V3.3.1 — Impression directe via QPrinter

- Impression directe sans passer par un lecteur PDF externe
- Dialogue d'impression natif Windows (QPrintDialog)
- Choix imprimante, copies, pages, orientation
- Rendu haute resolution (DPI de l'imprimante)
- Centrage automatique sur la page
- Fonctionne sans Adobe/Edge/lecteur PDF installe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jules
2026-03-21 16:43:32 +01:00
parent 2fcc92dbd9
commit 5e368ef260
3 changed files with 68 additions and 22 deletions

View File

@@ -7,8 +7,8 @@ import shutil
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QFileDialog, QMessageBox, QStatusBar, QLabel, QFileDialog, QMessageBox, QStatusBar,
QSplitter, QProgressBar, QApplication, QToolBar) QSplitter, QProgressBar, QApplication, QToolBar)
from PyQt6.QtCore import Qt, QTimer from PyQt6.QtCore import Qt, QTimer, QRect
from PyQt6.QtGui import QAction, QIcon, QDragEnterEvent, QDropEvent from PyQt6.QtGui import QAction, QIcon, QDragEnterEvent, QDropEvent, QPageLayout
from app.pdf_viewer import PdfViewer from app.pdf_viewer import PdfViewer
from app.page_panel import PagePanel from app.page_panel import PagePanel
@@ -1012,26 +1012,72 @@ class MainWindow(QMainWindow):
if not self._require_file(): if not self._require_file():
return return
try: try:
from PyQt6.QtPrintSupport import QPrinter, QPrintDialog
from PyQt6.QtGui import QPainter, QImage
import pypdfium2 as pdfium
source = self._result_file or self._current_file source = self._result_file or self._current_file
tmp_print = os.path.join(tempfile.gettempdir(), "copydev_print.pdf") pdf = pdfium.PdfDocument(source)
shutil.copy2(source, tmp_print)
if sys.platform == "win32": printer = QPrinter(QPrinter.PrinterMode.HighResolution)
# "print" envoie directement au dialogue d'impression printer.setPageOrientation(
os.startfile(tmp_print, "print") QPageLayout.Orientation.Landscape
else: if pdf[0].get_size()[0] > pdf[0].get_size()[1]
import subprocess else QPageLayout.Orientation.Portrait
subprocess.Popen(["lp", tmp_print]) )
self._status_label.setText("Impression lancee...")
except OSError: dialog = QPrintDialog(printer, self)
# Fallback : ouvrir le fichier normalement dialog.setWindowTitle("Imprimer — CopyDev Imposing Tool")
try: if dialog.exec() != QPrintDialog.DialogCode.Accepted:
if sys.platform == "win32": return
os.startfile(tmp_print)
self._status_label.setText("Fichier ouvert — utilisez Ctrl+P pour imprimer") self._show_progress()
except Exception as e2: self._status_label.setText("Impression en cours...")
QMessageBox.critical(self, "Erreur", f"Impossible d'imprimer :\n{e2}") QApplication.processEvents()
painter = QPainter()
painter.begin(printer)
for i in range(len(pdf)):
if i > 0:
printer.newPage()
page = pdf[i]
# Rendu a haute resolution
dpi = printer.resolution()
scale = dpi / 72
bitmap = page.render(scale=scale)
pil_image = bitmap.to_pil()
data = pil_image.tobytes("raw", "RGBA")
qimage = QImage(data, pil_image.width, pil_image.height, QImage.Format.Format_RGBA8888)
# Calculer le placement sur la page imprimee
page_rect = printer.pageRect(QPrinter.Unit.Point)
pw, ph = page.get_size()
scale_x = page_rect.width() / pil_image.width
scale_y = page_rect.height() / pil_image.height
s = min(scale_x, scale_y)
target_w = int(pil_image.width * s)
target_h = int(pil_image.height * s)
x = int((page_rect.width() - target_w) / 2)
y = int((page_rect.height() - target_h) / 2)
from PyQt6.QtCore import QRect
painter.drawImage(QRect(x, y, target_w, target_h), qimage)
painter.end()
self._hide_progress()
self._status_label.setText(f"Impression terminee — {len(pdf)} page(s)")
except ImportError:
QMessageBox.critical(self, "Erreur",
"Le module d'impression n'est pas disponible.\n"
"Installez PyQt6 avec le support impression.")
except Exception as e: except Exception as e:
QMessageBox.critical(self, "Erreur", f"Impossible d'imprimer :\n{e}") self._hide_progress()
QMessageBox.critical(self, "Erreur", f"Erreur d'impression :\n{e}")
def _do_crop_marks(self): def _do_crop_marks(self):
if not self._require_file(): if not self._require_file():

View File

@@ -14,7 +14,7 @@ REPO = "jules/copydev-imposing-tool"
BRANCH = "master" BRANCH = "master"
# Version actuelle (incrementee a chaque release) # Version actuelle (incrementee a chaque release)
VERSION = "3.3.0" VERSION = "3.3.1"
def get_remote_version(): def get_remote_version():

View File

@@ -1 +1 @@
3.3.0 3.3.1