问题
My intention is to create a toolbar in Win32 containing a transparent icon. I have tried the following code to create a simple toolbar with one button having a custom image:
// 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
only supports 24-bit bitmaps, which means there is no alpha channel for transparency. However, I can simulate a transparency effect by using a mask color via ImageList_AddMasked
. (Here, I am setting white (RGB(255, 255, 255)
) to the mask color.)
This worked fine, but the image displayed this way is extremely sharp/jagged because of the lack of granularity in the alpha channel (each pixel is either transparent or fully opaque).
I understand that the PNG format can solve this, since it provides a true alpha channel. I know that the PNG format is supported by Win32 ImageLists, but I don't know how to use it properly. (PNG resources can be added to Visual Studio resources, but I don't know how to use them from code.)
I couldn't find any way to make LoadImage
load a PNG. The only supported types are IMAGE_BITMAP
IMAGE_CURSOR
and IMAGE_ICON
. I changed the resource (ID_IMG_SPAWN
) to a PNG file and tried each of those three types one by one, but all resulted in merely a blank display like this:
Can anyone help me out? How can I use LoadImage
to load a transparent PNG and use it as a toolbar image?
回答1:
ImageList_Create only supports 24-bit bitmaps, which means there is no alpha channel for transparency.
No, that's wrong. ImageList_Create
supports 32-bit bitmaps as well.
Since you intend to create a toolbar in Win32 containing a transparent icon, you do NOT need to load a PNG at all. If you desire PNG you may have to work around with GdiPlus as @barmak says.
32-bit bitmap has 8 bits for ALPHA. Using 32-bit bitmaps can make the same effect as PNG does.
You say your button image was showing blank when you did these:
changed
ILC_COLOR24
toILC_COLOR32
changed the resource of
ID_IMG_SPAWN
to a 32-bit bitmap
IN FACT To show a 32-bit bitmap properly, you have to:
change
ILC_COLOR24
toILC_COLOR32
change the resource of
ID_IMG_SPAWN
to a 32-bit bitmap with premultiplied alpha.create a DIB section to your bitmap when loading
(Win32's format requirement is very strict)
Q: How to create a DIB section to the bitmap?
A: Specify LR_CREATEDIBSECTION
in the last parameter of LoadImage
.
Explanation:
LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)
This is your code of the LoadImage
function. See the MSDN document of LoadImage, to create the DIB section, all you need is to specify LR_CREATEDIBSECTION
in the last parameter of LoadImage
.
Q: How to get a BMP with premultiplied alpha?
A: Pixelformer can help you convert your alpha-channeled file to a premultiplied-alpha BMP.
The steps are
- Open your image (any format) in Pixelformer and choose Export from the menu
- Select A8:R8:G8: B8 (32bpp) and Premultiplied Alpha, then click Ok.
Then you can save your BMP file! Import this BMP file to Visual Studio resources, replacing your previous 24-bit BMP.
Then, you don't need to use the ImageList_AddMasked
(which makes the image sharp) anymore, because you already have a recognizable ALPHA in your 32-bit BMP. So, straight use ImageList_Add
.
Okay, after the manipulations explained above your code should be this:
// 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);
This worked fine as below.
These I answered above is well enough to solve this problem.
For more information about DIB bitmaps and Premultiplied Alpha, see the links.
回答2:
LoadImage
will return NULL
when trying to load PNG resource.
You can add your PNG resource as ICON. Otherwise use Windows Imaging Component, or Gdiplus+ to load the png resource.
Read PNG resource as follows:
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);
}
Resource definition should look like this:
ID_PNG1 RCDATA "file.png"
来源:https://stackoverflow.com/questions/58751417/how-can-i-add-a-transparent-png-as-a-toolbar-icon