tajetitas
This commit is contained in:
51
KeyGenerator/excel_parser.py
Normal file
51
KeyGenerator/excel_parser.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import pandas as pd
|
||||
import json
|
||||
import os
|
||||
|
||||
file_path = r'C:\Users\Pepitho\Desktop\SekiPOS\KeyGenerator\wea.xlsx'
|
||||
sheet_name = 'Non FTL'
|
||||
new_url_base = "https://server-ifps.accurateig.com/assets/commodities/"
|
||||
|
||||
def get_one_of_each():
|
||||
if not os.path.exists(file_path):
|
||||
print("❌ Excel file not found.")
|
||||
return
|
||||
|
||||
# 1. Load Excel
|
||||
df = pd.read_excel(file_path, sheet_name=sheet_name)
|
||||
|
||||
# 2. Drop rows missing the essentials
|
||||
df = df.dropna(subset=['IMAGE', 'PLU', 'COMMODITY'])
|
||||
|
||||
# 3. CRITICAL: Drop duplicates by COMMODITY only
|
||||
# This ignores Variety and Size, giving us exactly one row per fruit type.
|
||||
df_unique = df.drop_duplicates(subset=['COMMODITY'], keep='first')
|
||||
|
||||
data_output = []
|
||||
|
||||
for _, row in df_unique.iterrows():
|
||||
# Extract filename from the messy URL in Excel
|
||||
original_link = str(row['IMAGE'])
|
||||
filename = original_link.split('/')[-1]
|
||||
|
||||
# Build the final working URL
|
||||
image_url = f"{new_url_base}{filename}"
|
||||
|
||||
# Get the clean Commodity name
|
||||
commodity = str(row['COMMODITY']).title()
|
||||
plu_code = str(row['PLU'])
|
||||
|
||||
data_output.append({
|
||||
"name": commodity,
|
||||
"plu": plu_code,
|
||||
"image": image_url
|
||||
})
|
||||
|
||||
# 4. Save to JSON
|
||||
with open('one_of_each.json', 'w', encoding='utf-8') as f:
|
||||
json.dump(data_output, f, indent=4, ensure_ascii=False)
|
||||
|
||||
print(f"✅ Success! Generated 'one_of_each.json' with {len(data_output)} unique commodities.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
get_one_of_each()
|
||||
@@ -1,76 +1,116 @@
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import barcode
|
||||
import urllib3
|
||||
import re
|
||||
from barcode.writer import ImageWriter
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import os
|
||||
import random
|
||||
from io import BytesIO
|
||||
|
||||
# Items to generate
|
||||
ITEMS = [
|
||||
{"name": "Plátano", "icon": "🍌"},
|
||||
{"name": "Manzana", "icon": "🍎"},
|
||||
{"name": "Tomate", "icon": "🍅"},
|
||||
{"name": "Lechuga", "icon": "🥬"},
|
||||
{"name": "Cebolla", "icon": "🧅"},
|
||||
{"name": "Pan Batido", "icon": "🥖"}
|
||||
]
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
os.makedirs('keychain_cards', exist_ok=True)
|
||||
# --- CONFIGURATION ---
|
||||
JSON_FILE = 'frutas.json'
|
||||
OUTPUT_DIR = 'keychain_cards'
|
||||
IMG_CACHE_DIR = 'image_cache'
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(IMG_CACHE_DIR, exist_ok=True)
|
||||
|
||||
def clean_filename(name):
|
||||
"""Prevents Windows path errors by stripping illegal characters."""
|
||||
return re.sub(r'[\\/*?:"<>|]', "_", name)
|
||||
|
||||
def get_ean_from_plu(plu):
|
||||
"""Standard 4-digit PLU to EAN-13 padding."""
|
||||
return f"000000{str(plu).zfill(4)}00"
|
||||
|
||||
def get_cached_image(url, plu):
|
||||
"""Checks local cache before downloading."""
|
||||
cache_path = os.path.join(IMG_CACHE_DIR, f"{plu}.jpg")
|
||||
if os.path.exists(cache_path):
|
||||
return cache_path
|
||||
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 downloading {plu}: {e}")
|
||||
return None
|
||||
|
||||
def generate_card(item):
|
||||
name = item['name']
|
||||
# Generate a private EAN-13 starting with 99
|
||||
# We need 12 digits (the 13th is a checksum added by the library)
|
||||
random_digits = ''.join([str(random.randint(0, 9)) for _ in range(10)])
|
||||
code_str = f"99{random_digits}"
|
||||
plu = item['plu']
|
||||
img_url = item['image']
|
||||
|
||||
# Generate Barcode Image
|
||||
EAN = barcode.get_barcode_class('ean13')
|
||||
ean = EAN(code_str, writer=ImageWriter())
|
||||
# Use original English name for filename and display
|
||||
safe_name = clean_filename(name).replace(' ', '_')
|
||||
final_path = os.path.join(OUTPUT_DIR, f"PLU_{plu}_{safe_name}.png")
|
||||
|
||||
# Customizing the output image size
|
||||
options = {
|
||||
'module_height': 15.0,
|
||||
'font_size': 10,
|
||||
'text_distance': 3.0,
|
||||
'write_text': True
|
||||
}
|
||||
# 1. Skip if already done
|
||||
if os.path.exists(final_path):
|
||||
return
|
||||
|
||||
# 2. Local Image Fetch
|
||||
local_img_path = get_cached_image(img_url, plu)
|
||||
|
||||
# Create the card canvas (300x450 pixels ~ 2.5x3.5 inches)
|
||||
card = Image.new('RGB', (300, 400), color='white')
|
||||
# 3. Canvas Setup
|
||||
card = Image.new('RGB', (300, 450), color='white')
|
||||
draw = ImageDraw.Draw(card)
|
||||
|
||||
# Draw a border for cutting
|
||||
draw.rectangle([0, 0, 299, 399], outline="black", width=2)
|
||||
|
||||
# Try to add the Emoji/Text (Requires a font that supports emojis, otherwise just text)
|
||||
# Thicker frame as requested (width=3)
|
||||
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")
|
||||
|
||||
# 4. Text
|
||||
try:
|
||||
# If on Linux, try to find a ttf
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40)
|
||||
title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 25)
|
||||
# Standard Windows font path
|
||||
f_name = ImageFont.truetype("arialbd.ttf", 22)
|
||||
f_plu = ImageFont.truetype("arial.ttf", 18)
|
||||
except:
|
||||
font = ImageFont.load_default()
|
||||
title_font = ImageFont.load_default()
|
||||
f_name = f_plu = ImageFont.load_default()
|
||||
|
||||
# Draw Name and Emoji
|
||||
draw.text((150, 60), item['icon'], fill="black", font=font, anchor="mm")
|
||||
draw.text((150, 120), name, fill="black", font=title_font, anchor="mm")
|
||||
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")
|
||||
|
||||
# 5. Barcode
|
||||
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})
|
||||
|
||||
# Save barcode to temp file
|
||||
barcode_img_path = f"keychain_cards/{code_str}_tmp"
|
||||
ean.save(barcode_img_path, options=options)
|
||||
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")
|
||||
|
||||
# Paste barcode onto card
|
||||
b_img = Image.open(f"{barcode_img_path}.png")
|
||||
b_img = b_img.resize((260, 180)) # Resize to fit card
|
||||
card.paste(b_img, (20, 180))
|
||||
|
||||
# Cleanup and save final
|
||||
os.remove(f"{barcode_img_path}.png")
|
||||
final_path = f"keychain_cards/{name.replace(' ', '_')}.png"
|
||||
card.save(final_path)
|
||||
print(f"Generated {name}: {ean.get_fullcode()}")
|
||||
print(f"✅ Card created: {name} ({plu})")
|
||||
|
||||
for item in ITEMS:
|
||||
generate_card(item)
|
||||
|
||||
print("\nAll cards generated in 'keychain_cards/' folder.")
|
||||
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"Processing {len(data)} cards...")
|
||||
for entry in data:
|
||||
generate_card(entry)
|
||||
print("\nAll done. Try not to lose your keys.")
|
||||
BIN
KeyGenerator/wea.xlsx
Normal file
BIN
KeyGenerator/wea.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user