简体   繁体   中英

HICON/HBITMAP to QIcon/QPixmap/QImage/Anything with a Q in it

I'm trying to get 48x48 or 256x256 icons from files in Windows and have come across what seems like a dead-end. At the moment I have a HICON handle(since PySides QFileIconProvider only returns 32x32 icons) in python which I would like to show in a pyside window but functions like QPixmap.fromHICON/HBITMAP are not implemented and also seems to have been removed from the source since Qt 4.8(?). Also, I'm trying to avoid having to save the icon to a file.

So, is there any way to get a HICON or possibly any other things you can turn it into, to any kind of PySide object?

EDIT: I've been trying to simply rewrite the old function fromWinHBITMAP function in python but it isn't going great. I'm uncertain how I should translate the src line into python and I don't either have any idea how I change the value of the memory buffer returned by 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;
            }
        }

At the moment I create a PyCBITMAP from the HICON with the win32api and retrieves the list of bits.

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))

This results in "ValueError: cannot modify size of memoryview object"

The source for the function be found here: http://www.qtcentre.org/threads/19188-Converting-from-HBitmap-to-a-QPixmap?p=94747#post94747

Fixed it!

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

It's a bit hard to get this sort of setup going but from I read around Python Imaging Library (PIL) supports bitmap and ICO files and has downloads for Windows . Assuming you can get a filename of the icon, you can load it up with PIL and then transfer the raw data to a 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_()

Then work with whatever QImage operation you need to do from there.

While @egs0's answer is accurate, trying to display the output may cause problems because QLabel doesn't handle bitmap very well. To solve these problems, convert the result to another image format.

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

It's also possible to get the size of an icon using the following function, adapted from here :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM