PyQt5图片浏览器

分享一个图片浏览器

实现方式

qt本身有一个QGraphicsView类用来当做视图框架。
具体参考:如何在pyqt中使用 QGraphicsView 实现图片查看器
不过大佬给的例子,功能有点少,因此需要添加一下其他的功能

功能实现

  1. 图片旋转(顺时针/逆时针)
  2. 设置 1:1 大小
  3. 缩放以适应

代码示例:

    def setOriginalSize(self):
        """
        设置 1:1 大小
        :return:
        """
        self.resetTransform()
        self.setSceneRect(QRectF(self.pixmap.rect()))
        self.__setDragEnabled(self.__isEnableDrag())
        self.zoomInTimes = self.getZoomInTimes(self.pixmap.width())
    def setAdaptation(self):
        """
        缩放以适应
        :return:
        """
        self.setSceneRect(QRectF(self.pixmap.rect()))
        self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)
        self.__setDragEnabled(False)
        self.zoomInTimes = 0

    def rotationAngle(self):
        return self._rotationAngle

    def rotateClockwise(self, stepSize: int = 90):
        """
        顺时针旋转
        :param stepSize: 步长,旋转角度
        :return:
        """
        if self.pixmap.fileName() is None:
            return
        self._rotationAngle = self._rotationAngle + stepSize
        self.__rotation(self._rotationAngle)

    def __rotation(self, stepSize: int):
        """
        指定图片中心并旋转
        :return:
        """
        self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())  # 指定图片旋转中心点
        self.pixmapItem.setRotation(stepSize)
        self.setAdaptation()

具体代码

# coding:utf-8
from PyQt5.QtCore import QRectF, QSize, Qt
from PyQt5.QtGui import QPainter, QPixmap, QWheelEvent, QResizeEvent
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsPixmapItem, QGraphicsItem


class Pixmap(QPixmap):
    def __init__(self, fileName: str, *args, **kwargs):
        super().__init__(fileName, *args, **kwargs)
        self._fileName = fileName

    def fileName(self):
        return self._fileName


class ImageGraphicsView(QGraphicsView):
    """
    图片查看器
    """

    def __init__(self, fileName: str = None, parent=None):
        super().__init__(parent)
        self._rotationAngle = 0

        self.zoomInTimes = 0
        self.maxZoomInTimes = 22
        self.pixmap = Pixmap(fileName)
        self.pixmapItem = QGraphicsPixmapItem()
        self.graphicsScene = QGraphicsScene()
        self.displayedImageSize = QSize(0, 0)

        self.__initWidget()

    def __initWidget(self):
        """
        初始化小部件
        :return:
        """
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏水平滚动条
        self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)  # 隐藏垂直滚动条
        self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)  # 以鼠标所在位置为锚点进行缩放
        self.pixmapItem.setTransformationMode(Qt.TransformationMode.SmoothTransformation)  # 平滑转型
        self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)  # 平滑像素图变换

        self.pixmapItem.setPixmap(self.pixmap)
        self.graphicsScene.addItem(self.pixmapItem)
        self.setScene(self.graphicsScene)

        self.setStyleSheet('background-color: #ffffff;')

    def setImage(self, fileName: str):
        """
        设置显示的图片
        :param fileName:
        :return:
        """
        self.resetTransform()
        del self.pixmap
        self.pixmap = Pixmap(fileName)
        self.pixmapItem.setPixmap(self.pixmap)
        self.zoomInTimes = 0
        # 调整图片大小
        self.setSceneRect(QRectF(self.pixmap.rect()))
        ratio = self.__getScaleRatio()
        self.displayedImageSize = self.pixmap.size() * ratio
        if ratio < 1:
            self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)
        self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())

    def setOriginalSize(self):
        """
        设置 1:1 大小
        :return:
        """
        self.resetTransform()
        self.setSceneRect(QRectF(self.pixmap.rect()))
        self.__setDragEnabled(self.__isEnableDrag())
        self.zoomInTimes = self.getZoomInTimes(self.pixmap.width())

    def setAdaptation(self):
        """
        缩放以适应
        :return:
        """
        self.setSceneRect(QRectF(self.pixmap.rect()))
        self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)
        self.__setDragEnabled(False)
        self.zoomInTimes = 0

    def rotationAngle(self):
        return self._rotationAngle

    def rotateClockwise(self, stepSize: int = 90):
        """
        顺时针旋转
        :param stepSize: 步长,旋转角度
        :return:
        """
        if self.pixmap.fileName() is None:
            return
        self._rotationAngle = self._rotationAngle + stepSize
        self.__rotation(self._rotationAngle)

    def __rotation(self, stepSize: int):
        """
        指定图片中心并旋转
        :return:
        """
        self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())  # 指定图片旋转中心点
        self.pixmapItem.setRotation(stepSize)
        self.setAdaptation()

    def __isEnableDrag(self):
        """
        根据图片的尺寸决定是否启动拖拽功能
        :return:
        """
        v = self.verticalScrollBar().maximum() > 0
        h = self.horizontalScrollBar().maximum() > 0
        return v or h

    def __setDragEnabled(self, isEnabled: bool):
        """
        设置拖拽是否启动
        :param isEnabled: bool
        :return:
        """
        if isEnabled:
            self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
        else:
            self.setDragMode(QGraphicsView.DragMode.NoDrag)

    def __getScaleRatio(self):
        """
        获取显示的图像和原始图像的缩放比例
        :return:
        """
        if self.pixmap.isNull():
            return 1

        pw = self.pixmap.width()
        ph = self.pixmap.height()
        rw = min(1, self.width() / pw)
        rh = min(1, self.height() / ph)
        return min(rw, rh)

    def enlargePicture(self, anchor=QGraphicsView.AnchorUnderMouse):
        """
        放大图片
        :return:
        """
        if self.zoomInTimes == self.maxZoomInTimes:
            return
        self.setTransformationAnchor(anchor)
        self.zoomInTimes += 1
        self.scale(1.1, 1.1)
        self.__setDragEnabled(self.__isEnableDrag())

        # 还原 anchor
        self.setTransformationAnchor(self.AnchorUnderMouse)

    def shrinkPicture(self, anchor=QGraphicsView.AnchorUnderMouse):
        """
        缩小图片
        :return:
        """
        if self.zoomInTimes == 0 and not self.__isEnableDrag():
            return

        self.setTransformationAnchor(anchor)

        self.zoomInTimes -= 1

        # 原始图像的大小
        pw = self.pixmap.width()
        ph = self.pixmap.height()

        # 实际显示的图像宽度
        w = self.displayedImageSize.width() * 1.1 ** self.zoomInTimes
        h = self.displayedImageSize.height() * 1.1 ** self.zoomInTimes

        if pw > self.width() or ph > self.height():
            # 在窗口尺寸小于原始图像时禁止继续缩小图像比窗口还小
            if w <= self.width() and h <= self.height():
                self.fitInView(self.pixmapItem)
            else:
                self.scale(1 / 1.1, 1 / 1.1)
        else:
            # 在窗口尺寸大于图像时不允许缩小的比原始图像小
            if w <= pw:
                self.resetTransform()
            else:
                self.scale(1 / 1.1, 1 / 1.1)

        self.__setDragEnabled(self.__isEnableDrag())

        # 还原 anchor
        self.setTransformationAnchor(self.AnchorUnderMouse)

    def getZoomInTimes(self, width: int, step: int = 100):
        for i in range(0, self.maxZoomInTimes):
            if width - self.displayedImageSize.width() * 1.1 ** i <= step:
                return i
        return self.maxZoomInTimes

    def fitInView(self, item: QGraphicsItem, mode=Qt.AspectRatioMode.KeepAspectRatio):
        """
        缩放场景使其适应窗口大小
        :param item:
        :param mode:
        :return:
        """
        super().fitInView(item, mode)
        self.displayedImageSize = self.__getScaleRatio() * self.pixmap.size()
        self.zoomInTimes = 0

    def resizeEvent(self, event: QResizeEvent):
        if self.zoomInTimes > 0:
            return
        # 调整图片大小
        ratio = self.__getScaleRatio()
        self.displayedImageSize = self.pixmap.size() * ratio
        if ratio < 1:
            self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)
        else:
            self.resetTransform()

    def resetTransform(self):
        """
        重置变换
        :return:
        """
        self.zoomInTimes = 0
        self.__setDragEnabled(False)
        super().resetTransform()

    def wheelEvent(self, e: QWheelEvent):
        """
        滚动鼠标滚轮缩放图片
        :param e:
        :return:
        """
        if e.angleDelta().y() > 0:
            self.enlargePicture()
        else:
            self.shrinkPicture()

该函数可以显示图片实现图片下旋转、放大、缩小等功能

界面实现

pillow源码修改

在实现图片列表时,如果全部加载出来会直接爆内存,因此需要借助pillow生成缩略图,但是pillow最新版本没有适配PyQt5,如果使用需要改源码。

ImageQt.py中修改源码
在这里插入图片描述
将红框中的代码加上就行了。
在这里插入图片描述

ImageQt错误

如果你使用了pillow这个库直接转为QPixmap你就会发现很多问题。

PyQt5+pillow实现缩略图,代码示例:

import sys
from PyQt5.Qt import *
import res.res_rc
from PIL import Image, ImageQt


class Window(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.vBox = QVBoxLayout(self)
        self.vBox.setContentsMargins(0, 0, 0, 0)
        self.vBox.setSpacing(0)
        file = r"G:\手机\壁纸\电脑壁纸\1689637545648.png"
        img = Image.open(file)
        img.thumbnail((200, 120))

        label = QLabel()
        label.setPixmap(ImageQt.toqpixmap(img))

        self.vBox.addWidget(label)


if __name__ == '__main__':
    QApplication.setHighDpiScaleFactorRoundingPolicy(
        Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)
    demo = Window()
    demo.resize(800, 600)
    demo.show()
    sys.exit(app.exec_())

运行结果:

运行后,你会发现基本上所有图片都会变成花屏,于是就直接放弃了,那么只能生成本地图片,然后在显示出来,于是使用本地sqlite数据库,为了使方便引入了SQLAlchemy来管理数据库,别问为什么,问就是不想写SQL,这要也方便了后期拓展

def CreateThumbnail(fileName, saveFile, *, size=(200, 120), **kwargs):
    """创建缩略图"""
    img = Image.open(fileName)
    img.thumbnail(size=size, **kwargs)
    img.save(saveFile)

在这里插入图片描述

主页面布局

在这里插入图片描述

项目开源地址

https://gitee.com/chiyaun/picture-browser.git

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyQt5是一款基于Python的GUI库,提供了丰富的功能和组件可用于创建各种类型的应用程序。要实现浏览图片的功能,可以使用PyQt5中的QFileDialog和QLabel组件。 首先,需要导入PyQt5和相关模块: ```python import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QLabel from PyQt5.QtGui import QPixmap ``` 然后,创建一个继承自QMainWindow的窗口类,重写其中的一些方法,并添加一个QLabel用于显示图片: ```python class ImageViewer(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.label = QLabel(self) self.setCentralWidget(self.label) self.setWindowTitle('图片浏览器') self.setGeometry(100, 100, 500, 500) ``` 在initUI()方法中,创建了一个QLabel作为中央控件,并将其设置为窗口的中央部分。接下来,需要添加一个方法来处理打开图片的事件: ```python def openImage(self): options = QFileDialog.Options() options |= QFileDialog.ReadOnly fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "图像文件 (*.png *.jpg *.bmp)", options=options) if fileName: pixmap = QPixmap(fileName) self.label.setPixmap(pixmap) self.label.adjustSize() ``` 这个方法首先创建了一个QFileDialog以供用户选择要打开的图片。然后,检查是否选择了有效的文件名。如果选择了有效的文件名,就创建一个QPixmap对象,并使用setPixmap()方法设置给label,然后调整label的大小以适应图片。 最后,需要将该方法连接到打开图片的动作: ```python def initUI(self): self.label = QLabel(self) self.setCentralWidget(self.label) self.setWindowTitle('图片浏览器') self.setGeometry(100, 100, 500, 500) openAction = QAction('打开', self) openAction.setShortcut('Ctrl+O') openAction.triggered.connect(self.openImage) menubar = self.menuBar() fileMenu = menubar.addMenu('文件') fileMenu.addAction(openAction) ``` 在initUI()方法中,创建了一个打开动作,并设置快捷键为Ctrl+O。将该动作连接到openImage()方法,然后创建一个菜单栏,并在文件菜单中添加该动作。 最后,创建应用程序实例,并运行: ```python if __name__ == '__main__': app = QApplication(sys.argv) window = ImageViewer() window.show() sys.exit(app.exec_()) ``` 这样就实现了一个简单的图片浏览器应用程序。用户可以通过点击文件菜单中的打开动作来选择并浏览图片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值