Zu QtPds gewechselt
This commit is contained in:
+108
-109
@@ -1,11 +1,12 @@
|
|||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
# import time
|
import time
|
||||||
|
|
||||||
import pymupdf # PyMuPDF
|
from PySide6.QtCore import Qt, QSize
|
||||||
from PySide6.QtCore import Qt
|
|
||||||
from PySide6.QtGui import QCursor, QPixmap, QImage, QPainter, QAction
|
from PySide6.QtGui import QCursor, QPixmap, QImage, QPainter, QAction
|
||||||
from PySide6.QtWidgets import QLabel, QMainWindow, QApplication, QStyleFactory
|
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
|
from ui.MainWinddow_ui import Ui_MainWindow
|
||||||
|
|
||||||
@@ -14,7 +15,8 @@ class MainWindow(QMainWindow):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
"""
|
"""
|
||||||
Konstruktor für die MainWindow-Klasse.
|
Konstruktor für die MainWindow-Klasse.
|
||||||
|
Verwendet PySide6.QtPdf für optimale Performance.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
parent: Übergeordnetes Widget, falls vorhanden
|
parent: Übergeordnetes Widget, falls vorhanden
|
||||||
"""
|
"""
|
||||||
@@ -28,7 +30,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.thumbnail_to_page = {}
|
self.thumbnail_to_page = {}
|
||||||
|
|
||||||
# PDF-Dokumente für späteres On-Demand-Rendering speichern
|
# 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
|
# Aktueller Zoom-Faktor
|
||||||
self.current_zoom = 100 # 100%
|
self.current_zoom = 100 # 100%
|
||||||
@@ -156,10 +158,22 @@ class MainWindow(QMainWindow):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Alle drei PDF-Dateien öffnen und speichern
|
# Alle drei PDF-Dateien öffnen mit QtPdf
|
||||||
diff_doc = pymupdf.open(diff_pdf_path)
|
diff_doc = QPdfDocument()
|
||||||
ref_doc = pymupdf.open(ref_pdf_path)
|
ref_doc = QPdfDocument()
|
||||||
new_doc = pymupdf.open(new_pdf_path)
|
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
|
# PDF-Dokumente für später speichern
|
||||||
self.pdf_documents[pdf_filename] = {
|
self.pdf_documents[pdf_filename] = {
|
||||||
@@ -169,22 +183,29 @@ class MainWindow(QMainWindow):
|
|||||||
}
|
}
|
||||||
|
|
||||||
print(f"PDFs geladen: {pdf_filename}")
|
print(f"PDFs geladen: {pdf_filename}")
|
||||||
print(f" diff: {len(diff_doc)} Seiten")
|
print(f" diff: {diff_doc.pageCount()} Seiten")
|
||||||
print(f" ref: {len(ref_doc)} Seiten")
|
print(f" ref: {ref_doc.pageCount()} Seiten")
|
||||||
print(f" new: {len(new_doc)} Seiten")
|
print(f" new: {new_doc.pageCount()} Seiten")
|
||||||
|
|
||||||
# Nehme die maximale Seitenzahl aller drei PDFs (diff_doc bestimmt die Anzahl)
|
# Nehme die Seitenzahl der diff-PDF als Basis
|
||||||
max_pages = len(diff_doc)
|
max_pages = diff_doc.pageCount()
|
||||||
|
|
||||||
|
# Performance-Test: Messe Thumbnail-Erstellung
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
# Erstelle nur Thumbnails (keine Vollbilder)
|
# Erstelle nur Thumbnails (keine Vollbilder)
|
||||||
for page_num in range(max_pages):
|
for page_num in range(max_pages):
|
||||||
# Nur diff-Seite für Thumbnail rendern
|
# Nur diff-Seite für Thumbnail rendern
|
||||||
diff_page = diff_doc[page_num]
|
page_size = diff_doc.pagePointSize(page_num)
|
||||||
matrix = pymupdf.Matrix(1.0, 1.0) # Normale Auflösung für Thumbnails
|
|
||||||
diff_pix = diff_page.get_pixmap(matrix=matrix)
|
# Skalierung für Thumbnail (entspricht ca. Matrix(1.0, 1.0) in PyMuPDF)
|
||||||
diff_img_data = diff_pix.tobytes("png")
|
scale_factor = 200.0 / page_size.width() # 200 Pixel Breite für Thumbnail
|
||||||
diff_qimg = QImage.fromData(diff_img_data)
|
|
||||||
diff_pixmap = QPixmap.fromImage(diff_qimg)
|
# 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 erstellen und zur linken Spalte hinzufügen
|
||||||
thumbnail = QLabel()
|
thumbnail = QLabel()
|
||||||
@@ -210,6 +231,9 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
print(f"Thumbnail für Seite {page_num + 1} erstellt")
|
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
|
# Setze die erste PDF als aktuelle PDF
|
||||||
if self.current_pdf is None:
|
if self.current_pdf is None:
|
||||||
self.current_pdf = pdf_filename
|
self.current_pdf = pdf_filename
|
||||||
@@ -248,52 +272,51 @@ class MainWindow(QMainWindow):
|
|||||||
print(f"PDF-Dokument {pdf_filename} nicht gefunden")
|
print(f"PDF-Dokument {pdf_filename} nicht gefunden")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
docs = self.pdf_documents[pdf_filename]
|
docs = self.pdf_documents[pdf_filename]
|
||||||
|
|
||||||
# Diff-Seite laden (bestimmt die Abmessungen)
|
# 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-Seite rendern (immer vorhanden)
|
||||||
diff_pix = diff_page.get_pixmap(matrix=matrix)
|
diff_image = diff_doc.render(page_num, render_size)
|
||||||
diff_img_data = diff_pix.tobytes("png")
|
diff_pixmap = QPixmap.fromImage(diff_image)
|
||||||
diff_qimg = QImage.fromData(diff_img_data)
|
|
||||||
diff_pixmap = QPixmap.fromImage(diff_qimg)
|
|
||||||
|
|
||||||
# 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_width = diff_pixmap.width()
|
||||||
diff_height = diff_pixmap.height()
|
diff_height = diff_pixmap.height()
|
||||||
|
|
||||||
# Ref-Seite prüfen und rendern oder weiße Seite erstellen
|
# Ref-Seite prüfen und rendern oder weiße Seite erstellen
|
||||||
if page_num < len(docs['ref']):
|
ref_doc = docs['ref']
|
||||||
ref_page = docs['ref'][page_num]
|
if page_num < ref_doc.pageCount():
|
||||||
ref_pix = ref_page.get_pixmap(matrix=matrix)
|
ref_image = ref_doc.render(page_num, render_size)
|
||||||
ref_img_data = ref_pix.tobytes("png")
|
ref_pixmap = QPixmap.fromImage(ref_image)
|
||||||
ref_qimg = QImage.fromData(ref_img_data)
|
|
||||||
ref_pixmap = QPixmap.fromImage(ref_qimg)
|
|
||||||
print(f"Ref-Seite {page_num + 1} gerendert")
|
print(f"Ref-Seite {page_num + 1} gerendert")
|
||||||
else:
|
else:
|
||||||
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
|
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
|
||||||
ref_pixmap = QPixmap(diff_width, diff_height)
|
ref_pixmap = QPixmap(diff_width, diff_height)
|
||||||
ref_pixmap.fill(Qt.GlobalColor.white)
|
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
|
# New-Seite prüfen und rendern oder weiße Seite erstellen
|
||||||
if page_num < len(docs['new']):
|
new_doc = docs['new']
|
||||||
new_page = docs['new'][page_num]
|
if page_num < new_doc.pageCount():
|
||||||
new_pix = new_page.get_pixmap(matrix=matrix)
|
new_image = new_doc.render(page_num, render_size)
|
||||||
new_img_data = new_pix.tobytes("png")
|
new_pixmap = QPixmap.fromImage(new_image)
|
||||||
new_qimg = QImage.fromData(new_img_data)
|
|
||||||
new_pixmap = QPixmap.fromImage(new_qimg)
|
|
||||||
print(f"New-Seite {page_num + 1} gerendert")
|
print(f"New-Seite {page_num + 1} gerendert")
|
||||||
else:
|
else:
|
||||||
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
|
# Erstelle weiße Seite mit gleichen Abmessungen wie Diff-Seite
|
||||||
new_pixmap = QPixmap(diff_width, diff_height)
|
new_pixmap = QPixmap(diff_width, diff_height)
|
||||||
new_pixmap.fill(Qt.GlobalColor.white)
|
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
|
# Cache die gerenderten Pixmaps für schnelle Alpha/Zoom-Operationen
|
||||||
self.current_rendered_pixmaps = {
|
self.current_rendered_pixmaps = {
|
||||||
@@ -309,7 +332,8 @@ class MainWindow(QMainWindow):
|
|||||||
# Zeige das Bild mit aktuellem Alpha- und Zoom-Wert an
|
# Zeige das Bild mit aktuellem Alpha- und Zoom-Wert an
|
||||||
self.update_current_display()
|
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:
|
except Exception as e:
|
||||||
print(f"Fehler beim Rendern der Seite {page_num + 1}: {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.setPixmap(layered_pixmap)
|
||||||
self.fullsize_label.setAlignment(Qt.AlignmentFlag.AlignHCenter)
|
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):
|
def create_layered_pixmap(self, ref_pixmap, diff_pixmap, new_pixmap, alpha_value):
|
||||||
"""
|
"""
|
||||||
Erstellt ein übergelagertes Pixmap basierend auf dem Alpha-Wert.
|
Erstellt ein übergelagertes Pixmap basierend auf dem Alpha-Wert.
|
||||||
@@ -432,6 +417,42 @@ class MainWindow(QMainWindow):
|
|||||||
painter.end()
|
painter.end()
|
||||||
return result
|
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):
|
def on_button_clicked(self):
|
||||||
"""Wird ausgeführt, wenn der Button geklickt wird."""
|
"""Wird ausgeführt, wenn der Button geklickt wird."""
|
||||||
print("Button wurde geklickt!")
|
print("Button wurde geklickt!")
|
||||||
@@ -469,26 +490,14 @@ class MainWindow(QMainWindow):
|
|||||||
self.update_current_display()
|
self.update_current_display()
|
||||||
|
|
||||||
def on_fullsize_mouse_press(self, event, fullsize_label):
|
def on_fullsize_mouse_press(self, event, fullsize_label):
|
||||||
"""
|
"""Wird ausgeführt, wenn die Maustaste auf einem großen Bild gedrückt wird."""
|
||||||
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
|
|
||||||
"""
|
|
||||||
if event.button() == Qt.MouseButton.LeftButton:
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
self.is_dragging = True
|
self.is_dragging = True
|
||||||
self.last_drag_position = event.globalPosition().toPoint()
|
self.last_drag_position = event.globalPosition().toPoint()
|
||||||
fullsize_label.setCursor(QCursor(Qt.CursorShape.ClosedHandCursor))
|
fullsize_label.setCursor(QCursor(Qt.CursorShape.ClosedHandCursor))
|
||||||
|
|
||||||
def on_fullsize_mouse_move(self, event, fullsize_label):
|
def on_fullsize_mouse_move(self, event, fullsize_label):
|
||||||
"""
|
"""Wird ausgeführt, wenn die Maus über einem großen Bild bewegt wird."""
|
||||||
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
|
|
||||||
"""
|
|
||||||
if self.is_dragging and self.last_drag_position is not None:
|
if self.is_dragging and self.last_drag_position is not None:
|
||||||
current_pos = event.globalPosition().toPoint()
|
current_pos = event.globalPosition().toPoint()
|
||||||
delta = current_pos - self.last_drag_position
|
delta = current_pos - self.last_drag_position
|
||||||
@@ -509,13 +518,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.last_drag_position = current_pos
|
self.last_drag_position = current_pos
|
||||||
|
|
||||||
def on_fullsize_mouse_release(self, event, fullsize_label):
|
def on_fullsize_mouse_release(self, event, fullsize_label):
|
||||||
"""
|
"""Wird ausgeführt, wenn die Maustaste auf einem großen Bild losgelassen wird."""
|
||||||
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
|
|
||||||
"""
|
|
||||||
if event.button() == Qt.MouseButton.LeftButton:
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
self.is_dragging = False
|
self.is_dragging = False
|
||||||
self.last_drag_position = None
|
self.last_drag_position = None
|
||||||
@@ -523,9 +526,5 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Wird beim Schließen der Anwendung aufgerufen."""
|
"""Wird beim Schließen der Anwendung aufgerufen."""
|
||||||
# PDF-Dokumente schließen
|
# PDF-Dokumente schließen ist bei QtPdf automatisch durch Garbage Collection
|
||||||
for pdf_filename, docs in self.pdf_documents.items():
|
|
||||||
docs['diff'].close()
|
|
||||||
docs['ref'].close()
|
|
||||||
docs['new'].close()
|
|
||||||
super().closeEvent(event)
|
super().closeEvent(event)
|
||||||
|
|||||||
Reference in New Issue
Block a user