Win32 无法添加具有透明度的自定义工具栏图标
Win32 Unable to add custom toolbar icon having transparency
我正在使用此代码向 window 添加工具栏,其中一个按钮具有自定义图像:
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME, NULL,WS_CHILD |
TBSTYLE_FLAT|TBSTYLE_AUTOSIZE |TBSTYLE_LIST|CCS_BOTTOM, 0, 0, 0, 0,
hwnd, NULL, ghInstance, NULL); //create the toolbar
SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold,
static_cast<LPARAM>(MAKELONG(TRUE, 0))); //set the font. there cannot be the problem
//↓↓↓↓↓**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//
auto hImagelist = ImageList_Create(32, 32,ILC_COLOR32|ILC_MASK,1, 0);
//↑↑↑↑↑**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//
HBITMAP bitmap = static_cast<HBITMAP>(ghInstance,
MAKEINTRESOURCE(ID_IMG_SPAWN),// <- ID_IMG_SPAWN is my custom resource
IMAGE_BITMAP, 32, 32, NULL));
ImageList_Add(hImagelist, bitmap, nullptr);
SendMessage(hToolbar, TB_SETIMAGELIST,static_cast<WPARAM>(0),(LPARAM)hImagelist);
上面代码中,ID_IMG_SPAWN
是我导入到Visual Studio的资源bmp图片。但是,Visual Studio 抛出了一个错误,说它无法识别我的 bmp,并且当 运行 应用程序时 bmp 显示为空白。
Visual Studio 告诉我我的 bmp 没有被识别,请看下面的错误:
应用程序运行时如下所示:
我了解到 Visual Studio 特此仅识别 24 位 bmp。
所以,我把bmp转成24bit再导入,把ILC_COLOR32
改成ILC_COLOR24
,果然有效。没有错误,按钮上显示了我的图像。
但是,我丢失了 Alpha 通道。因为 24 位位图不支持 alpha 通道,所以我的图像最终有一个丑陋的方形背景。
如果您使用的是 Visual Studio 2010 或更高版本(我猜),您可以使用 PNG 文件。如所述 here.
尝试这样的事情(注意我使用了 "BINARY"
资源..也许它也适用于其他人但不确定..此代码适用于 32 位位图、alpha 透明 PNG 和 JPEG ):
#include <windows.h>
#include <gdiplus.h>
HBITMAP LoadBitmapFromResource(DWORD ResourceID, bool transparent = true)
{
HANDLE hGlobal = NULL;
ULONG_PTR GDIToken = 0;
Gdiplus::Image* Img = NULL;
Gdiplus::GdiplusStartupInput GDIStartInput = NULL;
Gdiplus::GdiplusStartup(&GDIToken, &GDIStartInput, NULL);
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(ResourceID), "BINARY");
if (!hResource) {return NULL;}
HGLOBAL hFileResource = LoadResource(NULL, hResource);
if (!hFileResource) {return NULL;}
LPVOID lpFile = LockResource(hFileResource);
if (!lpFile) {return NULL;}
DWORD dwSize = SizeofResource(NULL, hResource);
if (!dwSize) {return NULL;}
void* data = LockResource(hFileResource);
if (!data) {return NULL;}
IStream* pStream = NULL;
hGlobal = GlobalAlloc(GMEM_FIXED, dwSize);
memcpy(hGlobal, data, dwSize);
UnlockResource(hFileResource);
FreeResource(hFileResource);
if (CreateStreamOnHGlobal(hGlobal, true, &pStream) == S_OK)
{
Img = new Gdiplus::Image(pStream, false);
pStream->Release();
GlobalFree(hGlobal);
hGlobal = NULL;
HBITMAP hBitmap = NULL;
static_cast<Gdiplus::Bitmap*>(Img)->GetHBITMAP(transparent ? Gdiplus::Color::Transparent : Gdiplus::Color(0, 0, 0), &hBitmap);
delete Img;
Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
GDIStartInput = NULL;
GDIToken = 0;
return hBitmap;
}
GlobalFree(hGlobal);
hGlobal = NULL;
Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
GDIStartInput = NULL;
GDIToken = 0;
return NULL;
}
您将不得不 link 对抗 GDIPlus
。为加载的每个图像不断启动和关闭 GDIPlus 不是很好。所以最好将其移动到某个地方。但除此之外,一切都应该正常。
没有 GDIPlus 也有其他方法,但它会很长 post..
I learned that Visual Studio hereby recognizes ONLY 24bit bmp.
不,那是错误的。 Visual Studio 支持 alpha 预乘 32 位位图。
32位位图有8位ALPHA,可以做出平滑的效果。
要正确显示 32 位位图,您必须:
指定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);
如下所示效果很好。
我上面回答的这些已经可以解决这个问题了。您可能想知道 "What means DIB bitmaps?" "What is Premultiplied Alpha?"。这些都是很深的话题。
要学习 DIB bitmaps and Premultiplied Alpha,请参阅链接。
我正在使用此代码向 window 添加工具栏,其中一个按钮具有自定义图像:
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME, NULL,WS_CHILD |
TBSTYLE_FLAT|TBSTYLE_AUTOSIZE |TBSTYLE_LIST|CCS_BOTTOM, 0, 0, 0, 0,
hwnd, NULL, ghInstance, NULL); //create the toolbar
SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold,
static_cast<LPARAM>(MAKELONG(TRUE, 0))); //set the font. there cannot be the problem
//↓↓↓↓↓**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//
auto hImagelist = ImageList_Create(32, 32,ILC_COLOR32|ILC_MASK,1, 0);
//↑↑↑↑↑**ILC_COLOR32 is specificied here but 32bit bmp is still not showing**//
HBITMAP bitmap = static_cast<HBITMAP>(ghInstance,
MAKEINTRESOURCE(ID_IMG_SPAWN),// <- ID_IMG_SPAWN is my custom resource
IMAGE_BITMAP, 32, 32, NULL));
ImageList_Add(hImagelist, bitmap, nullptr);
SendMessage(hToolbar, TB_SETIMAGELIST,static_cast<WPARAM>(0),(LPARAM)hImagelist);
上面代码中,ID_IMG_SPAWN
是我导入到Visual Studio的资源bmp图片。但是,Visual Studio 抛出了一个错误,说它无法识别我的 bmp,并且当 运行 应用程序时 bmp 显示为空白。
Visual Studio 告诉我我的 bmp 没有被识别,请看下面的错误:
应用程序运行时如下所示:
我了解到 Visual Studio 特此仅识别 24 位 bmp。
所以,我把bmp转成24bit再导入,把ILC_COLOR32
改成ILC_COLOR24
,果然有效。没有错误,按钮上显示了我的图像。
但是,我丢失了 Alpha 通道。因为 24 位位图不支持 alpha 通道,所以我的图像最终有一个丑陋的方形背景。
如果您使用的是 Visual Studio 2010 或更高版本(我猜),您可以使用 PNG 文件。如所述 here.
尝试这样的事情(注意我使用了 "BINARY"
资源..也许它也适用于其他人但不确定..此代码适用于 32 位位图、alpha 透明 PNG 和 JPEG ):
#include <windows.h>
#include <gdiplus.h>
HBITMAP LoadBitmapFromResource(DWORD ResourceID, bool transparent = true)
{
HANDLE hGlobal = NULL;
ULONG_PTR GDIToken = 0;
Gdiplus::Image* Img = NULL;
Gdiplus::GdiplusStartupInput GDIStartInput = NULL;
Gdiplus::GdiplusStartup(&GDIToken, &GDIStartInput, NULL);
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(ResourceID), "BINARY");
if (!hResource) {return NULL;}
HGLOBAL hFileResource = LoadResource(NULL, hResource);
if (!hFileResource) {return NULL;}
LPVOID lpFile = LockResource(hFileResource);
if (!lpFile) {return NULL;}
DWORD dwSize = SizeofResource(NULL, hResource);
if (!dwSize) {return NULL;}
void* data = LockResource(hFileResource);
if (!data) {return NULL;}
IStream* pStream = NULL;
hGlobal = GlobalAlloc(GMEM_FIXED, dwSize);
memcpy(hGlobal, data, dwSize);
UnlockResource(hFileResource);
FreeResource(hFileResource);
if (CreateStreamOnHGlobal(hGlobal, true, &pStream) == S_OK)
{
Img = new Gdiplus::Image(pStream, false);
pStream->Release();
GlobalFree(hGlobal);
hGlobal = NULL;
HBITMAP hBitmap = NULL;
static_cast<Gdiplus::Bitmap*>(Img)->GetHBITMAP(transparent ? Gdiplus::Color::Transparent : Gdiplus::Color(0, 0, 0), &hBitmap);
delete Img;
Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
GDIStartInput = NULL;
GDIToken = 0;
return hBitmap;
}
GlobalFree(hGlobal);
hGlobal = NULL;
Gdiplus::GdiplusShutdown(GdiImage::GDIToken);
GDIStartInput = NULL;
GDIToken = 0;
return NULL;
}
您将不得不 link 对抗 GDIPlus
。为加载的每个图像不断启动和关闭 GDIPlus 不是很好。所以最好将其移动到某个地方。但除此之外,一切都应该正常。
没有 GDIPlus 也有其他方法,但它会很长 post..
I learned that Visual Studio hereby recognizes ONLY 24bit bmp.
不,那是错误的。 Visual Studio 支持 alpha 预乘 32 位位图。
32位位图有8位ALPHA,可以做出平滑的效果。
要正确显示 32 位位图,您必须:
指定
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);
如下所示效果很好。
我上面回答的这些已经可以解决这个问题了。您可能想知道 "What means DIB bitmaps?" "What is Premultiplied Alpha?"。这些都是很深的话题。
要学习 DIB bitmaps and Premultiplied Alpha,请参阅链接。