实战PyQt5: 121-使用QImage实现一个看图应用
liuian 2025-01-20 14:46 35 浏览
QImage简介
QImage类提供了独立于硬件的图像表示形式,该图像表示形式可以直接访问像素数据,并且可以用作绘制设备。QImage是QPaintDevice子类,因此可以使用QPainter直接在图像上绘制。在QImage上使用QPainter时,可以在当前GUI线程以外的其他线程中执行绘制。
QImage提供了多种方式来读取图像文件,在创建QImage对象时可以加载图像文件,也可以在创建对象之后,使用load()或者loadFrameData()函数来加载图像。加载图像时,文件名可以是磁盘上的实际文件,也可以是嵌入到应用程序的资源。
QImage类支持包括单色,8位,32位和alpha混合图像。QImage提供了一组函数用于获取有关图像的各种信息和实现图像转换。
- 几何尺寸信息: 函数size(), width(), height(), dotsPerMeterX()和dotsPerMeterY()提供了图像的尺寸和纵横比信息。rect()函数返回图像的包围矩形,vaild()函数用于判断一组坐标是否位于这个包围矩形内。
- 色彩信息: 使用pixel()函数可以获得指定像素的颜色,该颜色是一个独立于文件格式的QRgb值。对于单色或者8位图像,colorCount()和colorTable() 函数提供了有关用于存储图数据的颜色分量的信息。hasAlphaChannel()返回函数是否有alpha通道的信息。
- 文本信息: text() 函数返回给定文本关键值的图像文本信息。函数textKeys()返回图像的文本关键值信息。
- 底层信息: depth()函数返回图像的位深度信息。图像支持的深度信息把包括1(单色),8、16、24和32位。bitPlaneCount()返回图像的位平面数。
像素操作
QImage的像素操作功能取决于图像格式而有所不同,原因是单色和8位图像的颜色是基于索引值,使用颜色查找表来获得,而32位图像则直接存储ARGB值。
如果是32位图像,则可以使用setPixel()函数为给定的像素设置一个ARGB颜色值。例如:
image = QImage(3, 3, QImage.Format_RGB32)
value = qRgb(180, 149, 39) # 0xffbd9527
image.setPixel(1, 1, value)
value = qRgb(122, 163, 39) # 0xff7aa327
image.setPixel(0, 1, value)
image.setPixel(1, 0, value)
value = qRgb(237, 187, 51) # 0xffedba31
image.setPixel(2, 1, value)用一个方格表示一个像素,上面代码生成的图像可以用下图来描述:
对于8位和单色图像,像素值为图像颜色表中的索引值,因此setPixel()函数只能用于将给定位置的像素颜色设置为图像颜色表中的预定义的颜色值,即是说,它只能改变像素的索引值。若需要更改颜色或者将颜色添加到图像的颜色表中,可以使用setColor()函数来完成。颜色表中的一项为一个ARGB颜色值,使用qRgb()和qRgba()函数可以为setColor()提供需要的QRgb值。例如:
image = QImage(3, 3, QImage.Format_Indexed8)
value = qRgb(122, 163, 39) # 0xff7aa327
image.setColor(0, value)
value = qRgb(237, 187, 51) # 0xffedba31
image.setColor(1, value)
value = qRgb(180, 149, 39) # 0xffbd9527
image.setColor(2, value)
image.setPixel(0, 1, 0)
image.setPixel(1, 0,0)
image.setPixel(1,1,2)
image.setPixel(2,1,1)用一个方格表示一个像素,上面代码生成的图像可以用下图来描述:
图像格式
QImage中存储的每个像素都由整数表示。整数的大小取决于格式。QImage支持QImage.Format枚举描述的图像格式。Qt提供以下图像格式:
- QImage.Format_Invalid (0): 无效图片。
- QImage.Format_Mono (1): 每像素使用1位存储图像。字节首先用高位(MSB方式打包)。
- QImage.Format_MonoLSB (2): 每像素使用1位存储图像。字节首先用低位(LSB方式打包)。
- QImage.Format_Indexed8 (3): 使用8位索引将图像存储到颜色表中。
- QImage.Format_RGB32 (4): 图像使用32位RGB格式(0xffRRGGBB)存储。
- QImage.Format_ARGB32 (5): 图像使用32位ARGB格式(0xAARRGGBB)存储。
- QImage.Format_ARGB32_Premultiplied (6): 使用预乘的32位ARGB格式(0xAARRGGBB)存储图像,即红色,绿色和蓝色通道乘以除以255的alpha分量。(如果RR,GG或BB的值大于alpha使用预乘ARGB32的某些操作(例如使用alpha混合的图像合成)要比使用普通ARGB32更快。
- QImage.Format_RGB16 (7): 图像以16位RGB格式(5-6-5)存储。
- QImage.Format_ARGB8565_Premultiplied (8): 使用预乘的24位ARGB格式(8-5-6-5)存储图像。
- QImage.Format_RGB666 (9): 图像以24位RGB格式(6-6-6)存储。未使用的最高有效位始终为零。
- QImage.Format_ARGB6666_Premultiplied (10): 使用预乘的24位ARGB格式(6-6-6-6)存储图像。
- QImage.Format_RGB555 (11): 图像以16位RGB格式(5-5-5)存储。未使用的最高有效位始终为零。
- QImage.Format_ARGB8555_Premultiplied (12): 使用预乘的24位ARGB格式(8-5-5-5)存储图像。
- QImage.Format_RGB888 (13): 图像以24位RGB格式(8-8-8)存储。
- QImage.Format_RGB444 (14): 图像以16位RGB格式(4-4-4)存储。未使用的位始终为零。
- QImage.Format_ARGB4444_Premultiplied (15): 使用预乘的16位ARGB格式(4-4-4-4)存储图像。
- QImage.Format_RGBX8888 (16): 图像使用32位字节排序的RGB(x)格式(8-8-8-8)存储。这与Format_RGBA8888相同,除了alpha必须始终为255。(在Qt 5.2中添加)
- QImage.Format_RGBA8888 (17): 图像使用32位字节顺序RGBA格式(8-8-8-8)存储。与ARGB32不同,这是一种字节排序格式,这意味着32位编码在大字节序和小字节序架构之间有所不同,分别为(0xRRGGBBAA)和(0xAABBGGRR)。如果读取为字节0xRR,0xGG,0xBB,0xAA,则颜色顺序在任何体系结构上都是相同的。(在Qt 5.2中添加)。
- QImage.Format_RGBA8888_Premultiplied (18): 使用预乘的32位字节排序RGBA格式(8-8-8-8)存储图像。(在Qt 5.2中添加)。
- QImage.Format_BGR30 (19): 图像使用32位BGR格式(x-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_A2BGR30_Premultiplied (20): 图像使用32位预乘ABGR格式(2-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_RGB30 (21): 图像以32位RGB格式(x-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_A2RGB30_Premultiplied (22): 图像使用32位预乘ARGB格式(2-10-10-10)存储。(在Qt 5.4中添加)。
- QImage.Format_Alpha8 (23): 图像使用仅8位alpha格式存储。(在Qt 5.5中添加)。
- QImage.Format_Grayscale8 (24): 图像使用8位灰度格式存储。(在Qt 5.5中添加)。
- QImage.Format_Grayscale16 (28): 图像使用16位灰度格式存储。(在Qt 5.13中添加)。
- QImage.Format_RGBX64 (25): 使用64位半字排序的RGB(x)格式(16-16-16-16)存储图像。这与Format_RGBA64相同,除了alpha必须始终为65535。(在Qt 5.12中添加)。
- QImage.Format_RGBA64 (26): 图像使用64位半字排序RGBA格式(16-16-16-16)存储。(在Qt 5.12中添加)。
- QImage.Format_RGBA64_Premultiplied (27): 使用预乘的64位半字排序RGBA格式(16-16-16-16)存储图像。(在Qt 5.12中添加)。
- QImage.Format_BGR888 (29): 图像使用24位BGR格式存储。(在Qt 5.14中添加)。
图像变换和图像属性修改
QImage支持许多用于创建新图像的功能:
- createAlphaMask(): 从该图像的alpha缓冲区生成并返回一个1-bpp的蒙版
- mirrored(): 生成一个径向图像
- scaled(): 生成一个缩放图像
- rgbSwapped(): 从RGB图像构造一个BGR图像
- scaledToWidth(): 返回缩放到指定宽度的图像
- caledToHeight(): 返回缩放到指定高度的图像
- transformed():返回使用给定的转换矩阵和转换模式转换的图像
一些用于就地图像属性的函数:
- setDotsPerMeterX(): 设置物理单位的水平像素数来定义纵横比。
- setDotsPerMeterY(): 设置物理单位的垂直像素数来定义纵横比。
- fill(): 用给定的像素值填充整个图像。
- invertPixels(): 使用给定的InvertMode值反转图像中的所有像素值。
- setColorTable(): 设置用于转换颜色索引的颜色表。仅单色和8位格式。
- setColorCount(): 调整颜色表的大小。仅单色和8位格式。
创建一个看图应用
参考pyqt5-examples样例文件imageviewer.py, 实现一个简单的看图程序,完整代码如下:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QDir
from PyQt5.QtGui import QImage, QPainter, QPixmap, QPalette
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction,
QFileDialog, QMessageBox, QLabel, QScrollArea, QSizePolicy)
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
class ImageViewer(QMainWindow):
def __init__(self, parent=None):
super(ImageViewer, self).__init__(parent)
# 设置窗口标题
self.setWindowTitle('实战Qt for Python: QImage实现一个看图应用')
# 设置窗口大小
self.resize(500, 400)
self.initUi()
def initUi(self):
#打印
self.printer = QPrinter()
#缩放因子
self.scaleFactor = 0.0
#创建显示图片的窗口
self.imgLabel = QLabel()
self.imgLabel.setBackgroundRole(QPalette.Base)
self.imgLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.imgLabel.setScaledContents(True)
self.scrollArea = QScrollArea()
self.scrollArea.setBackgroundRole(QPalette.Dark)
self.scrollArea.setWidget(self.imgLabel)
self.setCentralWidget(self.scrollArea)
self.initMenuBar()
def initMenuBar(self):
menuBar = self.menuBar()
menuFile = menuBar.addMenu('文件(&F)')
menuView = menuBar.addMenu('视图(&V)')
actionOpen = QAction('打开(&O)...', self, shortcut='Ctrl+O', triggered=self.onFileOpen)
self.actionPrint = QAction('打印(&P)...', self, shortcut='Ctrl+P', enabled=False, triggered=self.onFilePrint)
actionExit = QAction('退出(&X)', self, shortcut='Ctrl+Q', triggered=QApplication.instance().quit)
self.actionZoomIn = QAction('放大(25%)(&I)', self, shortcut='Ctrl++', enabled=False, triggered=self.onViewZoomIn)
self.actionZoomOut = QAction('缩小(25%)(&O)', self, shortcut='Ctrl++', enabled=False, triggered=self.onViewZoomOut)
self.actionNormalSize = QAction('原始尺寸(&N)', self, shortcut='Ctrl+S', enabled=False, triggered=self.onViewNormalSize)
self.actionFitToWindow = QAction('适应窗口(&F)', self, shortcut='Ctrl+F', enabled=False, checkable=True, triggered=self.onViewFitToWindow)
menuFile.addAction(actionOpen)
menuFile.addAction(self.actionPrint)
menuFile.addSeparator()
menuFile.addAction(actionExit)
menuView.addAction(self.actionZoomIn)
menuView.addAction(self.actionZoomOut)
menuView.addAction(self.actionNormalSize)
menuView.addSeparator()
menuView.addAction(self.actionFitToWindow)
#打开文件
def onFileOpen(self):
filename,_ = QFileDialog.getOpenFileName(self, '打开文件', QDir.currentPath())
if filename:
image = QImage(filename)
if image.isNull():
QMessageBox.information(self, '图像浏览器', '不能加载文件%s.' % filename)
return
self.imgLabel.setPixmap(QPixmap.fromImage(image))
self.scaleFactor = 1.0
self.actionPrint.setEnabled(True)
self.actionFitToWindow.setEnabled(True)
self.updateActions()
if not self.actionFitToWindow.isChecked():
self.imgLabel.adjustSize()
#打印
def onFilePrint(self):
dlg = QPrintDialog(self.printer, self)
if dlg.exec():
painter = QPainter(self.printer)
rect = painter.viewport()
size = self.imgLabel.pixmap().size()
size.scale(rect.size(), Qt.KeepAspectRatio)
painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
painter.setWindow(self.imgLabel.pixmap().rect())
painter.drawPixmap(0, 0, self.imgLabel.pixmap())
#放大图像
def onViewZoomIn(self):
self.scaleIamge(1.25)
def onViewZoomOut(self):
self.scaleIamge(0.8)
def onViewNormalSize(self):
self.imgLabel.adjustSize()
self.scaleFactor = 1.0
def onViewFitToWindow(self):
fitToWindow = self.actionFitToWindow.isChecked()
self.scrollArea.setWidgetResizable(fitToWindow)
if not fitToWindow:
self.onViewNormalSize()
self.updateActions()
def updateActions(self):
checked = not self.actionFitToWindow.isChecked()
self.actionZoomIn.setEnabled(checked)
self.actionZoomOut.setEnabled(checked)
self.actionNormalSize.setEnabled(checked)
def scaleIamge(self, factor):
self.scaleFactor *= factor
self.imgLabel.resize(self.scaleFactor * self.imgLabel.pixmap().size())
self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)
self.actionZoomIn.setEnabled(self.scaleFactor < 4.0)
self.actionZoomOut.setEnabled(self.scaleFactor > 0.25)
def adjustScrollBar(self, scrollBar, factor):
scrollBar.setValue(int(factor * scrollBar.value() + ((factor - 1) * scrollBar.pageStep()/2)))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ImageViewer()
window.show()
sys.exit(app.exec()) 运行结果如下图:
本文知识点
- QImage支持的图像格式
- 使用QImage进行图像变换
- 创建一个简单的图像浏览应用
前一篇: 实战PyQt5:120-像素图QPixmap和QBitmap
请多多关注,评论,收藏,点赞,和转发。
相关推荐
- 搭建一个20人的办公网络(适用于20多人的小型办公网络环境)
-
楼主有5台机上网,则需要一个8口路由器,组网方法如下:设备:1、8口路由器一台,其中8口为LAN(局域网)端口,一个WAN(广域网)端口,价格100--400元2、网线N米,这个你自己会看了:)...
- 笔记本电脑各种参数介绍(笔记本电脑各项参数新手普及知识)
-
1、CPU:这个主要取决于频率和二级缓存,频率越高、二级缓存越大,速度越快,现在的CPU有三级缓存、四级缓存等,都影响相应速度。2、内存:内存的存取速度取决于接口、颗粒数量多少与储存大小,一般来说,内...
- 汉字上面带拼音输入法下载(字上面带拼音的输入法是哪个)
-
使用手机上的拼音输入法打成汉字的方法如下:1.打开手机上的拼音输入法,在输入框中输入汉字的拼音,例如“nihao”。2.根据输入法提示的候选词,选择正确的汉字。例如,如果输入“nihao”,输...
- xpsp3安装版系统下载(windowsxpsp3安装教程)
-
xpsp3纯净版在采用微软封装部署技术的基础上,结合作者的实际工作经验,融合了许多实用的功能。它通过一键分区、一键装系统、自动装驱动、一键设定分辨率,一键填IP,一键Ghost备份(恢复)等一系列...
- 没有备份的手机数据怎么恢复
-
手机没有备份恢复数据方法如下1、使用数据线将手机与电脑连接好,在“我的电脑”中可以看到手机的盘符。 2、将手机开启USB调试模式。在手机设置中找到开发者选项,然后点击“开启USB调试模式”。 3、...
- 电脑怎么激活windows11专业版
-
win11专业版激活方法有多种,以下提供两种常用的激活方式:方法一:使用激活密钥激活。在win11桌面上右键点击“此电脑”,选择“属性”选项。进入属性页面后,点击“更改产品密钥或升级windows”。...
- 华为手机助手下载官网(华为手机助手app下载专区)
-
华为手机助手策略调整,已不支持从应用市场下载手机助手,目前华为手机助手是需要在电脑上下载或更新手机助手到最新版本,https://consumer.huawei.com/cn/support/his...
- 光纤线断了怎么接(宽带光纤线断了怎么接)
-
宽带光纤线断了可以重接,具体操作方法如下:1、光纤连接的时候要根据束管内,同色相连,同芯相连,按顺序进行连接,由大到小。一般有三种连接方法,分别是熔接、活动连接和机械连接。2、连接的时候要开剥光缆,抛...
- win7旗舰版和专业版区别(win7旗舰版跟专业版)
-
1、功能区别:Win7旗舰版比专业版多了三个功能,分别是Bitlocker、BitlockerToGo和多语言界面; 2、用途区别:旗舰版的功能是所有版本中最全最强大的,占用的系统资源,...
- 万能连接钥匙(万能wifi连接钥匙下载)
-
1、首先打开wifi万能钥匙软件,若手机没有开启WLAN,就根据软件提示打开WLAN开关;2、打开WLAN开关后,会显示附近的WiFi,如果知道密码,可点击相应WiFi后点击‘输入密码’连接;3、若不...
- 雨林木风音乐叫什么(雨林木风是啥)
-
雨林木风的创始人是陈年鑫先生。陈年鑫先生于1999年创立了雨林木风公司,其初衷是为满足中国市场对高品质、高性能电脑的需求。在陈年鑫先生的领导下,雨林木风以技术创新、产品质量和客户服务为核心价值,不断推...
- aics6序列号永久序列号(aics6破解序列号)
-
关于AICS6这个版本,虽然是比较久远的版本,但是在功能上也是十分全面和强大的,作为一名平面设计师的话,AICS6的现有的功能已经能够应付几乎所有的设计工作了……到底AICC2019的功能是不是...
- 手机可以装电脑系统吗(手机可以装电脑系统吗怎么装)
-
答题公式1:手机可以通过数据线或无线连接的方式给电脑装系统。手机安装系统需要一定的技巧和软件支持,一般需要通过数据线或无线连接的方式与电脑连接,并下载相应的软件和系统文件进行安装。对于大部分手机用户来...
- 一周热门
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
