Gestion evenements + cadres par event + fix cadre paysage + dossier non-imprimees

- CRUD evenements : creer, activer, editer, supprimer dans panneau admin
- Cadres specifiques par evenement (aucun/disponible/defaut/impose)
- Fix cadre paysage deformé : rotation auto si orientation ne correspond pas
- Photos non imprimees vont dans sous-dossier "non_imprimees" (USB/FTP)
  au lieu d'etre ignorees ; booth recoit toujours toutes les photos

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 00:16:35 +02:00
parent 545d8cd6ad
commit 9ce8fc0e55
9 changed files with 621 additions and 60 deletions

View File

@@ -121,13 +121,24 @@ def chroma_key(chemin_photo: Path, nom_fond: str | None = None,
return chemin_export
def appliquer_cadre_impression(img: Image.Image, format_papier: str, nom_cadre: str) -> Image.Image:
def appliquer_cadre_impression(img: Image.Image, format_papier: str, nom_cadre: str, event_id: str | None = None) -> Image.Image:
"""Composite un cadre PNG par-dessus l'image assemblée."""
chemin = DOSSIER_CADRES / format_papier / nom_cadre
chemin = None
if event_id:
from backend.evenements import DOSSIER_EVENEMENTS
chemin_event = DOSSIER_EVENEMENTS / event_id / "cadres" / format_papier / nom_cadre
if chemin_event.exists():
chemin = chemin_event
if chemin is None:
chemin = DOSSIER_CADRES / format_papier / nom_cadre
if not chemin.exists():
log.warning(f"Cadre introuvable : {chemin}")
return img
cadre = Image.open(chemin).convert("RGBA")
img_portrait = img.height > img.width
cadre_portrait = cadre.height > cadre.width
if img_portrait != cadre_portrait:
cadre = cadre.rotate(90, expand=True)
if cadre.size != img.size:
cadre = cadre.resize(img.size, Image.LANCZOS)
base = img.convert("RGBA")