Files

165 lines
5.4 KiB
Python

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()