Multi-pose : même photo dupliquée + crop to fill

- La photo en cours est dupliquée dans toutes les zones du template
- Crop to fill : l'image remplit chaque zone au maximum (pas de bords)
- Fonctionne avec l'image éditée (filtres, etc.) pas juste l'originale

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 22:19:07 +01:00
parent 528e6bdfad
commit cd8f2dfed3

View File

@@ -313,79 +313,73 @@ class EditorScreen(QWidget):
if not zones: if not zones:
return return
# Utilise la photo en cours (ou l'image éditée du canvas)
source_pixmap = None
if self.pixmap_item:
source_pixmap = self.pixmap_item.pixmap()
elif self.current_image_path:
source_pixmap = QPixmap(self.current_image_path)
if not source_pixmap or source_pixmap.isNull():
return
self.multipose_zones = zones self.multipose_zones = zones
self.multipose_images = {} self.multipose_source = source_pixmap
# Demander les photos pour chaque zone # Taille canvas = format d'impression (ex: 1800x1200 pour 15x10)
sr = self.scene.sceneRect() canvas_w = 1800
canvas_w, canvas_h = int(sr.width()) or 1800, int(sr.height()) or 1200 canvas_h = 1200
self._render_multipose(source_pixmap, zones, canvas_w, canvas_h)
def _crop_to_fill(self, pixmap, target_w, target_h):
"""Crop centré pour remplir exactement target_w x target_h."""
src_w = pixmap.width()
src_h = pixmap.height()
src_ratio = src_w / src_h
target_ratio = target_w / target_h
if src_ratio > target_ratio:
# Image trop large → crop horizontal
new_w = int(src_h * target_ratio)
x_offset = (src_w - new_w) // 2
cropped = pixmap.copy(x_offset, 0, new_w, src_h)
else:
# Image trop haute → crop vertical
new_h = int(src_w / target_ratio)
y_offset = (src_h - new_h) // 2
cropped = pixmap.copy(0, y_offset, src_w, new_h)
return cropped.scaled(target_w, target_h,
Qt.AspectRatioMode.IgnoreAspectRatio,
Qt.TransformationMode.SmoothTransformation)
def _render_multipose(self, source_pixmap, zones, canvas_w, canvas_h):
"""Dessine le multi-pose : même image dupliquée, crop to fill."""
self.scene.clear() self.scene.clear()
self.pixmap_item = None self.pixmap_item = None
# Canvas blanc
white = QImage(canvas_w, canvas_h, QImage.Format.Format_ARGB32)
white.fill(QColor(255, 255, 255))
bg = self.scene.addPixmap(QPixmap.fromImage(white))
self.scene.setSceneRect(QRectF(0, 0, canvas_w, canvas_h))
# Dessiner les zones avec numéros
for i, (zx, zy, zw, zh) in enumerate(zones):
rx = int(zx * canvas_w)
ry = int(zy * canvas_h)
rw = int(zw * canvas_w)
rh = int(zh * canvas_h)
# Bordure de zone
from PyQt6.QtWidgets import QGraphicsRectItem
from PyQt6.QtGui import QPen, QBrush
rect = self.scene.addRect(rx + 2, ry + 2, rw - 4, rh - 4,
QPen(QColor(100, 100, 100), 2),
QBrush(QColor(240, 240, 240)))
# Numéro
text = self.scene.addText(str(i + 1), QFont("", 40))
text.setDefaultTextColor(QColor(150, 150, 150))
text.setPos(rx + rw / 2 - 20, ry + rh / 2 - 30)
self.view.fitInView(self.scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio)
# Charger les photos depuis la galerie d'import
import_photos = self.main_window.import_screen.photos
if import_photos:
self._fill_multipose_from_list(import_photos, zones, canvas_w, canvas_h)
def _fill_multipose_from_list(self, photos, zones, canvas_w, canvas_h):
"""Remplit les zones multi-pose avec les premières photos disponibles."""
self.scene.clear()
# Canvas blanc # Canvas blanc
white = QImage(canvas_w, canvas_h, QImage.Format.Format_ARGB32) white = QImage(canvas_w, canvas_h, QImage.Format.Format_ARGB32)
white.fill(QColor(255, 255, 255)) white.fill(QColor(255, 255, 255))
self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(white)) self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(white))
self.scene.setSceneRect(QRectF(0, 0, canvas_w, canvas_h)) self.scene.setSceneRect(QRectF(0, 0, canvas_w, canvas_h))
gap = 4 # espace entre les photos gap = 6 # espace entre les zones
for i, (zx, zy, zw, zh) in enumerate(zones): for i, (zx, zy, zw, zh) in enumerate(zones):
if i >= len(photos):
break
rx = int(zx * canvas_w) + gap rx = int(zx * canvas_w) + gap
ry = int(zy * canvas_h) + gap ry = int(zy * canvas_h) + gap
rw = int(zw * canvas_w) - gap * 2 rw = int(zw * canvas_w) - gap * 2
rh = int(zh * canvas_h) - gap * 2 rh = int(zh * canvas_h) - gap * 2
pixmap = QPixmap(photos[i]) if rw <= 0 or rh <= 0:
if pixmap.isNull():
continue continue
scaled = pixmap.scaled(rw, rh,
Qt.AspectRatioMode.KeepAspectRatio, # Crop to fill : l'image remplit toute la zone
Qt.TransformationMode.SmoothTransformation) filled = self._crop_to_fill(source_pixmap, rw, rh)
item = self.scene.addPixmap(scaled) item = self.scene.addPixmap(filled)
# Centrer dans la zone item.setPos(rx, ry)
offset_x = rx + (rw - scaled.width()) / 2
offset_y = ry + (rh - scaled.height()) / 2
item.setPos(offset_x, offset_y)
self.view.fitInView(self.scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio) self.view.fitInView(self.scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio)