Zu QtPds gewechselt

This commit is contained in:
2025-05-31 21:27:58 +02:00
parent 36372992c4
commit ce339a31ba
+106 -107
View File
@@ -1,11 +1,12 @@
import glob
import os
# import time
import time
import pymupdf # PyMuPDF
from PySide6.QtCore import Qt
from PySide6.QtCore import Qt, QSize
from PySide6.QtGui import QCursor, QPixmap, QImage, QPainter, QAction
from PySide6.QtWidgets import QLabel, QMainWindow, QApplication, QStyleFactory
from PySide6.QtPdf import QPdfDocument
from PySide6.QtPdfWidgets import QPdfView
from ui.MainWinddow_ui import Ui_MainWindow
@@ -14,6 +15,7 @@ class MainWindow(QMainWindow):
def __init__(self, parent=None):
"""
Konstruktor für die MainWindow-Klasse.
Verwendet PySide6.QtPdf für optimale Performance.
Args:
parent: Übergeordnetes Widget, falls vorhanden
@@ -28,7 +30,7 @@ class MainWindow(QMainWindow):
self.thumbnail_to_page = {}
# PDF-Dokumente für späteres On-Demand-Rendering speichern
self.pdf_documents = {} # {pdf_filename: {'diff': doc, 'ref': doc, 'new': doc}}
self.pdf_documents = {} # {pdf_filename: {'diff': QPdfDocument, 'ref': QPdfDocument, 'new': QPdfDocument}}
# Aktueller Zoom-Faktor
self.current_zoom = 100 # 100%
@@ -156,10 +158,22 @@ class MainWindow(QMainWindow):
continue
try:
# Alle drei PDF-Dateien öffnen und speichern
diff_doc = pymupdf.open(diff_pdf_path)
ref_doc = pymupdf.open(ref_pdf_path)
new_doc = pymupdf.open(new_pdf_path)
# Alle drei PDF-Dateien öffnen mit QtPdf
diff_doc = QPdfDocument()
ref_doc = QPdfDocument()
new_doc = QPdfDocument()
# PDF-Dateien laden
diff_doc.load(diff_pdf_path)
ref_doc.load(ref_pdf_path)
new_doc.load(new_pdf_path)
# Warten bis PDFs geladen sind
if (diff_doc.status() != QPdfDocument.Status.Ready or
ref_doc.status() != QPdfDocument.Status.Ready or
new_doc.status() != QPdfDocument.Status.Ready):
print(f"Fehler beim Laden der PDFs für {pdf_filename}")
continue
# PDF-Dokumente für später speichern
self.pdf_documents[pdf_filename] = {
@@ -169,22 +183,29 @@ class MainWindow(QMainWindow):
}
print(f"PDFs geladen: {pdf_filename}")
print(f" diff: {len(diff_doc)} Seiten")
print(f" ref: {len(ref_doc)} Seiten")
print(f" new: {len(new_doc)} Seiten")
print(f" diff: {diff_doc.pageCount()} Seiten")
print(f" ref: {ref_doc.pageCount()} Seiten")
print(f" new: {new_doc.pageCount()} Seiten")
# Nehme die maximale Seitenzahl aller drei PDFs (diff_doc bestimmt die Anzahl)
max_pages = len(diff_doc)
# Nehme die Seitenzahl der diff-PDF als Basis
max_pages = diff_doc.pageCount()
# Performance-Test: Messe Thumbnail-Erstellung
start_time = time.time()
# Erstelle nur Thumbnails (keine Vollbilder)
for page_num in range(max_pages):
# Nur diff-Seite für Thumbnail rendern
diff_page = diff_doc[page_num]
matrix = pymupdf.Matrix(1.0, 1.0) # Normale Auflösung für Thumbnails
diff_pix = diff_page.get_pixmap(matrix=matrix)
diff_img_data = diff_pix.tobytes("png")
diff_qimg = QImage.fromData(diff_img_data)
diff_pixmap = QPixmap.fromImage(diff_qimg)
page_size = diff_doc.pagePointSize(page_num)
# Skalierung für Thumbnail (entspricht ca. Matrix(1.0, 1.0) in PyMuPDF)
scale_factor = 200.0 / page_size.width() # 200 Pixel Breite für Thumbnail
# Seite rendern
page_image = diff_doc.render(page_num, QSize(int(page_size.width() * scale_factor),
int(page_size.height() * scale_factor)))
diff_pixmap = QPixmap.fromImage(page_image)
# Thumbnail erstellen und zur linken Spalte hinzufügen
thumbnail = QLabel()
@@ -210,6 +231,9 @@ class MainWindow(QMainWindow):
print(f"Thumbnail für Seite {page_num + 1} erstellt")
thumbnail_time = time.time() - start_time
print(f"Performance: {max_pages} Thumbnails in {thumbnail_time:.3f}s")
# Setze die erste PDF als aktuelle PDF
if self.current_pdf is None:
self.current_pdf = pdf_filename
@@ -248,52 +272,51 @@ class MainWindow(QMainWindow):
print(f"PDF-Dokument {pdf_filename} nicht gefunden")
return
start_time = time.time()
try:
docs = self.pdf_documents[pdf_filename]
# Diff-Seite laden (bestimmt die Abmessungen)
diff_page = docs['diff'][page_num]
diff_doc = docs['diff']
page_size = diff_doc.pagePointSize(page_num)
# Seiten in hoher Auflösung rendern
matrix = pymupdf.Matrix(2.0, 2.0) # 2x Vergrößerung für bessere Qualität
# Hohe Auflösung für Vollbild (entspricht ca. Matrix(2.0, 2.0) in PyMuPDF)
scale_factor = 2.0
render_size = QSize(int(page_size.width() * scale_factor),
int(page_size.height() * scale_factor))
# Diff-Seite rendern (immer vorhanden)
diff_pix = diff_page.get_pixmap(matrix=matrix)
diff_img_data = diff_pix.tobytes("png")
diff_qimg = QImage.fromData(diff_img_data)
diff_pixmap = QPixmap.fromImage(diff_qimg)
diff_image = diff_doc.render(page_num, render_size)
diff_pixmap = QPixmap.fromImage(diff_image)
# Ermittle die Abmessungen der Diff-Seite für weiße Seiten
# Ermittle die Abmessungen für weiße Seiten
diff_width = diff_pixmap.width()
diff_height = diff_pixmap.height()
# Ref-Seite prüfen und rendern oder weiße Seite erstellen
if page_num < len(docs['ref']):
ref_page = docs['ref'][page_num]
ref_pix = ref_page.get_pixmap(matrix=matrix)
ref_img_data = ref_pix.tobytes("png")
ref_qimg = QImage.fromData(ref_img_data)
ref_pixmap = QPixmap.fromImage(ref_qimg)
ref_doc = docs['ref']
if page_num < ref_doc.pageCount():
ref_image = ref_doc.render(page_num, render_size)
ref_pixmap = QPixmap.fromImage(ref_image)
print(f"Ref-Seite {page_num + 1} gerendert")
else:
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
ref_pixmap = QPixmap(diff_width, diff_height)
ref_pixmap.fill(Qt.GlobalColor.white)
print(f"Weiße Ref-Seite {page_num + 1} erstellt (Seite existiert nicht)")
print(f"Weiße Ref-Seite {page_num + 1} erstellt")
# New-Seite prüfen und rendern oder weiße Seite erstellen
if page_num < len(docs['new']):
new_page = docs['new'][page_num]
new_pix = new_page.get_pixmap(matrix=matrix)
new_img_data = new_pix.tobytes("png")
new_qimg = QImage.fromData(new_img_data)
new_pixmap = QPixmap.fromImage(new_qimg)
new_doc = docs['new']
if page_num < new_doc.pageCount():
new_image = new_doc.render(page_num, render_size)
new_pixmap = QPixmap.fromImage(new_image)
print(f"New-Seite {page_num + 1} gerendert")
else:
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
new_pixmap = QPixmap(diff_width, diff_height)
new_pixmap.fill(Qt.GlobalColor.white)
print(f"Weiße New-Seite {page_num + 1} erstellt (Seite existiert nicht)")
print(f"Weiße New-Seite {page_num + 1} erstellt")
# Cache die gerenderten Pixmaps für schnelle Alpha/Zoom-Operationen
self.current_rendered_pixmaps = {
@@ -309,7 +332,8 @@ class MainWindow(QMainWindow):
# Zeige das Bild mit aktuellem Alpha- und Zoom-Wert an
self.update_current_display()
print(f"Seite {page_num + 1} erfolgreich gerendert und gecacht")
render_time = time.time() - start_time
print(f"Performance: Seite {page_num + 1} gerendert in {render_time:.3f}s")
except Exception as e:
print(f"Fehler beim Rendern der Seite {page_num + 1}: {e}")
@@ -342,45 +366,6 @@ class MainWindow(QMainWindow):
self.fullsize_label.setPixmap(layered_pixmap)
self.fullsize_label.setAlignment(Qt.AlignmentFlag.AlignHCenter)
def _clear_layout(self, layout):
"""Entfernt alle Widgets aus einem Layout."""
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
def _connect_signals(self):
"""Verbindet Signale mit den entsprechenden Slots."""
# Button-Klicks verbinden
self.ui.pushButton.clicked.connect(self.on_button_clicked)
# Zoom-Slider verbinden
self.ui.zoom.valueChanged.connect(self.apply_zoom)
self.ui.zoom.mouseDoubleClickEvent = lambda event: self.ui.zoom.setValue(100)
# Alpha-Slider verbinden
self.ui.alpha.valueChanged.connect(self.on_alpha_changed)
self.ui.alpha.mouseDoubleClickEvent = lambda event: self.ui.alpha.setValue(0)
def on_alpha_changed(self, alpha_value):
"""
Wird ausgeführt, wenn der Alpha-Slider geändert wird.
Optimiert: Verwendet gecachte Pixmaps statt erneutes PDF-Rendering.
Args:
alpha_value: Der neue Alpha-Wert (-100 bis 100)
"""
print(f"Alpha geändert auf {alpha_value}")
# start = time.time()
# Verwende gecachte Pixmaps für schnelle Alpha-Änderungen
self.update_current_display()
# dauer = time.time() - start
# print(f"Dauer: {dauer}")
def create_layered_pixmap(self, ref_pixmap, diff_pixmap, new_pixmap, alpha_value):
"""
Erstellt ein übergelagertes Pixmap basierend auf dem Alpha-Wert.
@@ -432,6 +417,42 @@ class MainWindow(QMainWindow):
painter.end()
return result
def _clear_layout(self, layout):
"""Entfernt alle Widgets aus einem Layout."""
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
def _connect_signals(self):
"""Verbindet Signale mit den entsprechenden Slots."""
# Button-Klicks verbinden
self.ui.pushButton.clicked.connect(self.on_button_clicked)
# Zoom-Slider verbinden
self.ui.zoom.valueChanged.connect(self.apply_zoom)
# Alpha-Slider verbinden
self.ui.alpha.valueChanged.connect(self.on_alpha_changed)
def on_alpha_changed(self, alpha_value):
"""
Wird ausgeführt, wenn der Alpha-Slider geändert wird.
Optimiert: Verwendet gecachte Pixmaps statt erneutes PDF-Rendering.
Args:
alpha_value: Der neue Alpha-Wert (-100 bis 100)
"""
print(f"Alpha geändert auf {alpha_value}")
start_time = time.time()
# Verwende gecachte Pixmaps für schnelle Alpha-Änderungen
self.update_current_display()
alpha_time = time.time() - start_time
print(f"Alpha-Update in {alpha_time:.6f}s")
def on_button_clicked(self):
"""Wird ausgeführt, wenn der Button geklickt wird."""
print("Button wurde geklickt!")
@@ -469,26 +490,14 @@ class MainWindow(QMainWindow):
self.update_current_display()
def on_fullsize_mouse_press(self, event, fullsize_label):
"""
Wird ausgeführt, wenn die Maustaste auf einem großen Bild gedrückt wird.
Args:
event: Das Maus-Event
fullsize_label: Das große Bild-Label
"""
"""Wird ausgeführt, wenn die Maustaste auf einem großen Bild gedrückt wird."""
if event.button() == Qt.MouseButton.LeftButton:
self.is_dragging = True
self.last_drag_position = event.globalPosition().toPoint()
fullsize_label.setCursor(QCursor(Qt.CursorShape.ClosedHandCursor))
def on_fullsize_mouse_move(self, event, fullsize_label):
"""
Wird ausgeführt, wenn die Maus über einem großen Bild bewegt wird.
Args:
event: Das Maus-Event
fullsize_label: Das große Bild-Label
"""
"""Wird ausgeführt, wenn die Maus über einem großen Bild bewegt wird."""
if self.is_dragging and self.last_drag_position is not None:
current_pos = event.globalPosition().toPoint()
delta = current_pos - self.last_drag_position
@@ -509,13 +518,7 @@ class MainWindow(QMainWindow):
self.last_drag_position = current_pos
def on_fullsize_mouse_release(self, event, fullsize_label):
"""
Wird ausgeführt, wenn die Maustaste auf einem großen Bild losgelassen wird.
Args:
event: Das Maus-Event
fullsize_label: Das große Bild-Label
"""
"""Wird ausgeführt, wenn die Maustaste auf einem großen Bild losgelassen wird."""
if event.button() == Qt.MouseButton.LeftButton:
self.is_dragging = False
self.last_drag_position = None
@@ -523,9 +526,5 @@ class MainWindow(QMainWindow):
def closeEvent(self, event):
"""Wird beim Schließen der Anwendung aufgerufen."""
# PDF-Dokumente schließen
for pdf_filename, docs in self.pdf_documents.items():
docs['diff'].close()
docs['ref'].close()
docs['new'].close()
# PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection
super().closeEvent(event)