实战PyQt5: 121-使用QImage实现一个看图应用
haoteby 2025-01-10 13:47 1 浏览
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
请多多关注,评论,收藏,点赞,和转发。
相关推荐
- 用户界面干货盘点
-
为了解决大家找资源难的问题,EVGET特别开辟每周盘点用户界面干货的专栏,一网打尽热门的界面资讯、Demo示例、版本升级及下载、移动Web开发,以及各种UI神器推荐。更多资源及工具也可以在用户界面专题...
- 不仅仅是创意,26款科技小玩意
-
新科技不断在卖场出现,总是吸引着消费者的眼球。许多很棒的科技小玩意儿被发明,手机、平板、手提电脑、游戏主机、甚至是3D打印都适用。现在的初创公司已经发正在让21世纪打破各种科技壁垒障碍。本文收集26...
- FastReport.Net报表设计器如何连接到SQLCe
-
MicrosoftSQLServerCompactEdition是一个简单的本地关系数据库,不需要安装,并且已与数据库文件建立连接。您不需要管理员权限即可使用基础功能。您也只能“密码”基础功能...
- 2015年最值得关注的8款用户界面新品
-
软件界面开发解决方案这一块一直以来是慧都控件(EVGET)的强项,我们有400多款用户界面产品,250多款图表报表产品,此外还提供专业的软件界面定制开发服务,其中DevExpress定制开发、甘特图定...
- 小贴士:安装TBarCode office的注意事项和相关资源
-
TBarCodeoffice是一款适用于MicrosoftWord2007、2010等版本,具有强大功能的条码插件。在这里我们介绍一下安装TBarCodeoffice的注意事项和相关资源。安装...
- 初学者不容错过的修复Bug小技巧
-
Bug的发生,我想这是每个开发人员几乎每天都要面对的问题,包括历史上非常有名的编程人员,他们依旧要面对Bug。成为一个熟练的程序员并不意味着永远不会犯错误,而是擅于发现错误并能很好地修正错误。当你刚开...
- 【推荐】一款基于 .NET 开源的支持多厂区、多项目级的MOM/MES系统
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍tmom是一款基于.NET开源、通用的生产制造系统,支持多厂区/多项目级的MOM/MES系统,计划排程...
- 你不可不知的10个Github功能
-
Github让全世界的开发人员、设计人员可以在一起工作交流。Github不仅提供大量开源项目、编程语言代码,他也发布过Windows和OSX桌面应用,可以让我们在工作中无缝集成Github。...
- Fastreport.Net用户手册(十四):文本编辑
-
编辑对象的文本,只需双击文本内容,然后会弹出一个文本编辑器。在编辑器右方有一个可以添加至文本中的数据树组件。可以通过鼠标拖拽该组件到需要的地方。在文本中嵌入该组件的另一个方法是双击该组件,然后该组件将...
- 火狐浏览器开发者专版上手体验
-
当Mozilla宣布FirefoxDeveloperEdition,我想不少开发者都很高兴,因为第一个大型开发者专用浏览器诞生了。既然是开发者专用版,那么和普通版本肯定是不一样的。早已经迫不及待...
- FastReport.Net 2015.3.3 优化了报表解析器
-
FastReport.Net2015.3.3于近日正式发布。点击FastReport.Net2015.3.3下载试用FastReport.Net最新版本。[Core][Exports]重写保存在...
- 改变上网体验:10个超赞的Google Chrome扩展
-
你使用谷歌浏览器浏览网页吗?其实,全世界数以百万的用户都喜欢使用GoogleChrome浏览网页,这也促使其成为全球使用量第二大的Web浏览器。GoogleChrome浏览器具有快速、干净的页面,...
- 如何在 FastReport Online Designer 中处理报表的 5 个函数
-
FastReports产品的时代并没有停滞不前。每个月都会添加新的函数和对象,并改进和优化当前的代码。FastReportOnlineDesigner...
- Winform应用界面开发技术特点图解
-
整理一下自己之前的Winform开发要点,以图文的方式展示一些关键性的技术特点,总结一下。...
- 跨平台的可视化Web报表设计器-FastReport Online Designer
-
好消息!FastReportOnlineDesigner现在作为一个独立的应用程序发布啦!此前作为FastReport.Net的专业版的一部分的在线设计测试版,现在可以单独或作为FastRepor...