开发者

Best way to extract .ico from .exe and paint with PyQt?

I am looking for a way to extract an icon from a .exe file using Python. I know that you can use win32gui's ExtractIconEx function to grab the icon of a .exe but this returns a HIcon resource handle which is no good because I want to paint the icon using PyQt.

Also the only example I have seen using win32gui does not have any transparency and the icons do not look smooth.

What would be the best way to go about doing this using Python & PyQt?

--Edit--

Thanks to help from Lukáš Lalinský this problem is now solved, here is the final code is anyone is seeking to do something similar to me:

import sys
import win32ui
import win32gui
from PyQt4 import开发者_高级运维 QtCore
from PyQt4 import QtGui

class testWindow(QtGui.QMainWindow):
    def __init__(self):
        super(testWindow, self).__init__()
        self.setGeometry(180.0, 130.0, 280.0, 400.0)
        self.setMouseTracking(True)

        large, small = win32gui.ExtractIconEx('C:\\Users\\Blank\\Apps\\Web Browsers\\Firefox\\Firefox.exe', 0)
        win32gui.DestroyIcon(small[0])

        self.pixmap = QtGui.QPixmap.fromWinHBITMAP(self.bitmapFromHIcon(large[0]), 2)
    def bitmapFromHIcon(self, hIcon):
        hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
        hbmp = win32ui.CreateBitmap()
        hbmp.CreateCompatibleBitmap(hdc, 32, 32)
        hdc = hdc.CreateCompatibleDC()
        hdc.SelectObject(hbmp)
        hdc.DrawIcon((0, 0), hIcon)
        hdc.DeleteDC()
        return hbmp.GetHandle()
    def paintEvent(self, event):
        painter = QtGui.QPainter()
        painter.begin(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(QtCore.Qt.NoPen)
        painter.setBrush(QtGui.QBrush(QtGui.QColor(255.0, 255.0, 255.0, 255.0), QtCore.Qt.SolidPattern))
        painter.drawRect(QtCore.QRect(0.0, 0.0, 280.0, 400.0))
        painter.drawPixmap(QtCore.QRect(0.0, 0.0, 32.0, 32.0), self.pixmap)
        painter.end()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    mainWindow = testWindow()
    mainWindow.show()
    app.exec_()


There is a method to create QPixmap from a HBITMAP, so the only problem is how to convert HICON to HBITMAP. This can be done using GetIconInfo.

icons = win32gui.ExtractIconEx('C:/Program Files/Internet Explorer/iexplore.exe', 0, 10)
info = win32gui.GetIconInfo(icons[0][0])
pixmap = QtGui.QPixmap.fromWinHBITMAP(info[4])
info[3].close()
info[4].close()
# call win32gui.DestroyIcon on all the icons returned by ExtractIconEx

EDIT: This code will not help with antialiasing and alpha channel. Your new code is almost correct, but you need to tell Qt to load the alpha channel. If you replace:

self.pixmap = QtGui.QPixmap.fromWinHBITMAP(self.bitmapFromHIcon(large[0]))

with:

self.pixmap = QtGui.QPixmap.fromWinHBITMAP(self.bitmapFromHIcon(large[0]), 2)

it will do the right thing. The "magic" number 2 should be technically QtGui.QPixmap.Alpha but for some reason Qt doesn't provide the constant.


If you don't have access to fromWinHBITMAP (such as in PySide6) then it is possible to create the icon using win32gui.DrawIconEx.

import win32ui
import win32gui
from PySide6 import QtGui, QtCore, QtWidgets

# Get the icons
icons = win32gui.ExtractIconEx('C:/Program Files/Internet Explorer/iexplore.exe', 0)
icon = icons[0][0]
width = height = 32

# Create DC and bitmap and make them compatible.
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, width, height)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)

# Draw the icon.
win32gui.DrawIconEx(hdc.GetHandleOutput(), 0, 0, icon, width, height, 0, None, 0x0003)

# Get the icon's bits and convert to a QtGui.QImage.
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.
# This step is only necessary if you are displaying the image.
# QtWidgets.QLabel and similar have trouble displaying the current format.
buffer = QtCore.QBuffer()
buffer.SetOpenMode(QtCore.QIODevice.ReadWrite)
image.save(buffer, "PNG")
image.loadFromData(buffer.data(), "PNG")
    
# Create a QtGui.QPixmap from the QtGui.QImage.
pixmap = QtGui.Pixmap.fromImage(image)

# Destroy the icons.
for iconList in icons:
    for icon in iconList:
        win32gui.DestroyIcon(icon)

# Display the image.
display_label = QtWidgets.QLabel()
display_label.setPixmap(pixmap)
display_label.show()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜