views:

376

answers:

1

Hello,

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_()
A: 

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.

Lukáš Lalinský
Thanks for the sample, I have been able to take the HIcon returned from ExtractIconEx and convert it to a HBitmap using a simple function. So everything is working now, except the background of the icon is not transparent and the icon is not antialiased :(So far: http://i34.tinypic.com/v33dom.png
Christopher Poole
Replace `fromWinHBITMAP(...)` with `fromWinHBITMAP(..., 2)` (`2` should be `QPixmap.Alpha`, but PyQt doesn't seem to expose that).
Lukáš Lalinský
Excellent its now transparent! What would be the best way to smooth it out a bit? Right now its a huge improvement: http://i36.tinypic.com/11kcj04.png
Christopher Poole
Never mind I had the QRect for the Pixmap drawing set to 36 x 36 and it was stretching the icon, everything is fine now. Thanks alot for the help!
Christopher Poole