首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何添加透明的PNG作为工具栏图标?

如何添加透明的PNG作为工具栏图标?
EN

Stack Overflow用户
提问于 2019-11-07 14:57:11
回答 2查看 2.2K关注 0票数 4

我的目的是在Win32中创建一个包含透明图标的工具栏。我尝试了以下代码来创建一个具有自定义图像的按钮的简单工具栏:

代码语言:javascript
运行
复制
// Create the toolbar
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME,
                             NULL,
                             WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | CCS_BOTTOM,
                             0, 0, 0, 0,
                             hwnd,
                             NULL,
                             ghInstance, // <-this is the HINSTANCE of the application
                             NULL);

// Set the font (this cannot be the problem)
SendMessage(hToolbar,
            WM_SETFONT,
            (WPARAM)hFontBold,
            static_cast<LPARAM>(MAKELONG(TRUE, 0)));

auto hImagelist = ImageList_Create(32, 32,ILC_COLOR24 | ILC_MASK, 1, 0);

HBITMAP bitmap = static_cast<HBITMAP>(LoadImage(ghInstance,
    /* ID_IMG_SPAWN is my custom resource -> */ MAKEINTRESOURCE(ID_IMG_SPAWN), 
                                                IMAGE_BITMAP,
                                                32, 32,
                                                NULL));
ImageList_AddMasked(hImagelist,
                    bitmap,
                    RGB(255,255,255) /* white is the transparent color */);
SendMessage(hToolbar,
            TB_SETIMAGELIST,
            static_cast<WPARAM>(0),
            (LPARAM)hImagelist);

ImageList_Create只支持24位位图,这意味着没有透明的alpha通道.但是,我可以通过ImageList_AddMasked使用掩膜颜色来模拟透明效果。(在这里,我将白色(RGB(255, 255, 255))设置为掩膜颜色。)

这很好,但是这样显示的图像非常锐利/锯齿状,因为alpha通道中缺少粒度(每个像素都是透明的或完全不透明的)。

我知道PNG格式可以解决这个问题,因为它提供了一个真正的alpha通道。我知道Win32 ImageLists支持PNG格式,但我不知道如何正确使用它。(可以将PNG资源添加到Visual资源中,但我不知道如何从代码中使用它们。)

我找不到让LoadImage加载PNG的任何方法。唯一受支持的类型是IMAGE_BITMAPIMAGE_CURSORIMAGE_ICON。我将资源(ID_IMG_SPAWN)更改为PNG文件,并逐一尝试了这三种类型中的每一种类型,但都只产生了这样的空白显示:

有人能帮我吗?如何使用LoadImage加载透明的PNG并将其用作工具栏映像?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-11-09 02:05:47

ImageList_Create只支持24位位图,这意味着没有透明的alpha通道.

不,那是不对的。ImageList_Create 支持32位位图以及

因为您打算在Win32中创建一个包含透明图标的工具栏,所以根本不需要加载一个PNG。如果你想要PNG,你可能需要和GdiPlus合作,就像barmak说的那样。

32位位图有8位的阿尔法.使用32位位图可以产生与PNG相同的效果.

当你这样做的时候,你说你的按钮图像是空白的:

  • ILC_COLOR24改为ILC_COLOR32
  • ID_IMG_SPAWN的资源更改为32位位图

实际上,要正确显示32位位图,您必须:

  • ILC_COLOR24更改为ILC_COLOR32
  • ID_IMG_SPAWN的资源更改为32位位图,并使用预乘的α.
  • 在加载时向位图创建DIB部分

(Win32 32的格式要求非常严格)

问:如何创建位图的DIB部分?

A:在LR_CREATEDIBSECTION的最后一个参数中指定LoadImage

解释:

LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)

这是LoadImage函数的代码。请参阅LoadImage的MSDN文档,要创建DIB部分,只需在LoadImage的最后一个参数中指定LR_CREATEDIBSECTION

问:如何获得具有预乘α的BMP?

答:皮克塞尔器可以帮助你把你的α通道文件转换成一个前置的-α- BMP.

步骤如下

  1. 在Pixelformer中打开图像(任何格式),然后从菜单中选择导出

  1. 选择A8:R8:G8: B8 (32 B8)和Pre相乘Alpha,然后单击Ok。

然后你可以保存你的BMP文件!将此BMP文件导入Visual资源,替换以前的24位BMP。

然后,您不再需要使用ImageList_AddMasked (它使图像清晰),因为您已经在您的32位BMP中有一个可识别的ALPHA。所以,直接使用ImageList_Add

好的,在上面解释的操作之后,您的代码应该如下:

代码语言:javascript
运行
复制
// Create the toolbar
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME,NULL,
     WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | CCS_BOTTOM,
     0, 0, 0, 0, hwnd, NULL, ghInstance, NULL);

// Set the font (this cannot be the problem)
SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold,
     static_cast<LPARAM>(MAKELONG(TRUE, 0)));

auto hImagelist =
ImageList_Create(32, 32,ILC_COLOR32 /*DON'T NEED THE MASK. CHANGED TO ILC_COLOR32.*/, 1, 0);

HBITMAP bitmap = static_cast<HBITMAP>(LoadImage((HINSTANCE)GetWindowLong(hwnd,
      GWL_HINSTANCE), MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,
      32, 32, LR_CREATEDIBSECTION  /*THIS IS IMPORTANT*/   ));

ImageList_Add(hImagelist, bitmap, NULL);
SendMessage(hToolbar, TB_SETIMAGELIST, static_cast<WPARAM>(0), (LPARAM)hImagelist);

这件事做得不错,如下所示。

我上面回答的这些问题足以解决这个问题。

有关DIB位图预乘α的详细信息,请参阅链接。

票数 2
EN

Stack Overflow用户

发布于 2019-11-07 17:34:27

当试图加载PNG资源时,LoadImage将返回NULL

您可以添加您的PNG资源作为图标。否则,使用或Gdiplus+加载png资源。

请阅读PNG资源如下:

代码语言:javascript
运行
复制
HBITMAP loadimage(HINSTANCE hinst, const wchar_t* name)
{
    HBITMAP hbitmap = NULL;
    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput tmp;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);
    if(auto hres = FindResource(hinst, name, RT_RCDATA))
        if(auto size = SizeofResource(hinst, hres))
            if(auto data = LockResource(LoadResource(hinst, hres)))
                if(auto stream = SHCreateMemStream((BYTE*)data, size))
                {
                    Gdiplus::Bitmap bmp(stream);
                    stream->Release();
                    bmp.GetHBITMAP(Gdiplus::Color::Transparent, &hbitmap);
                }
    Gdiplus::GdiplusShutdown(token);
    return hbitmap;
}

...
auto hbitmap = loadimage(ghinst, MAKEINTRESOURCE(ID_PNG1 ));
if(hbitmap)
{
    ImageList_AddMasked(himage, hbitmap, 0);
    DeleteObject(hbitmap);
}

资源定义应该如下所示:

代码语言:javascript
运行
复制
ID_PNG1 RCDATA "file.png"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58751417

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档