从.exe中提取.ico并用PyQt绘制的最佳方法是什么?
我想用Python从一个.exe文件中提取图标。我知道可以使用win32gui的ExtractIconEx函数来获取.exe文件的图标,但这个函数返回的是一个HIcon资源句柄,这对我来说没用,因为我想用PyQt来绘制这个图标。
而且,我看到的唯一一个使用win32gui的例子没有透明效果,图标看起来也不够光滑。
那么,使用Python和PyQt来实现这个目标的最佳方法是什么呢?
--编辑--
多亏了Lukáš Lalinský的帮助,这个问题现在解决了。如果有人想做类似的事情,这里是最终的代码:
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_()
2 个回答
0
如果你无法使用 fromWinHBITMAP
(比如在 PySide6 中),那么你可以通过 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()
1
有一种方法可以从 HBITMAP
创建 QPixmap
,所以唯一的问题就是如何把 HICON
转换成 HBITMAP
。这个可以通过使用 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
编辑: 这段代码对抗锯齿和透明通道没有帮助。你新的代码几乎是正确的,但你需要告诉 Qt 去加载透明通道。如果你把:
self.pixmap = QtGui.QPixmap.fromWinHBITMAP(self.bitmapFromHIcon(large[0]))
替换成:
self.pixmap = QtGui.QPixmap.fromWinHBITMAP(self.bitmapFromHIcon(large[0]), 2)
这样就能正确处理了。这个“魔法”数字 2
在技术上应该是 QtGui.QPixmap.Alpha
,但出于某种原因,Qt 没有提供这个常量。