PyQt5图片浏览器

PyQt5图片浏览器

  • 实现方式
    • 功能实现
    • 具体代码
  • 界面实现
    • `pillow`源码修改
    • `ImageQt`错误
    • 主页面布局
  • 项目开源地址

分享一个图片浏览器

实现方式

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 = 0def rotationAngle(self):return self._rotationAngledef rotateClockwise(self, stepSize: int = 90):"""顺时针旋转:param stepSize: 步长,旋转角度:return:"""if self.pixmap.fileName() is None:returnself._rotationAngle = self._rotationAngle + stepSizeself.__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, QGraphicsItemclass Pixmap(QPixmap):def __init__(self, fileName: str, *args, **kwargs):super().__init__(fileName, *args, **kwargs)self._fileName = fileNamedef fileName(self):return self._fileNameclass ImageGraphicsView(QGraphicsView):"""图片查看器"""def __init__(self, fileName: str = None, parent=None):super().__init__(parent)self._rotationAngle = 0self.zoomInTimes = 0self.maxZoomInTimes = 22self.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.pixmapself.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() * ratioif 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 = 0def rotationAngle(self):return self._rotationAngledef rotateClockwise(self, stepSize: int = 90):"""顺时针旋转:param stepSize: 步长,旋转角度:return:"""if self.pixmap.fileName() is None:returnself._rotationAngle = self._rotationAngle + stepSizeself.__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() > 0h = self.horizontalScrollBar().maximum() > 0return v or hdef __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 1pw = 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:returnself.setTransformationAnchor(anchor)self.zoomInTimes += 1self.scale(1.1, 1.1)self.__setDragEnabled(self.__isEnableDrag())# 还原 anchorself.setTransformationAnchor(self.AnchorUnderMouse)def shrinkPicture(self, anchor=QGraphicsView.AnchorUnderMouse):"""缩小图片:return:"""if self.zoomInTimes == 0 and not self.__isEnableDrag():returnself.setTransformationAnchor(anchor)self.zoomInTimes -= 1# 原始图像的大小pw = self.pixmap.width()ph = self.pixmap.height()# 实际显示的图像宽度w = self.displayedImageSize.width() * 1.1 ** self.zoomInTimesh = self.displayedImageSize.height() * 1.1 ** self.zoomInTimesif 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())# 还原 anchorself.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 ireturn self.maxZoomInTimesdef 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 = 0def resizeEvent(self, event: QResizeEvent):if self.zoomInTimes > 0:return# 调整图片大小ratio = self.__getScaleRatio()self.displayedImageSize = self.pixmap.size() * ratioif ratio < 1:self.fitInView(self.pixmapItem, Qt.KeepAspectRatio)else:self.resetTransform()def resetTransform(self):"""重置变换:return:"""self.zoomInTimes = 0self.__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, ImageQtclass 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/705221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聚集高速托盘类四向穿梭车ASRV|一车跑全仓可获得10000个货位的HEGERLS智能搬运机器人

随着国内外制造业加速转型升级&#xff0c;越来越多的企业需要进行物流智能化升级&#xff0c;但是往往受到仓库面积、高度、形状等现实条件的限制&#xff0c;以及市场不确定性因素的影响。因此&#xff0c;相对于投资传统的自动化立体库&#xff0c;企业更倾向于选择智能化、…

机器学习-01-课程目标与职位分析

总结 本系列是机器学习课程的第01篇&#xff0c;主要介绍本门课程的课程目标与职位分析 教材 数据挖掘与机器学习 课程教学方法 布鲁姆教学法 认知领域&#xff08;cognitive domain&#xff09; 1.知道&#xff08;知识&#xff09;&#xff08;knowledge&#xff09; 是指…

细嗦MySQL三大日志

文章目录 三大日志&#xff1a;binlog&#xff08;归档日志&#xff09;、redo log&#xff08;重做日志&#xff09;、undo log&#xff08;回滚日志&#xff09;redo log刷盘机制日志文件组 binlog记录格式写入机制 两阶段提交undo log提供回滚操作提供MVCC&#xff08;多版本…

科技云报道:黑马Groq单挑英伟达,AI芯片要变天?

科技云报道原创。 近一周来&#xff0c;大模型领域重磅产品接连推出&#xff1a;OpenAI发布“文字生视频”大模型Sora&#xff1b;Meta发布视频预测大模型 V-JEPA&#xff1b;谷歌发布大模型 Gemini 1.5 Pro&#xff0c;更毫无预兆地发布了开源模型Gemma… 难怪网友们感叹&am…

【Excel PDF 系列】POI + iText 库实现 Excel 转换 PDF

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 如果您有疑问或者见解&#xff0c;欢迎指教&#xff1a; 企鹅&#xff1a;869192208 文章目录 前言转换前后效果引入 pom 配置代码实现 前言 最近遇到生成 Excel 并转 pdf 的需求&#xff0c;磕磕碰碰总…

stm32——hal库学习笔记(DMA实验)

一、DMA介绍&#xff08;了解&#xff09; 二、DMA结构框图介绍&#xff08;熟悉&#xff09; 三、DMA相关寄存器介绍&#xff08;熟悉&#xff09; 四、DMA相关HAL库驱动介绍&#xff08;掌握&#xff09; 五、DMA配置步骤&#xff08;掌握&#xff09; 六、编程实战&#xff…

Anaconda和TensorFlow环境搭建!!

Anaconda下载 进入官网下载 https://www.anaconda.com/download 也可以通过清华的映像站下载&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 我这里下载的是3.4.20版本。下载好就可以安装默认安装就行。 打开Anaconda Prompt修改成国内镜像 conda c…

大概了解一下G1收集器

在上一篇文章中&#xff08;链接&#xff1a;大概了解一下CMS收集器&#xff09;我们提到&#xff0c;CMS是一种主要针对旧生代对象进行回收的收集器。与CMS不同&#xff0c;G1号称“全功能的垃圾收集器”&#xff0c;对初生代内存和旧生代内存均进行管理。鉴于此&#xff0c;这…

pyspark分布式部署随机森林算法

前言 分布式算法的文章我早就想写了&#xff0c;但是一直比较忙&#xff0c;没有写&#xff0c;最近一个项目又用到了&#xff0c;就记录一下运用Spark部署机器学习分类算法-随机森林的记录过程&#xff0c;写了一个demo。 基于pyspark的随机森林算法预测客户 本次实验采用的…

成功解决ModuleNotFoundError: No module named ‘cv2’

&#x1f525; 成功解决ModuleNotFoundError: No module named ‘cv2’ &#x1f525; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 …

中间件-Nginx漏洞整改(限制IP访问隐藏nginx版本信息)

中间件-Nginx漏洞整改&#xff08;限制IP访问&隐藏nginx版本信息&#xff09; 一、限制IP访问1.1 配置Nginx的ACL1.2 重载Nginx配置1.3 验证结果 二、隐藏nginx版本信息2.1 打开Nginx配置文件2.2 隐藏Nginx版本信息2.3 保存并重新加载Nginx配置2.4 验证结果2.5 验证隐藏版本…

ubuntu20.04安装和使用 Maldet (Linux Malware Detect)

1、下载 Maldet sudo wget http://www.rfxn.com/downloads/maldetect-current.tar.gz 2、解压Maldet sudo tar -xvf maldetect-current.tar.gz 3、进入到Maldet目录&#xff0c;然后运行安装脚本 sudo ./install.sh 4、安装ClamAV sudo apt-get update sudo apt-get in…

Jenkins 中针对视图分组(11)

一、将没有在视图的项目进行归纳操作&#xff1b; 新增的项目规则&#xff0c;并入到某就一个视图中&#xff0c;但常规是设置一个规则&#xff0c;后续按照规则走&#xff0c;就不用单独设置 1、首先到控制台页面&#xff0c;如果没有视图分组就点击加号新增&#xff1b;已存在…

JavaScript异步编程

回调地狱 回调地狱是一种由于过度使用嵌套回调函数而导致的代码结构不清晰、难以理解和维护的问题。一个典型例子是嵌套多个回调函数&#xff0c;每个回调函数都作为另一个回调函数的参数。这样会导致各个部分之间高度耦合、程序结构混乱、流程难以追踪&#xff0c;每个任务只能…

详解顺序结构滑动窗口处理算法

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

性能优化问题思考总结

INP 是什么&#xff1f; Interaction to Next Paint (INP) INP是一项指标&#xff0c;通过观察用户在访问网页期间发生的所有点击、点按和键盘互动的延迟时间&#xff0c;评估网页对用户互动的总体响应情况。 互动是指在同一逻辑用户手势期间触发的一组事件处理脚本。例如&a…

龙蜥OS 尝试

> 尝试一下龙蜥OS&#xff0c;和Centos8应该没什么区别。 阿里云版本龙蜥 https://alinux3.oss-cn-hangzhou.aliyuncs.com/aliyun_3_x64_20G_nocloud_alibase_20230727.vhd Index of /anolis/8.8/isos/GA/x86_64/ (openanolis.cn) 网卡 我在虚拟机上安装完后&#xff0c;…

SpringBoot使用classfinal-maven-plugin插件加密Jar包

jar包加密 1、在启动类的pom.xml中加入classfinal-maven-plugin插件 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><…

算法沉淀——动态规划之子数组、子串系列(上)(leetcode真题剖析)

算法沉淀——动态规划之子数组、子串系列 01.最大子数组和02.环形子数组的最大和03.乘积最大子数组04.乘积为正数的最长子数组长度 01.最大子数组和 题目链接&#xff1a;https://leetcode.cn/problems/maximum-subarray/、 给你一个整数数组 nums &#xff0c;请你找出一个具…

计算机设计大赛 深度学习实现行人重识别 - python opencv yolo Reid

文章目录 0 前言1 课题背景2 效果展示3 行人检测4 行人重识别5 其他工具6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的行人重识别算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…