#!/usr/bin/env python3 """Génère des cadres de démonstration pour chaque format d'impression.""" from pathlib import Path from PIL import Image, ImageDraw RACINE = Path(__file__).resolve().parent.parent DOSSIER_CADRES = RACINE / "frontend" / "assets" / "cadres" FORMATS = { "strip": (600, 1800), "10x15": (1200, 1800), "15x20": (1800, 2400), } # ─── Cadres simples (tous formats) ─────────────────────────────────────────── def cadre_simple(largeur, hauteur, couleur_bord, epaisseur=30, couleur_coin=None): img = Image.new("RGBA", (largeur, hauteur), (0, 0, 0, 0)) d = ImageDraw.Draw(img) cc = couleur_coin or couleur_bord ep = epaisseur # 4 bords d.rectangle([0, 0, largeur, ep], fill=couleur_bord) d.rectangle([0, hauteur - ep, largeur, hauteur], fill=couleur_bord) d.rectangle([0, 0, ep, hauteur], fill=couleur_bord) d.rectangle([largeur - ep, 0, largeur, hauteur], fill=couleur_bord) # coins tc = ep + 20 for x, y in [(0, 0), (largeur - tc, 0), (0, hauteur - tc), (largeur - tc, hauteur - tc)]: d.rectangle([x, y, x + tc, y + tc], fill=cc) # ligne intérieure fine m = ep + 8 d.rectangle([m, m, largeur - m, hauteur - m], outline=cc, width=2) return img # ─── Cadres pellicule (format strip uniquement) ─────────────────────────────── def cadre_pellicule(largeur, hauteur, couleur_bord=(15, 15, 15, 255), couleur_perf=(50, 50, 50, 255), label=""): """Cadre pellicule avec perforations sur les côtés gauche et droit.""" img = Image.new("RGBA", (largeur, hauteur), (0, 0, 0, 0)) d = ImageDraw.Draw(img) bord = 52 # largeur de la bande pellicule de chaque côté perf_h = 22 # hauteur d'une perforation perf_w = 16 # largeur d'une perforation perf_r = 4 # rayon arrondi perf_gap = 14 # espace entre perforations # Bandes noires gauche et droite d.rectangle([0, 0, bord, hauteur], fill=couleur_bord) d.rectangle([largeur - bord, 0, largeur, hauteur], fill=couleur_bord) # Bande fine haut et bas bord_h = 10 d.rectangle([0, 0, largeur, bord_h], fill=couleur_bord) d.rectangle([0, hauteur - bord_h, largeur, hauteur], fill=couleur_bord) # Perforations gauche y = perf_gap while y + perf_h < hauteur: x = (bord - perf_w) // 2 d.rounded_rectangle([x, y, x + perf_w, y + perf_h], radius=perf_r, fill=couleur_perf) y += perf_h + perf_gap # Perforations droite y = perf_gap while y + perf_h < hauteur: x = largeur - bord + (bord - perf_w) // 2 d.rounded_rectangle([x, y, x + perf_w, y + perf_h], radius=perf_r, fill=couleur_perf) y += perf_h + perf_gap # Ligne intérieure fine pour délimiter la zone photo m = bord + 4 d.rectangle([m, bord_h + 4, largeur - m, hauteur - bord_h - 4], outline=(80, 80, 80, 180), width=1) return img def cadre_pellicule_vintage(largeur, hauteur): """Pellicule couleur sépia avec numéros de frame.""" img = Image.new("RGBA", (largeur, hauteur), (0, 0, 0, 0)) d = ImageDraw.Draw(img) bord = 58 bord_sepia = (40, 28, 12, 255) perf_col = (90, 65, 30, 255) perf_h, perf_w, perf_r, perf_gap = 20, 14, 3, 16 d.rectangle([0, 0, bord, hauteur], fill=bord_sepia) d.rectangle([largeur - bord, 0, largeur, hauteur], fill=bord_sepia) d.rectangle([0, 0, largeur, 8], fill=bord_sepia) d.rectangle([0, hauteur - 8, largeur, hauteur], fill=bord_sepia) for side in [0, 1]: y = perf_gap while y + perf_h < hauteur: x = (bord - perf_w) // 2 if side == 0 else largeur - bord + (bord - perf_w) // 2 d.rounded_rectangle([x, y, x + perf_w, y + perf_h], radius=perf_r, fill=perf_col) y += perf_h + perf_gap # Filet intérieur m = bord + 5 d.rectangle([m, 12, largeur - m, hauteur - 12], outline=(100, 75, 35, 200), width=2) return img def cadre_pellicule_couleur(largeur, hauteur, teinte=(220, 50, 50)): """Pellicule colorée style photobooth rétro.""" img = Image.new("RGBA", (largeur, hauteur), (0, 0, 0, 0)) d = ImageDraw.Draw(img) bord = 50 r, g, b = teinte col_bord = (r, g, b, 255) col_perf = (min(255, r + 60), min(255, g + 60), min(255, b + 60), 255) perf_h, perf_w, perf_r, perf_gap = 20, 14, 4, 14 d.rectangle([0, 0, bord, hauteur], fill=col_bord) d.rectangle([largeur - bord, 0, largeur, hauteur], fill=col_bord) d.rectangle([0, 0, largeur, 8], fill=col_bord) d.rectangle([0, hauteur - 8, largeur, hauteur], fill=col_bord) for side in [0, 1]: y = perf_gap while y + perf_h < hauteur: x = (bord - perf_w) // 2 if side == 0 else largeur - bord + (bord - perf_w) // 2 d.rounded_rectangle([x, y, x + perf_w, y + perf_h], radius=perf_r, fill=col_perf) y += perf_h + perf_gap m = bord + 5 d.rectangle([m, 12, largeur - m, hauteur - 12], outline=col_perf, width=2) return img # ─── Main ───────────────────────────────────────────────────────────────────── def main(): # Cadres simples pour tous les formats SIMPLES = [ ("classique_blanc.png", (255, 255, 255, 255), (210, 210, 210, 255), 30), ("elegant_noir.png", (20, 20, 20, 255), (70, 70, 70, 255), 40), ("rose_gold.png", (198, 143, 115, 255), (230, 180, 150, 255), 35), ("festif_dore.png", (212, 175, 55, 255), (255, 215, 0, 255), 32), ] for fmt, (larg, haut) in FORMATS.items(): dossier = DOSSIER_CADRES / fmt dossier.mkdir(parents=True, exist_ok=True) for nom, col_bord, col_coin, ep in SIMPLES: cadre = cadre_simple(larg, haut, col_bord, ep, col_coin) cadre.save(dossier / nom, "PNG") print(f" ✓ {fmt}/{nom}") # Cadres pellicule — uniquement format strip dossier_strip = DOSSIER_CADRES / "strip" larg, haut = FORMATS["strip"] pellicules = [ ("pellicule_noir.png", cadre_pellicule(larg, haut)), ("pellicule_vintage.png", cadre_pellicule_vintage(larg, haut)), ("pellicule_rouge.png", cadre_pellicule_couleur(larg, haut, (200, 40, 40))), ("pellicule_bleu.png", cadre_pellicule_couleur(larg, haut, (30, 80, 180))), ("pellicule_vert.png", cadre_pellicule_couleur(larg, haut, (30, 140, 60))), ] for nom, img in pellicules: img.save(dossier_strip / nom, "PNG") print(f" ✓ strip/{nom} (pellicule)") if __name__ == "__main__": print("Génération des cadres de démonstration...") main() print("Terminé.")