HICON/HBITMAP 转换为 QIcon/QPixmap/QImage/任何带 Q 的内容
我想从Windows的文件中获取48x48或256x256的图标,但现在遇到了瓶颈。目前我在Python中有一个HICON句柄(因为PySide的QFileIconProvider只返回32x32的图标),我想在PySide窗口中显示这个图标,但像QPixmap.fromHICON/HBITMAP这样的函数没有实现,而且似乎从Qt 4.8开始就被移除了。此外,我还想避免将图标保存到文件中。
那么,有没有办法把HICON或者其他可以转换的东西变成PySide的对象呢?
编辑:我试着在Python中重新编写旧的fromWinHBITMAP函数,但进展不太顺利。我不确定该如何把源代码中的那一行翻译成Python,而且我也不知道如何更改QImage.scanLine()返回的内存缓冲区的值。
for (int y=0; y<h; ++y) {
QRgb *dest = (QRgb *) image.scanLine(y);
const QRgb *src = (const QRgb *) (data + y * bytes_per_line);
for (int x=0; x<w; ++x) {
dest[x] = src[x] | mask;
}
}
目前我使用win32api从HICON创建了一个PyCBITMAP,并获取了位图列表。
for y in range(0, hIcon.height):
dest = i.scanLine(y)
src = bitmapbits[y*hIcon.widthBytes:(y*hIcon.widthBytes)+hIcon.widthBytes]
for x in range(0, hIcon.width):
dest[x] = bytes(ctypes.c_uint32(src[x] | 0))
这导致了“ValueError: cannot modify size of memoryview object”的错误。
这个函数的源代码可以在这里找到:http://www.qtcentre.org/threads/19188-Converting-from-HBitmap-to-a-QPixmap?p=94747#post94747
3 个回答
虽然@egs0的回答是正确的,但如果你尝试显示输出,可能会遇到问题,因为QLabel
对位图的处理不是很好。为了解决这些问题,可以把结果转换成其他的图片格式。
import win32ui
import win32gui
# Doesn't matter which library. Qt5 should work just as well.
from PySide6 import QtGui, QtCore
def iconToQImage(hIcon, width, height, im_format="PNG"):
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, width, height)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
win32gui.DrawIconEx(hdc.GetHandleOutput(), 0, 0, hIcon, width, height, 0, None, 0x0003)
bitmapbits = hbmp.GetBitmapBits(True)
image = QtGui.QImage(bitmapbits, width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
# Write to and then load from a buffer to convert to PNG.
buffer = QtCore.QBuffer()
buffer.setOpenMode(QtCore.QIODevice.ReadWrite)
image.save(buffer, im_format)
image.loadFromData(buffer.data(), im_format)
# Use QtGui.Pixmap.fromImage() to get a pixmap instead.
return image
你也可以使用以下函数来获取图标的大小,这个函数是从这里改编而来的:
def getIconSize(HIcon):
info = win32gui.GetIconInfo(HIcon)
if info[4]: # Icon has color plane.
bmp = win32gui.GetObject(info[4])
width = bmp.bmWidth
height = bmp.bmHeight
else: # Icon has no colour plane, image data stored in mask.
bmp = win32gui.GetObject(info[3])
width = bmp.width
height = bmp.height // 2 # A monochrome icon contains image and XOR mask in the hbmMask.
info[3].close()
info[4].close()
return width, height
要搞定这种设置有点难,不过我查了一下,Python Imaging Library(PIL)支持位图和ICO文件,而且有Windows的下载。假设你能拿到图标的文件名,你可以用PIL把它加载进来,然后把原始数据转移到QImage:
from PIL import Image
from PySide.QtGui import QImage, QImageReader, QLabel, QPixmap, QApplication
im = Image.open("my_image.png")
data = im.tostring('raw', 'RGBA')
app = QApplication([])
image = QImage(data, im.size[0], im.size[1], QImage.Format_ARGB32)
pix = QPixmap.fromImage(image)
lbl = QLabel()
lbl.setPixmap(pix)
lbl.show()
app.exec_()
接下来,你就可以根据需要对这个QImage
进行各种操作了。
解决了这个问题!
def iconToQImage(hIcon):
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, hIcon.width, hIcon.height)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
win32gui.DrawIconEx(hdc.GetHandleOutput(), 0, 0, hIcon.hIcon, hIcon.width, hIcon.height, 0, None, 0x0003)
bitmapbits = hbmp.GetBitmapBits(True)
image = QtGui.QImage(bitmapbits, hIcon.width, hIcon.height, QtGui.QImage.Format_ARGB32_Premultiplied)
return image