【问题标题】:Shell_NotifyIcon from RGB data来自 RGB 数据的 Shell_NotifyIcon
【发布时间】:2013-10-29 16:58:16
【问题描述】:

我在内存中有一个图标(RGB 或我想要的任何格式,通过 PIL/Pillow),我想将它用于

win32gui.Shell_NotifyIcon

这需要HICON。 如何将我的 RGB 像素放入 HICON?

或者,即使这很浪费,我什至不介意通过临时文件进行往返并使用 win32gui.LoadImage 重新加载它,如下所示:

from PIL import Image
#create example image with empty pixels:
img = Image.frombuffer("RGB", (32, 32), "\0"*32*32*3, "raw", "RGB", 0, 1)
img = img.convert("P")
img = img.resize((64, 64), Image.ANTIALIAS)
img.save("C:\\temp.ico", format="bmp")
import win32gui, win32api, win32con
flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
win32gui.LoadImage(None, "C:\\temp.ico", win32con.IMAGE_ICON, 0, 0, flags)

但这失败了:pywintypes.error: (0, 'LoadImage', 'No error message available')

我只是找不到可以写入的图片格式,然后LoadImageIMAGE_ICON 模式下可以正确读取和使用它。似乎LoadImage 仅支持该模式下的ICO 文件:我可以将PNGBMP 数据读回为IMAGE_BITMAP,但生成的句柄不能被Shell_NotifyIcon 使用。 有没有办法将IMAGE 转换为HICON? (在记忆中)

【问题讨论】:

  • 我认为传递给LoadImage的第三个参数应该是win32con.IMAGE_BITMAP
  • 如果你阅读了整篇文章,你会看到在使用IMAGE_BITMAP时“结果句柄不能被Shell_NotifyIcon使用”。
  • 很抱歉。我读到一些内容说“我不知道这是否适用于所有情况,但在 WinXP 上,.ico 可以是大小为 16x16、32x32 或 64x64 的 bmp。只需将扩展名从 bmp 更改为 ico,您就可以走吧。”
  • 如果将 .bmp 扩展名重命名为 .ico 技巧不起作用,我认为你不走运。因为 PIL 只支持读取 .ico 文件。这是一种简单的格式,因此您可以使用标题为 ICO (file format) 的 Wikipedia 文章中的信息编写自己的转换器。
  • @martineau 我已将示例代码更新为使用以“.ICO”扩展名保存的 64x64 图像,但仍然失败并显示“No error message available”。如果我必须自己编写代码(对于这样一个微不足道的事情!?),那么我宁愿编写避免使用临时文件并直接在内存中创建 HICON 的代码。

标签: python pywin32 system-tray trayicon loadimage


【解决方案1】:

我不知道我是怎么错过的,但是有一个名为 CreateIcon 的函数将像素数据作为输入,虽然 pywin32 的 win32gui 缺少这个函数,但有一个 CreateIconIndirect 代替,它一样好。

这样代码就变得简单了(仍然使用临时文件):

img = win32gui.LoadImage(None, "C:\\tmp.bmp", win32con.IMAGE_BITMAP, 0, 0, flags)
pyiconinfo = (True, 0, 0, img, img)
hicon = win32gui.CreateIconIndirect(pyiconinfo)

为了在不使用临时文件的情况下将 PIL 图像中的 RGB 像素转换为位图,我使用了这段代码(是的,这样做很慢,但它相对简单易读,并且在这种情况下,我真的不在乎性能):

def img_to_bitmap(image, pixel_value):
    hdc = win32gui.CreateCompatibleDC(0)
    dc = win32gui.GetDC(0)
    hbm = win32gui.CreateCompatibleBitmap(dc, size, size)
    hbm_save = win32gui.SelectObject(hdc, hbm)
    for x in range(size):
        for y in range(size):
            pixel = image.getpixel((x, y))
            v = pixel_value(pixel)
            win32gui.SetPixelV(hdc, x, y, v)
    win32gui.SelectObject(hdc, hbm_save)
    win32gui.ReleaseDC(self.hwnd, hdc)
    win32gui.ReleaseDC(self.hwnd, dc)
    return hbm

对于那些关心性能的人,更好的解决方案可能涉及CreateDIBitmapSetDIBits

现在可以在this tray icon wrapper classset_icon_from_data方法中找到更完整的代码,它处理将alpha通道拆分为自己的位图,这样我们也可以正确显示透明图像。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多