moved stuff + scanner com/hid edits
This commit is contained in:
164
extensions/python/KeyGenerator/createPDF.py
Normal file
164
extensions/python/KeyGenerator/createPDF.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import barcode
|
||||
import urllib3
|
||||
import re
|
||||
from barcode.writer import ImageWriter
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from io import BytesIO
|
||||
|
||||
# --- SETTINGS ---
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
JSON_FILE = os.path.join(os.getcwd(), 'curated_list.json')
|
||||
CARD_DIR = os.path.join(os.getcwd(), 'keychain_cards')
|
||||
IMG_CACHE_DIR = os.path.join(os.getcwd(), 'image_cache')
|
||||
OUTPUT_PDF = os.path.join(os.getcwd(), 'keychain_3x3_perfect.pdf')
|
||||
|
||||
# A4 at 300 DPI
|
||||
PAGE_W, PAGE_H = 2480, 3508
|
||||
COLS, ROWS = 3, 3
|
||||
PAGE_MARGIN = 150
|
||||
|
||||
# Ensure directories exist
|
||||
for d in [CARD_DIR, IMG_CACHE_DIR]:
|
||||
os.makedirs(d, exist_ok=True)
|
||||
|
||||
def clean_filename(name):
|
||||
return re.sub(r'[\\/*?:"<>|]', "_", name)
|
||||
|
||||
def get_ean_from_plu(plu):
|
||||
return f"000000{str(plu).zfill(4)}00"
|
||||
|
||||
def get_cached_image(url, plu):
|
||||
cache_path = os.path.join(IMG_CACHE_DIR, f"{plu}.jpg")
|
||||
|
||||
# Si el archivo ya existe en el cache, lo usamos sin importar la URL
|
||||
if os.path.exists(cache_path):
|
||||
return cache_path
|
||||
|
||||
# Si no existe y la URL es un placeholder, no podemos descargar nada
|
||||
if url == "URL_PLACEHOLDER":
|
||||
print(f"⚠️ {plu} tiene placeholder y no se encontró en {IMG_CACHE_DIR}")
|
||||
return None
|
||||
|
||||
# Lógica de descarga original para URLs reales
|
||||
try:
|
||||
headers = {'User-Agent': 'Mozilla/5.0'}
|
||||
res = requests.get(url, headers=headers, timeout=10, verify=False)
|
||||
if res.status_code == 200:
|
||||
with open(cache_path, 'wb') as f:
|
||||
f.write(res.content)
|
||||
return cache_path
|
||||
except Exception as e:
|
||||
print(f"❌ Error descargando {plu}: {e}")
|
||||
return None
|
||||
|
||||
def generate_card(item):
|
||||
name = item['name']
|
||||
plu = item['plu']
|
||||
img_url = item['image']
|
||||
|
||||
safe_name = clean_filename(name).replace(' ', '_')
|
||||
final_path = os.path.join(CARD_DIR, f"PLU_{plu}_{safe_name}.png")
|
||||
|
||||
if os.path.exists(final_path):
|
||||
return final_path
|
||||
|
||||
local_img_path = get_cached_image(img_url, plu)
|
||||
card = Image.new('RGB', (300, 450), color='white')
|
||||
draw = ImageDraw.Draw(card)
|
||||
draw.rectangle([0, 0, 299, 449], outline="black", width=3)
|
||||
|
||||
if local_img_path:
|
||||
try:
|
||||
img = Image.open(local_img_path).convert("RGB")
|
||||
w, h = img.size
|
||||
size = min(w, h)
|
||||
img = img.crop(((w-size)//2, (h-size)//2, (w+size)//2, (h+size)//2))
|
||||
img = img.resize((200, 200), Image.Resampling.LANCZOS)
|
||||
card.paste(img, (50, 40))
|
||||
except:
|
||||
draw.text((150, 140), "[IMG ERROR]", anchor="mm", fill="red")
|
||||
else:
|
||||
draw.text((150, 140), "[NOT FOUND]", anchor="mm", fill="red")
|
||||
|
||||
try:
|
||||
f_name = ImageFont.truetype("arialbd.ttf", 22)
|
||||
f_plu = ImageFont.truetype("arial.ttf", 18)
|
||||
except:
|
||||
f_name = f_plu = ImageFont.load_default()
|
||||
|
||||
draw.text((150, 260), name.upper(), fill="black", font=f_name, anchor="mm")
|
||||
draw.text((150, 295), f"PLU: {plu}", fill="#333333", font=f_plu, anchor="mm")
|
||||
|
||||
EAN = barcode.get_barcode_class('ean13')
|
||||
ean = EAN(get_ean_from_plu(plu), writer=ImageWriter())
|
||||
tmp = f"tmp_{plu}"
|
||||
ean.save(tmp, options={'module_height': 12.0, 'font_size': 10, 'text_distance': 4})
|
||||
|
||||
if os.path.exists(f"{tmp}.png"):
|
||||
b_img = Image.open(f"{tmp}.png")
|
||||
b_img = b_img.resize((280, 120))
|
||||
card.paste(b_img, (10, 320))
|
||||
os.remove(f"{tmp}.png")
|
||||
|
||||
card.save(final_path)
|
||||
print(f" - Card created: {name} ({plu})")
|
||||
return final_path
|
||||
|
||||
def create_pdf():
|
||||
all_files = sorted([f for f in os.listdir(CARD_DIR) if f.endswith('.png')])
|
||||
if not all_files:
|
||||
print("❌ No cards found to put in PDF.")
|
||||
return
|
||||
|
||||
available_w = PAGE_W - (PAGE_MARGIN * 2)
|
||||
available_h = PAGE_H - (PAGE_MARGIN * 2)
|
||||
slot_w, slot_h = available_w // COLS, available_h // ROWS
|
||||
|
||||
target_w = int(slot_w * 0.9)
|
||||
target_h = int(target_w * (450 / 300))
|
||||
|
||||
if target_h > (slot_h * 0.9):
|
||||
target_h = int(slot_h * 0.9)
|
||||
target_w = int(target_h * (300 / 450))
|
||||
|
||||
pages = []
|
||||
current_page = Image.new('RGB', (PAGE_W, PAGE_H), 'white')
|
||||
|
||||
print(f"📄 Organizing {len(all_files)} cards into {COLS}x{ROWS} grid...")
|
||||
|
||||
for i, filename in enumerate(all_files):
|
||||
item_idx = i % (COLS * ROWS)
|
||||
if item_idx == 0 and i > 0:
|
||||
pages.append(current_page)
|
||||
current_page = Image.new('RGB', (PAGE_W, PAGE_H), 'white')
|
||||
|
||||
row, col = item_idx // COLS, item_idx % COLS
|
||||
img_path = os.path.join(CARD_DIR, filename)
|
||||
card_img = Image.open(img_path).convert('RGB')
|
||||
card_img = card_img.resize((target_w, target_h), Image.Resampling.LANCZOS)
|
||||
|
||||
x = PAGE_MARGIN + (col * slot_w) + (slot_w - target_w) // 2
|
||||
y = PAGE_MARGIN + (row * slot_h) + (slot_h - target_h) // 2
|
||||
current_page.paste(card_img, (x, y))
|
||||
|
||||
pages.append(current_page)
|
||||
pages[0].save(OUTPUT_PDF, save_all=True, append_images=pages[1:], resolution=300.0, quality=100)
|
||||
print(f"✅ Created {OUTPUT_PDF}. Now go print it and stop crying.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.path.exists(JSON_FILE):
|
||||
print(f"❌ Missing {JSON_FILE}")
|
||||
else:
|
||||
with open(JSON_FILE, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
print(f"Step 1: Processing {len(data)} cards...")
|
||||
for entry in data:
|
||||
generate_card(entry)
|
||||
|
||||
print("\nStep 2: Generating PDF...")
|
||||
create_pdf()
|
||||
Reference in New Issue
Block a user