Fix impression pellicule : strip genere en paysage au lieu du portrait attendu

creer_strip() produisait une bande paysage (1800x595) alors que printer.py
('10x15-2up' -> PageSize ...-div2) et tous les cadres existants (assets/cadres/strip/*.png)
attendent une bande portrait fixe 600x1800 (5x15cm), dupliquee et coupee
automatiquement par l'imprimante. Le mismatch faisait pivoter/etirer
l'image a l'impression (StpiShrinkOutput=Crop sur un ratio incompatible),
d'ou le rendu deforme coupe en 2 mauvais morceaux au lieu de 2 pellicules
identiques.

- creer_strip() : bande 600x1800 portrait, photos empilees verticalement,
  perforations sur les cotes (au lieu de haut/bas)
- Cadre de visee live (camera.js) : formule de ratio mise a jour en
  consequence pour rester fidele au resultat final
This commit is contained in:
2026-06-21 23:00:48 +02:00
parent 0df68da41a
commit a79762197d
3 changed files with 33 additions and 30 deletions

View File

@@ -31,27 +31,31 @@ def _crop_center(img: Image.Image, ratio_cible: float) -> Image.Image:
def creer_strip(photos: list[Path], marge: int = 10, couleur_fond: str = "#000000", def creer_strip(photos: list[Path], marge: int = 10, couleur_fond: str = "#000000",
cadre: str | None = None) -> Path: cadre: str | None = None) -> Path:
"""Cree une bande portrait style pellicule (4 photos de gauche a droite). """Cree une bande portrait style pellicule (photos empilees de haut en bas).
Pellicule noire avec perforations, photos separees par des bandes noires. Pellicule noire avec perforations sur les cotes, photos separees par des
Plus large : utilise toute la hauteur d'un 10x15 paysage divise en 2. bandes noires. Taille fixe 600x1800px (5x15cm a 300dpi) : c'est le format
attendu par l'imprimante en mode "10x15-2up" (PageSize ...-div2), qui
duplique et decoupe automatiquement la bande en 2 exemplaires sur une
feuille 10x15. Doit rester strictement portrait (largeur < hauteur) et a
cette taille exacte pour eviter toute rotation/etirement a l'impression.
""" """
nb = len(photos) nb = len(photos)
images = [Image.open(p) for p in photos] images = [Image.open(p) for p in photos]
# Dimensions de la bande : largeur d'un 10x15 paysage, hauteur = moitie # Dimensions de la bande : format fixe attendu par printer.py (FORMATS["10x15-2up"])
bande_largeur = LARGEUR_10x15_L bande_largeur = 600
bande_hauteur = (HAUTEUR_10x15_L - marge) // 2 bande_hauteur = 1800
# Zone perforations pellicule (haut et bas) # Zone perforations pellicule (gauche et droite)
perf_hauteur = 34 perf_largeur = 34
zone_photos_hauteur = bande_hauteur - perf_hauteur * 2 zone_photos_largeur = bande_largeur - perf_largeur * 2
# Taille de chaque photo dans la bande (separees par bandes noires) # Taille de chaque photo dans la bande (separees par bandes noires)
sep = 12 # separateur noir entre photos sep = 12 # separateur noir entre photos
espace_photos = bande_largeur - marge * 2 - sep * (nb - 1) espace_photos = bande_hauteur - marge * 2 - sep * (nb - 1)
largeur_cellule = espace_photos // nb hauteur_cellule = espace_photos // nb
hauteur_cellule = zone_photos_hauteur largeur_cellule = zone_photos_largeur
ratio_cellule = largeur_cellule / hauteur_cellule ratio_cellule = largeur_cellule / hauteur_cellule
# Recadrer et redimensionner # Recadrer et redimensionner
@@ -66,24 +70,24 @@ def creer_strip(photos: list[Path], marge: int = 10, couleur_fond: str = "#00000
draw = ImageDraw.Draw(strip) draw = ImageDraw.Draw(strip)
# Bords pellicule noirs (deja le fond) # Bords pellicule noirs (deja le fond)
# Perforations pellicule (haut) - trous blancs dans le bord noir # Perforations pellicule (gauche) - trous blancs dans le bord noir
for px in range(marge + 10, bande_largeur - marge, 44): for py in range(marge + 10, bande_hauteur - marge, 44):
draw.rounded_rectangle( draw.rounded_rectangle(
[px, 8, px + 22, perf_hauteur - 8], [8, py, perf_largeur - 8, py + 22],
radius=5, fill=(60, 60, 60) radius=5, fill=(60, 60, 60)
) )
# Perforations pellicule (bas) # Perforations pellicule (droite)
for px in range(marge + 10, bande_largeur - marge, 44): for py in range(marge + 10, bande_hauteur - marge, 44):
draw.rounded_rectangle( draw.rounded_rectangle(
[px, bande_hauteur - perf_hauteur + 8, px + 22, bande_hauteur - 8], [bande_largeur - perf_largeur + 8, py, bande_largeur - 8, py + 22],
radius=5, fill=(60, 60, 60) radius=5, fill=(60, 60, 60)
) )
# Coller les photos (separees par des bandes noires verticales) # Coller les photos (separees par des bandes noires horizontales)
x = marge y = marge
for img in images_redim: for img in images_redim:
strip.paste(img, (x, perf_hauteur)) strip.paste(img, (perf_largeur, y))
x += largeur_cellule + sep y += hauteur_cellule + sep
if cadre: if cadre:
strip = appliquer_cadre_impression(strip, "strip", cadre) strip = appliquer_cadre_impression(strip, "strip", cadre)

View File

@@ -739,7 +739,7 @@
<script src="/js/websocket.js?v=3"></script> <script src="/js/websocket.js?v=3"></script>
<script src="/js/app.js?v=4"></script> <script src="/js/app.js?v=4"></script>
<script src="/js/camera.js?v=7"></script> <script src="/js/camera.js?v=8"></script>
<script src="/js/effects.js?v=3"></script> <script src="/js/effects.js?v=3"></script>
<script src="/js/gallery.js?v=3"></script> <script src="/js/gallery.js?v=3"></script>
<script src="/js/share.js?v=5"></script> <script src="/js/share.js?v=5"></script>

View File

@@ -87,13 +87,12 @@ function getRatioCelluleAttendu() {
const nb = getNombrePhotos(); const nb = getNombrePhotos();
const mode = config.multi_shot?.mode || 'strip'; const mode = config.multi_shot?.mode || 'strip';
if (mode === 'strip') { if (mode === 'strip') {
// Reproduit creer_strip() dans backend/collage.py // Reproduit creer_strip() dans backend/collage.py (bande portrait 600x1800, photos empilees)
const bandeLargeur = 1800, bandeHauteurTotale = 1200, marge = 10, sep = 12, perfHauteur = 34; const bandeLargeur = 600, bandeHauteur = 1800, marge = 10, sep = 12, perfLargeur = 34;
const bandeHauteur = Math.floor((bandeHauteurTotale - marge) / 2); const zonePhotosLargeur = bandeLargeur - perfLargeur * 2;
const zonePhotosHauteur = bandeHauteur - perfHauteur * 2; const espacePhotos = bandeHauteur - marge * 2 - sep * (nb - 1);
const espacePhotos = bandeLargeur - marge * 2 - sep * (nb - 1); const hauteurCellule = Math.floor(espacePhotos / nb);
const largeurCellule = Math.floor(espacePhotos / nb); return zonePhotosLargeur / hauteurCellule;
return largeurCellule / zonePhotosHauteur;
} else { } else {
// Reproduit creer_collage() dans backend/collage.py // Reproduit creer_collage() dans backend/collage.py
const colonnes = 2; const colonnes = 2;