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",
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.
Plus large : utilise toute la hauteur d'un 10x15 paysage divise en 2.
Pellicule noire avec perforations sur les cotes, photos separees par des
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)
images = [Image.open(p) for p in photos]
# Dimensions de la bande : largeur d'un 10x15 paysage, hauteur = moitie
bande_largeur = LARGEUR_10x15_L
bande_hauteur = (HAUTEUR_10x15_L - marge) // 2
# Dimensions de la bande : format fixe attendu par printer.py (FORMATS["10x15-2up"])
bande_largeur = 600
bande_hauteur = 1800
# Zone perforations pellicule (haut et bas)
perf_hauteur = 34
zone_photos_hauteur = bande_hauteur - perf_hauteur * 2
# Zone perforations pellicule (gauche et droite)
perf_largeur = 34
zone_photos_largeur = bande_largeur - perf_largeur * 2
# Taille de chaque photo dans la bande (separees par bandes noires)
sep = 12 # separateur noir entre photos
espace_photos = bande_largeur - marge * 2 - sep * (nb - 1)
largeur_cellule = espace_photos // nb
hauteur_cellule = zone_photos_hauteur
espace_photos = bande_hauteur - marge * 2 - sep * (nb - 1)
hauteur_cellule = espace_photos // nb
largeur_cellule = zone_photos_largeur
ratio_cellule = largeur_cellule / hauteur_cellule
# Recadrer et redimensionner
@@ -66,24 +70,24 @@ def creer_strip(photos: list[Path], marge: int = 10, couleur_fond: str = "#00000
draw = ImageDraw.Draw(strip)
# Bords pellicule noirs (deja le fond)
# Perforations pellicule (haut) - trous blancs dans le bord noir
for px in range(marge + 10, bande_largeur - marge, 44):
# Perforations pellicule (gauche) - trous blancs dans le bord noir
for py in range(marge + 10, bande_hauteur - marge, 44):
draw.rounded_rectangle(
[px, 8, px + 22, perf_hauteur - 8],
[8, py, perf_largeur - 8, py + 22],
radius=5, fill=(60, 60, 60)
)
# Perforations pellicule (bas)
for px in range(marge + 10, bande_largeur - marge, 44):
# Perforations pellicule (droite)
for py in range(marge + 10, bande_hauteur - marge, 44):
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)
)
# Coller les photos (separees par des bandes noires verticales)
x = marge
# Coller les photos (separees par des bandes noires horizontales)
y = marge
for img in images_redim:
strip.paste(img, (x, perf_hauteur))
x += largeur_cellule + sep
strip.paste(img, (perf_largeur, y))
y += hauteur_cellule + sep
if 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/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/gallery.js?v=3"></script>
<script src="/js/share.js?v=5"></script>

View File

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