Init projet Photostation - borne impression photo tactile PyQt6

Structure : 4 écrans (accueil, import, éditeur, impression),
navigation QStackedWidget, base éditeur QGraphicsScene.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 18:47:56 +01:00
parent a5b02cb56a
commit 6598e4073f
12 changed files with 539 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
"""Écran éditeur — recadrage, goodies, effets, multi-pose."""
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
QLabel, QGraphicsScene, QGraphicsView, QGraphicsPixmapItem,
QToolBar
)
from PyQt6.QtCore import Qt, QRectF
from PyQt6.QtGui import QFont, QPixmap, QImage, QPainter
class EditorScreen(QWidget):
def __init__(self, main_window):
super().__init__()
self.main_window = main_window
self.current_image_path = None
self.pixmap_item = None
self._setup_ui()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(10)
# Header
header = QHBoxLayout()
back_btn = QPushButton("Retour")
back_btn.setFont(QFont("", 14))
back_btn.clicked.connect(self.main_window.show_import)
header.addWidget(back_btn)
title = QLabel("Éditeur")
title.setFont(QFont("", 24, QFont.Weight.Bold))
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
header.addWidget(title, 1)
print_btn = QPushButton("Imprimer")
print_btn.setFont(QFont("", 14))
print_btn.setStyleSheet("""
QPushButton {
background-color: #4CAF50;
color: white;
border-radius: 10px;
padding: 10px 20px;
}
QPushButton:pressed { background-color: #388E3C; }
""")
print_btn.clicked.connect(self._go_print)
header.addWidget(print_btn)
layout.addLayout(header)
# Zone d'édition (QGraphicsScene)
self.scene = QGraphicsScene()
self.view = QGraphicsView(self.scene)
self.view.setRenderHint(QPainter.RenderHint.Antialiasing)
self.view.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
self.view.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
self.view.setStyleSheet("background-color: #333;")
layout.addWidget(self.view, 1)
# Barre d'outils
tools = QHBoxLayout()
tools.setSpacing(10)
tool_buttons = [
("Recadrer", self._crop),
("Rotation", self._rotate),
("N&B", self._filter_grayscale),
("Sépia", self._filter_sepia),
("Goodies", self._add_goodies),
("Multi-pose", self._multipose),
("Texte", self._add_text),
]
for label, callback in tool_buttons:
btn = QPushButton(label)
btn.setFont(QFont("", 13))
btn.setMinimumHeight(50)
btn.setStyleSheet("""
QPushButton {
background-color: #555;
color: white;
border-radius: 8px;
padding: 8px 15px;
}
QPushButton:pressed { background-color: #777; }
""")
btn.clicked.connect(callback)
tools.addWidget(btn)
layout.addLayout(tools)
def load_image(self, path):
self.current_image_path = path
self.scene.clear()
pixmap = QPixmap(path)
self.pixmap_item = self.scene.addPixmap(pixmap)
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
def _go_print(self):
# TODO: exporter le canvas édité en image
self.main_window.show_print(self.current_image_path)
def _crop(self):
# TODO: outil de recadrage interactif
pass
def _rotate(self):
if self.pixmap_item:
self.pixmap_item.setRotation(self.pixmap_item.rotation() + 90)
def _filter_grayscale(self):
if not self.current_image_path:
return
pixmap = QPixmap(self.current_image_path)
image = pixmap.toImage().convertToFormat(QImage.Format.Format_Grayscale8)
self.scene.clear()
self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(image))
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
def _filter_sepia(self):
if not self.current_image_path:
return
from PIL import Image, ImageOps
img = Image.open(self.current_image_path)
sepia = ImageOps.grayscale(img)
sepia = ImageOps.colorize(sepia, "#704214", "#C0A080")
# Convertir PIL -> QPixmap
data = sepia.convert("RGBA").tobytes("raw", "RGBA")
qimg = QImage(data, sepia.width, sepia.height, QImage.Format.Format_RGBA8888)
self.scene.clear()
self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(qimg))
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
def _add_goodies(self):
# TODO: panneau de sélection de stickers
pass
def _multipose(self):
# TODO: sélection de templates multi-photos
pass
def _add_text(self):
# TODO: ajout de texte éditable sur le canvas
pass