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?
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 to ILC_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 to ILC_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.
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"
I'm trying to load bitmaps for my buttons with the function SetImage from the CMFCButton. I don't get any error or something, just a plain button. I'm doing the same thing with icons and it works, but I need it to load bitmap too. I need to LoadImage from a path and not from the resources.
Here's my code :
iconResource = path + m_type + _T("U") + extension; //i.e : C:\test\earthU.bmp
HANDLE hIcon = ::LoadImage(nullptr, iconResource, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//same thing for Hot and Disable bitmap
and the call for the SetImage function :
SetImage((HBITMAP)hIcon, 0, (HBITMAP)hIconHot, 0 , (HBITMAP)hIconDis);
Use LR_CREATEDIBSECTION|LR_LOADFROMFILE flag when loading bitmap files for CMFCButton
::LoadImage(nullptr, bitmapfile, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
Partial explanation:
MFC source code for CMFCButton ("afxbutton.cpp") shows it adds LR_CREATEDIBSECTION for LoadImage. This is not documented and it is not clear why it needs that. It seems LR_CREATEDIBSECTION is required when source bitmap is not 32-bit.
I am developing an MFC application, where I need to capture the desktop and save as a vector image.
I can capture screen shot as .BMP and write to clipboard with following code.
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HDC hDesktopDC = GetDC(NULL);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
HGDIOBJ old_obj = SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,
hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hCaptureBitmap);
CloseClipboard();
// clean up
SelectObject(hCaptureDC, old_obj);
DeleteDC(hCaptureDC);
ReleaseDC(NULL, hDesktopDC);
DeleteObject(hCaptureBitmap);
But I am looking something similar code which would allow me to capture screenshot as vector image and place into clipboard; so, I can read as EMF from clipboard.
I tried searching for MFC functions to convert raster images to vector images from clipboard, but I have not found anything useful.
You can't. A screenshot gathers pixel data only. All information on how those pixels were generated (which is essentially what an EMF would store) is lost. It's not possible to recover the GDI calls issued to construct the final image.
Even if that were possible, EMF wouldn't be capable of representing rendering information for image data that is not produced by the GDI (e.g. Qt applications with an OpenGL/Direct2D rasterizer, WPF applications, or UWP applications).
I'm trying to load a .bmp file into a picture control. The bitmap IDB_BITMAP1 was added using the Resource View of Visual Studio. The picture control has id IDC_THUMBNAIL.
The following code doesn't work
HBITMAP hBMP = (HBITMAP)LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1));
[...]
case WM_INITDIALOG:
{
[...]
SendMessage(GetDlgItem(hDlg, IDC_THUMBNAIL), STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBMP);
Any idea? Thanks in advance
Is it possible to load a *.bmp file into a HBITMAP in a Win32 project, using only WINAPI functions?
Yes, it is possible using only the standard win32 library.
HBITMAP hBMP = (HBITMAP) LoadImage( NULL, "Your/ImagePath/a.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
hBMP is a handle to the BITMAP to use as you want.
Note: It is important to pass NULL as the first argument, from the docs:
hinst [in, optional]
To load a stand-alone resource (icon, cursor, or bitmap file)—for
example, c:\myimage.bmp—set this parameter to NULL.
From the msdn documentation for LoadImage.
Yes, you can use the OleLoadPictureFromPath or whatever it was called. Check it. The docs are probably still inconsistent and wrong about supported formats but in modern Windows also JPEG and PNG supported.