V2.6.0 — Recadrage non-destructif + impression + licence dialog
- Recadrage non-destructif : - Garde le fichier original en memoire - Reouvrir Recadrer reaffiche la page entiere avec le cadre existant - Les marges sont pre-remplies avec le crop precedent - Annuler revient au fichier actuel - Impression : os.startfile(path, "print") ouvre le dialogue d'impression Windows directement (au lieu d'ouvrir le navigateur) - Dialogue de licence custom (logo, champ monospace, bouton cyan) - Messages erreur/succes en dialogues custom colores Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,8 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self._current_file = None
|
||||
self._result_file = None
|
||||
self._original_file = None # fichier avant crop (pour recadrage non-destructif)
|
||||
self._crop_settings = {} # {page_index: {top, bottom, left, right} en pt}
|
||||
|
||||
# Drag & drop
|
||||
self.setAcceptDrops(True)
|
||||
@@ -444,11 +446,12 @@ class MainWindow(QMainWindow):
|
||||
def _open_pdf(self, path):
|
||||
self._current_file = path
|
||||
self._result_file = None
|
||||
self._original_file = path # reset l'original
|
||||
self._crop_settings = {} # reset les crops
|
||||
self._viewer.load_pdf(path)
|
||||
self._page_panel.load_thumbnails(self._viewer)
|
||||
self._file_label.setText(os.path.basename(path))
|
||||
self._status_label.setText(f"Fichier charge : {os.path.basename(path)}")
|
||||
# Ajuster apres affichage
|
||||
QTimer.singleShot(100, self._viewer.zoom_fit)
|
||||
|
||||
def _save_result(self):
|
||||
@@ -701,15 +704,30 @@ class MainWindow(QMainWindow):
|
||||
if not self._require_file():
|
||||
return
|
||||
from pypdf import PdfReader
|
||||
from app.engine.pdf_utils import get_page_size
|
||||
reader = PdfReader(self._current_file)
|
||||
page = reader.pages[self._viewer.current_page]
|
||||
from app.engine.pdf_utils import get_page_size, pt_to_mm
|
||||
|
||||
# Toujours travailler depuis l'original pour permettre la re-edition
|
||||
source = self._original_file or self._current_file
|
||||
reader = PdfReader(source)
|
||||
cur_page = self._viewer.current_page
|
||||
page = reader.pages[cur_page]
|
||||
w, h = get_page_size(page)
|
||||
|
||||
# Recharger l'original dans le viewer pour voir la page entiere
|
||||
self._viewer.load_pdf(source)
|
||||
self._viewer.go_to_page(cur_page)
|
||||
self._page_panel.load_thumbnails(self._viewer)
|
||||
QApplication.processEvents()
|
||||
|
||||
# Si on a des settings de crop existants pour cette page, pre-remplir
|
||||
existing = self._crop_settings.get(cur_page, None)
|
||||
|
||||
self._crop_dlg = CropDialog(
|
||||
page_width_pt=w, page_height_pt=h,
|
||||
total_pages=len(reader.pages),
|
||||
current_page=self._viewer.current_page,
|
||||
current_page=cur_page,
|
||||
viewer=self._viewer,
|
||||
existing_crop=existing,
|
||||
parent=self
|
||||
)
|
||||
|
||||
@@ -724,30 +742,59 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
if not settings.get("pages"):
|
||||
return
|
||||
|
||||
# Sauvegarder les settings de crop par page
|
||||
for pg in settings["pages"]:
|
||||
self._crop_settings[pg] = {
|
||||
"crop_top": settings["crop_top"],
|
||||
"crop_bottom": settings["crop_bottom"],
|
||||
"crop_left": settings["crop_left"],
|
||||
"crop_right": settings["crop_right"],
|
||||
}
|
||||
|
||||
# Appliquer le crop depuis l'original
|
||||
self._show_progress()
|
||||
source_file = self._original_file or self._current_file
|
||||
output = self._make_temp()
|
||||
try:
|
||||
crop_pages(self._current_file, output, **settings)
|
||||
self._show_result(output)
|
||||
crop_pages(source_file, output, **settings)
|
||||
self._result_file = output
|
||||
self._current_file = output
|
||||
self._viewer.load_pdf(output)
|
||||
self._viewer.go_to_page(cur_page)
|
||||
self._page_panel.load_thumbnails(self._viewer)
|
||||
self._hide_progress()
|
||||
self._status_label.setText(
|
||||
f"Recadrage applique — {len(settings['pages'])} page(s)"
|
||||
)
|
||||
QTimer.singleShot(100, self._viewer.zoom_fit)
|
||||
except Exception as e:
|
||||
self._hide_progress()
|
||||
QMessageBox.critical(self, "Erreur", str(e))
|
||||
|
||||
def on_crop_rejected():
|
||||
# Revenir au fichier actuel (croppe ou non)
|
||||
current = self._current_file
|
||||
self._viewer.load_pdf(current)
|
||||
self._viewer.go_to_page(cur_page)
|
||||
self._page_panel.load_thumbnails(self._viewer)
|
||||
self._crop_dlg = None
|
||||
|
||||
self._crop_dlg.accepted.connect(on_crop_accepted)
|
||||
self._crop_dlg.rejected.connect(lambda: setattr(self, '_crop_dlg', None))
|
||||
self._crop_dlg.rejected.connect(on_crop_rejected)
|
||||
self._crop_dlg.show()
|
||||
|
||||
def _do_print(self):
|
||||
if not self._require_file():
|
||||
return
|
||||
import subprocess
|
||||
try:
|
||||
source = self._result_file or self._current_file
|
||||
subprocess.Popen(["cmd", "/c", "start", "", source], shell=True)
|
||||
self._status_label.setText("Ouverture pour impression...")
|
||||
if sys.platform == "win32":
|
||||
os.startfile(source, "print")
|
||||
else:
|
||||
import subprocess
|
||||
subprocess.Popen(["lp", source])
|
||||
self._status_label.setText("Impression lancee...")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Erreur", f"Impossible d'imprimer :\n{e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user