如何添加透明的 PNG 作为工具栏图标?
How can I add a transparent PNG as a toolbar icon?
我的目的是在 Win32 中创建一个包含透明图标的工具栏。我已尝试使用以下代码创建一个简单的工具栏,其中包含一个带有自定义图像的按钮:
// 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)
)设置为蒙版颜色。)
这很好用,但是以这种方式显示的图像非常sharp/jagged,因为 alpha 通道缺乏粒度(每个像素要么是透明的,要么是完全透明的)不透明)。
我知道 PNG 格式可以解决这个问题,因为它提供了真正的 alpha 通道。我知道 Win32 ImageLists 支持 PNG 格式,但我不知道如何正确使用它。 (PNG资源可以添加到Visual Studio资源中,但我不知道如何从代码中使用它们。)
我找不到任何方法让 LoadImage
加载 PNG。唯一支持的类型是 IMAGE_BITMAP
IMAGE_CURSOR
和 IMAGE_ICON
。我将资源 (ID_IMG_SPAWN
) 更改为 PNG 文件,并逐一尝试了这三种类型,但所有结果都只是像这样的空白显示:
谁能帮帮我?如何使用 LoadImage
加载透明 PNG 并将其用作工具栏图像?
LoadImage
将在尝试加载 PNG 资源时 return NULL
。
您可以将 PNG 资源添加为 ICON。否则使用 Windows Imaging Component 或 Gdiplus+ 加载 png 资源。
读取PNG资源如下:
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);
}
资源定义应如下所示:
ID_PNG1 RCDATA "file.png"
ImageList_Create only supports 24-bit bitmaps, which means there is no alpha channel for transparency.
不,那是错误的。 ImageList_Create
也支持 32 位位图。
由于您打算在 Win32 中创建一个包含透明图标的工具栏,因此根本不需要加载 PNG。如果你想要 PNG,你可能需要像@barmak 所说的那样使用 GdiPlus。
32 位位图有 8 位用于 ALPHA。使用 32 位位图可以产生与 PNG 相同的效果。
您说您执行这些操作时按钮图像显示为空白:
已将 ILC_COLOR24
更改为 ILC_COLOR32
将 ID_IMG_SPAWN
的资源更改为 32 位位图
事实上要正确显示 32 位位图,您必须:
将ILC_COLOR24
更改为ILC_COLOR32
将 ID_IMG_SPAWN
的资源更改为具有预乘 alpha 的 32 位位图 。
加载时为位图创建一个 DIB 部分
(Win32的格式要求很严格)
问:如何为位图创建 DIB 部分?
A:在LoadImage
的最后一个参数中指定LR_CREATEDIBSECTION
。
解释:
LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)
这是您的 LoadImage
函数的代码。参见MSDN document of LoadImage,要创建DIB部分,你只需要在LoadImage
的最后一个参数中指定LR_CREATEDIBSECTION
。
问:如何得到预乘alpha的BMP?
答:Pixelformer 可以帮助您将 alpha 通道文件转换为预乘 alpha BMP。
步骤是
- 在 Pixelformer 中打开您的图像(任何格式)并从菜单中选择“导出”
- Select A8:R8:G8:B8(32bpp)和预乘Alpha,然后点击确定。
然后你就可以保存你的BMP文件了!将此 BMP 文件导入 Visual Studio 资源,替换您之前的 24 位 BMP。
那么,您就不需要再使用ImageList_AddMasked
(它使图像更清晰),因为您的32 位BMP 中已经有了可识别的ALPHA。所以,直接使用 ImageList_Add
.
好的,在上面解释的操作之后你的代码应该是这样的:
// 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 bitmaps and Premultiplied Alpha 的详细信息,请参阅链接。
我的目的是在 Win32 中创建一个包含透明图标的工具栏。我已尝试使用以下代码创建一个简单的工具栏,其中包含一个带有自定义图像的按钮:
// 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)
)设置为蒙版颜色。)
这很好用,但是以这种方式显示的图像非常sharp/jagged,因为 alpha 通道缺乏粒度(每个像素要么是透明的,要么是完全透明的)不透明)。
我知道 PNG 格式可以解决这个问题,因为它提供了真正的 alpha 通道。我知道 Win32 ImageLists 支持 PNG 格式,但我不知道如何正确使用它。 (PNG资源可以添加到Visual Studio资源中,但我不知道如何从代码中使用它们。)
我找不到任何方法让 LoadImage
加载 PNG。唯一支持的类型是 IMAGE_BITMAP
IMAGE_CURSOR
和 IMAGE_ICON
。我将资源 (ID_IMG_SPAWN
) 更改为 PNG 文件,并逐一尝试了这三种类型,但所有结果都只是像这样的空白显示:
谁能帮帮我?如何使用 LoadImage
加载透明 PNG 并将其用作工具栏图像?
LoadImage
将在尝试加载 PNG 资源时 return NULL
。
您可以将 PNG 资源添加为 ICON。否则使用 Windows Imaging Component 或 Gdiplus+ 加载 png 资源。
读取PNG资源如下:
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);
}
资源定义应如下所示:
ID_PNG1 RCDATA "file.png"
ImageList_Create only supports 24-bit bitmaps, which means there is no alpha channel for transparency.
不,那是错误的。 ImageList_Create
也支持 32 位位图。
由于您打算在 Win32 中创建一个包含透明图标的工具栏,因此根本不需要加载 PNG。如果你想要 PNG,你可能需要像@barmak 所说的那样使用 GdiPlus。
32 位位图有 8 位用于 ALPHA。使用 32 位位图可以产生与 PNG 相同的效果。
您说您执行这些操作时按钮图像显示为空白:
已将
ILC_COLOR24
更改为ILC_COLOR32
将
ID_IMG_SPAWN
的资源更改为 32 位位图
事实上要正确显示 32 位位图,您必须:
将
ILC_COLOR24
更改为ILC_COLOR32
将
ID_IMG_SPAWN
的资源更改为具有预乘 alpha 的 32 位位图 。加载时为位图创建一个 DIB 部分
(Win32的格式要求很严格)
问:如何为位图创建 DIB 部分?
A:在LoadImage
的最后一个参数中指定LR_CREATEDIBSECTION
。
解释:
LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)
这是您的 LoadImage
函数的代码。参见MSDN document of LoadImage,要创建DIB部分,你只需要在LoadImage
的最后一个参数中指定LR_CREATEDIBSECTION
。
问:如何得到预乘alpha的BMP?
答:Pixelformer 可以帮助您将 alpha 通道文件转换为预乘 alpha BMP。
步骤是
- 在 Pixelformer 中打开您的图像(任何格式)并从菜单中选择“导出”
- Select A8:R8:G8:B8(32bpp)和预乘Alpha,然后点击确定。
然后你就可以保存你的BMP文件了!将此 BMP 文件导入 Visual Studio 资源,替换您之前的 24 位 BMP。
那么,您就不需要再使用ImageList_AddMasked
(它使图像更清晰),因为您的32 位BMP 中已经有了可识别的ALPHA。所以,直接使用 ImageList_Add
.
好的,在上面解释的操作之后你的代码应该是这样的:
// 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 bitmaps and Premultiplied Alpha 的详细信息,请参阅链接。