132 lines
4.0 KiB
Python
132 lines
4.0 KiB
Python
|
|
import io
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from PIL import Image
|
||
|
|
from PyQt6.QtCore import Qt
|
||
|
|
from PyQt6.QtGui import QImage, QPixmap
|
||
|
|
from PyQt6.QtWidgets import (
|
||
|
|
QApplication,
|
||
|
|
QGraphicsPixmapItem,
|
||
|
|
QGraphicsScene,
|
||
|
|
QGraphicsView,
|
||
|
|
QMainWindow,
|
||
|
|
QPushButton,
|
||
|
|
QVBoxLayout,
|
||
|
|
QWidget,
|
||
|
|
)
|
||
|
|
|
||
|
|
# For PyQt5 users, change the imports above to this:
|
||
|
|
# from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QVBoxLayout, QWidget, QPushButton, QFileDialog
|
||
|
|
# from PyQt5.QtGui import QPixmap
|
||
|
|
# from PyQt5.QtCore import Qt
|
||
|
|
|
||
|
|
|
||
|
|
class ZoomableView(QGraphicsView):
|
||
|
|
"""
|
||
|
|
A custom QGraphicsView that provides zoom functionality with the mouse wheel.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, scene):
|
||
|
|
super().__init__(scene)
|
||
|
|
# Set anchor points for zooming and resizing
|
||
|
|
self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
|
||
|
|
self.setResizeAnchor(QGraphicsView.ViewportAnchor.AnchorViewCenter)
|
||
|
|
|
||
|
|
def wheelEvent(self, event):
|
||
|
|
"""
|
||
|
|
Handles mouse wheel events to zoom in or out.
|
||
|
|
"""
|
||
|
|
# Get the amount of scroll
|
||
|
|
angle = event.angleDelta().y()
|
||
|
|
|
||
|
|
if angle > 0:
|
||
|
|
# Zoom in
|
||
|
|
factor = 1.25
|
||
|
|
else:
|
||
|
|
# Zoom out
|
||
|
|
factor = 0.8
|
||
|
|
|
||
|
|
self.scale(factor, factor)
|
||
|
|
|
||
|
|
|
||
|
|
class ImageViewer(QMainWindow):
|
||
|
|
"""
|
||
|
|
Main application window for viewing an image.
|
||
|
|
Includes loading, zooming, and panning functionality.
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
super().__init__()
|
||
|
|
|
||
|
|
self.setWindowTitle("PyQt Image Viewer (Load, Zoom, Pan)")
|
||
|
|
self.setGeometry(100, 100, 800, 700)
|
||
|
|
|
||
|
|
# Main widget and layout
|
||
|
|
central_widget = QWidget()
|
||
|
|
self.setCentralWidget(central_widget)
|
||
|
|
layout = QVBoxLayout(central_widget)
|
||
|
|
|
||
|
|
# 1. Create the QGraphicsScene
|
||
|
|
# The scene is the container for all 2D graphical items
|
||
|
|
self.scene = QGraphicsScene()
|
||
|
|
|
||
|
|
# 2. Create the custom QGraphicsView
|
||
|
|
# This is our custom view with zoom capabilities
|
||
|
|
self.view = ZoomableView(self.scene)
|
||
|
|
|
||
|
|
# 3. Enable panning (drag the scene with the mouse)
|
||
|
|
# The hand cursor will appear when you click and drag.
|
||
|
|
self.view.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
|
||
|
|
|
||
|
|
# Add a button to load an image
|
||
|
|
self.load_button = QPushButton("Load Image")
|
||
|
|
self.load_button.clicked.connect(self.load_image)
|
||
|
|
|
||
|
|
# Add widgets to the layout
|
||
|
|
layout.addWidget(self.load_button)
|
||
|
|
layout.addWidget(self.view)
|
||
|
|
|
||
|
|
# A variable to hold the currently displayed image item
|
||
|
|
self.pixmap_item = None
|
||
|
|
|
||
|
|
def load_image(self):
|
||
|
|
file_path = Path(
|
||
|
|
"/home/lambda/Downloads/f546ed6d35ee05338b8403d57dda10103ac3b1b8.jpg@672w_378h_1c_!web-home-common-cover.avif"
|
||
|
|
)
|
||
|
|
image_data = file_path.read_bytes()
|
||
|
|
im = Image.open(io.BytesIO(image_data))
|
||
|
|
pixmap = QPixmap.fromImage(
|
||
|
|
QImage(im.tobytes(), im.size[0], im.size[1], QImage.Format.Format_RGB888)
|
||
|
|
)
|
||
|
|
if pixmap.isNull():
|
||
|
|
print(f"Error: Failed to load image from {file_path}")
|
||
|
|
return
|
||
|
|
# If an image is already loaded, remove the old one first
|
||
|
|
if self.pixmap_item:
|
||
|
|
self.scene.removeItem(self.pixmap_item)
|
||
|
|
|
||
|
|
# 5. Create a QGraphicsPixmapItem to hold the image
|
||
|
|
self.pixmap_item = QGraphicsPixmapItem(pixmap)
|
||
|
|
|
||
|
|
# 6. Add the item to the scene
|
||
|
|
self.scene.addItem(self.pixmap_item)
|
||
|
|
|
||
|
|
# --- Optional: Improve the viewing experience ---
|
||
|
|
# Reset any previous transformations (like zoom/pan)
|
||
|
|
self.view.resetTransform()
|
||
|
|
# Fit the entire image within the view, maintaining aspect ratio
|
||
|
|
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
# Create the application instance
|
||
|
|
app = QApplication(sys.argv)
|
||
|
|
|
||
|
|
# Create and show the main window
|
||
|
|
viewer = ImageViewer()
|
||
|
|
viewer.show()
|
||
|
|
|
||
|
|
# Start the application's event loop
|
||
|
|
sys.exit(app.exec())
|