-
-
Save acbetter/32c575803ec361c3e82064e60db4e3e0 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3 | |
# -*- coding: utf-8 -*- | |
from PyQt5.QtCore import Qt | |
from PyQt5.QtGui import QImage, QPixmap, QPalette, QPainter | |
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter | |
from PyQt5.QtWidgets import QLabel, QSizePolicy, QScrollArea, QMessageBox, QMainWindow, QMenu, QAction, \ | |
qApp, QFileDialog | |
class QImageViewer(QMainWindow): | |
def __init__(self): | |
super().__init__() | |
self.printer = QPrinter() | |
self.scaleFactor = 0.0 | |
self.imageLabel = QLabel() | |
self.imageLabel.setBackgroundRole(QPalette.Base) | |
self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) | |
self.imageLabel.setScaledContents(True) | |
self.scrollArea = QScrollArea() | |
self.scrollArea.setBackgroundRole(QPalette.Dark) | |
self.scrollArea.setWidget(self.imageLabel) | |
self.scrollArea.setVisible(False) | |
self.setCentralWidget(self.scrollArea) | |
self.createActions() | |
self.createMenus() | |
self.setWindowTitle("Image Viewer") | |
self.resize(800, 600) | |
def open(self): | |
options = QFileDialog.Options() | |
# fileName = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath()) | |
fileName, _ = QFileDialog.getOpenFileName(self, 'QFileDialog.getOpenFileName()', '', | |
'Images (*.png *.jpeg *.jpg *.bmp *.gif)', options=options) | |
if fileName: | |
image = QImage(fileName) | |
if image.isNull(): | |
QMessageBox.information(self, "Image Viewer", "Cannot load %s." % fileName) | |
return | |
self.imageLabel.setPixmap(QPixmap.fromImage(image)) | |
self.scaleFactor = 1.0 | |
self.scrollArea.setVisible(True) | |
self.printAct.setEnabled(True) | |
self.fitToWindowAct.setEnabled(True) | |
self.updateActions() | |
if not self.fitToWindowAct.isChecked(): | |
self.imageLabel.adjustSize() | |
def print_(self): | |
dialog = QPrintDialog(self.printer, self) | |
if dialog.exec_(): | |
painter = QPainter(self.printer) | |
rect = painter.viewport() | |
size = self.imageLabel.pixmap().size() | |
size.scale(rect.size(), Qt.KeepAspectRatio) | |
painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) | |
painter.setWindow(self.imageLabel.pixmap().rect()) | |
painter.drawPixmap(0, 0, self.imageLabel.pixmap()) | |
def zoomIn(self): | |
self.scaleImage(1.25) | |
def zoomOut(self): | |
self.scaleImage(0.8) | |
def normalSize(self): | |
self.imageLabel.adjustSize() | |
self.scaleFactor = 1.0 | |
def fitToWindow(self): | |
fitToWindow = self.fitToWindowAct.isChecked() | |
self.scrollArea.setWidgetResizable(fitToWindow) | |
if not fitToWindow: | |
self.normalSize() | |
self.updateActions() | |
def about(self): | |
QMessageBox.about(self, "About Image Viewer", | |
"<p>The <b>Image Viewer</b> example shows how to combine " | |
"QLabel and QScrollArea to display an image. QLabel is " | |
"typically used for displaying text, but it can also display " | |
"an image. QScrollArea provides a scrolling view around " | |
"another widget. If the child widget exceeds the size of the " | |
"frame, QScrollArea automatically provides scroll bars.</p>" | |
"<p>The example demonstrates how QLabel's ability to scale " | |
"its contents (QLabel.scaledContents), and QScrollArea's " | |
"ability to automatically resize its contents " | |
"(QScrollArea.widgetResizable), can be used to implement " | |
"zooming and scaling features.</p>" | |
"<p>In addition the example shows how to use QPainter to " | |
"print an image.</p>") | |
def createActions(self): | |
self.openAct = QAction("&Open...", self, shortcut="Ctrl+O", triggered=self.open) | |
self.printAct = QAction("&Print...", self, shortcut="Ctrl+P", enabled=False, triggered=self.print_) | |
self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close) | |
self.zoomInAct = QAction("Zoom &In (25%)", self, shortcut="Ctrl++", enabled=False, triggered=self.zoomIn) | |
self.zoomOutAct = QAction("Zoom &Out (25%)", self, shortcut="Ctrl+-", enabled=False, triggered=self.zoomOut) | |
self.normalSizeAct = QAction("&Normal Size", self, shortcut="Ctrl+S", enabled=False, triggered=self.normalSize) | |
self.fitToWindowAct = QAction("&Fit to Window", self, enabled=False, checkable=True, shortcut="Ctrl+F", | |
triggered=self.fitToWindow) | |
self.aboutAct = QAction("&About", self, triggered=self.about) | |
self.aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt) | |
def createMenus(self): | |
self.fileMenu = QMenu("&File", self) | |
self.fileMenu.addAction(self.openAct) | |
self.fileMenu.addAction(self.printAct) | |
self.fileMenu.addSeparator() | |
self.fileMenu.addAction(self.exitAct) | |
self.viewMenu = QMenu("&View", self) | |
self.viewMenu.addAction(self.zoomInAct) | |
self.viewMenu.addAction(self.zoomOutAct) | |
self.viewMenu.addAction(self.normalSizeAct) | |
self.viewMenu.addSeparator() | |
self.viewMenu.addAction(self.fitToWindowAct) | |
self.helpMenu = QMenu("&Help", self) | |
self.helpMenu.addAction(self.aboutAct) | |
self.helpMenu.addAction(self.aboutQtAct) | |
self.menuBar().addMenu(self.fileMenu) | |
self.menuBar().addMenu(self.viewMenu) | |
self.menuBar().addMenu(self.helpMenu) | |
def updateActions(self): | |
self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked()) | |
self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked()) | |
self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked()) | |
def scaleImage(self, factor): | |
self.scaleFactor *= factor | |
self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) | |
self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor) | |
self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor) | |
self.zoomInAct.setEnabled(self.scaleFactor < 3.0) | |
self.zoomOutAct.setEnabled(self.scaleFactor > 0.333) | |
def adjustScrollBar(self, scrollBar, factor): | |
scrollBar.setValue(int(factor * scrollBar.value() | |
+ ((factor - 1) * scrollBar.pageStep() / 2))) | |
if __name__ == '__main__': | |
import sys | |
from PyQt5.QtWidgets import QApplication | |
app = QApplication(sys.argv) | |
imageViewer = QImageViewer() | |
imageViewer.show() | |
sys.exit(app.exec_()) | |
# TODO QScrollArea support mouse | |
# base on https://github.com/baoboa/pyqt5/blob/master/examples/widgets/imageviewer.py | |
# | |
# if you need Two Image Synchronous Scrolling in the window by PyQt5 and Python 3 | |
# please visit https://gist.github.com/acbetter/e7d0c600fdc0865f4b0ee05a17b858f2 |
Well done, it helped a lot!
Thank you very much. It was really helpful!
Awesome widgets example for displaying an image. Is there a decent example out there like this but using a python main.py file and a separate QML file?
Awesome widgets example for displaying an image. Is there a decent example out there like this but using a python main.py file and a separate QML file?
2021 now but this example is also decent. I'm unfamiliar with QML so you need write your own code.
Thanks man!
Thank you for this code. How can I make "Fit to window" not distort the image?
Added Fit To Width Function Maestro67au/QT5_Image_Viewer
For those that are interested, added OCR, directory selection, file selection. Just an example of what can be done.
https://github.com/Maestro67au/QT5_OCR_Tool
amazing !!!
@Maestro67au The shared link is broken, but, nice job. I think you meant to share this: https://github.com/Maestro67au/QT5_OCR_Tool
Hello @acbetter . Very good code, great job, keep up the good work! I'm using part of your code and I have a problem that I can't solve. I want to create a vertical line in this place by clicking the mouse on an image (pixmap) (as I understand it, I need to work with Qpainter), but for reasons unknown to me I can’t do this. If you were able to make such a large application, I think you might have some ideas about it. Thank you very much in advance!
Thank @Lightning228 , I do appreciate that. I think you can listen mouse move/click event and use this event to generate a new(modified) image and replace it by self.imageLabel.setPixmap(QPixmap.fromImage(your_new_image))
There's a example of mouse event listening but verticalScrollBar https://gist.github.com/acbetter/e7d0c600fdc0865f4b0ee05a17b858f2
Thank you very much. Helped my project a lot.