CMFCButton::SetImage - Bitmaps won't show - c++

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.

Related

Problem with loading a bitmap with the LoadImage() function

I develop an application in C++ on Windows CE 2013.
I want to load a bitmap from file and show it on-screen.
The problem is the LoadImage() function always returns NULL.
HDC hdcOkno;
hdcOkno = GetDC(hWnd);
HBITMAP hbmObraz;
hbmObraz = (HBITMAP)LoadImage(NULL, L"C:\\Users\\tykab\\OneDrive\\Pulpit\\bitmapy\\background_blue.bmp", IMAGE_BITMAP, 0, 0, NULL);
BITMAP bmInfo;
GetObject(hbmObraz, sizeof(bmInfo), &bmInfo);
BitBlt(hdcOkno, 50, 50, bmInfo.bmWidth, bmInfo.bmHeight, hdcOkno, 0, 0, SRCCOPY);
Update:
Since you are working on Windows CE platform, LoadImage() can not load bitmaps from files. You should use SHLoadDIBitmap() instead.
Original Answer:
From the LoadImage documentation:
name
Type: LPCTSTR
...
If the hinst parameter is NULL and the fuLoad parameter omits the LR_LOADFROMFILE value, the lpszName specifies the OEM image to load...
...
If the fuLoad parameter includes the LR_LOADFROMFILE value, lpszName is the name of the file that contains the stand-alone resource (icon, cursor, or bitmap file). Therefore, set hinst to NULL.
You are not specifying the LR_LOADFROMFILE flag in the fuLoad parameter. The last parameter should be set to the following when loading a file:
LR_DEFAULTSIZE | LR_LOADFROMFILE
As mentioned in the comments, it's always a good idea to check GetLastError() on errors.

How can I add a transparent PNG as a toolbar icon?

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"

BitBlit/Copy from D2D1DeviceContext target D2D1Bitmap1 to HDC

For a past few days I was looking for an option to use DirectX 2D in a pattern where I can render to 'something' and then this 'something' - use as input to other drawing.
All of RenderTargets like Hwnd, Dc, Wic bitmap - does not allow to do it (Wic target does not use HW acceleration).
Only one way I found is D2D1DeviceContext
M$ document
There I can create ID2D1Bitmap1 (which also, when created with CPU_READ flag - can be mapped and read) which can be set as target.
So far - so good, all is working fine.
However, at the end, we all want to display the result of drawing onto a user screen and for this purpose - we need to pass it to some WinAPI DC.
I've done it this way.
Create ID2D1Bitmap1 with GDI compatibility
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
Get from ID2D1DeviceContext - ID2D1GdiInteropRenderTarget
_d2d1context->QueryInterface(IID_PPV_ARGS(&_d2d1GDIinterface))
And finally - using this interface, I get DC and use GDI function BitBlt
void paste_bitmap_into_dc(HDC dc, ID2D1Bitmap& bitmap) {
_d2d1context->SetTarget(&bitmap);
_d2d1context->BeginDraw();
HDC new_dc;
_d2d1GDIinterface->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &new_dc);
BitBlt(dc, 0, 0, bitmap.size().x, bitmap.size().y, new_dc, 0, 0, SRCCOPY);
RECT update_rect;
SetRect(&update_rect, 0, 0, 0, 0); // i don't want to actually update bitmap on ID2D1DeviceContext
_d2d1GDIinterface->ReleaseDC(&update_rect);
_d2d1context->EndDraw();
}
That works but I'm not sure that this is a proper (fastest) way, since there is DC created and its coppied twice (hopefuly - on HW side): from target ID2D1Bitmap to this new DC and then from new DC to input DC.
And actually this method is more for drawing with GDI on D2D1 content (ReleaceDC have argument which part of bitmap to update).
Someone could help/confirm this is the way?
Thanks in advance!

Load Bitmap Image into WINApi C++ and Display

I am building a GUI using WINApi C++ Unicode. My ultimate goal is not to load the .bmp image from a file because i will be passing around the GUI as a .exe file.
Is it possible to load the .bmp image into the GUI's resource and load the image from there every time I want to display on my GUI?
Sure. There's a resource type specially for bitmaps. Just use "Add resource" in the Visual Studio resource view. Example code on how to use it should be available in the MSDN.
Put this in the resource (.rc) file
IDI_NORMAL BITMAP "Normal.bmp"
Then this in main colde (.cpp) file
HBITMAP hBMP = (HBITMAP)LoadBitmapW(hInst, MAKEINTRESOURCEW(IDI_NORMAL)); //test bitmap
HDC hMemDC = CreateCompatibleDC(hdc);
::SelectObject(hMemDC, hBMP);
BitBlt(hdc, 0, 0, 1000, 1000, hMemDC, 0, 0, SRCCOPY);
::DeleteDC(hMemDC);
Works perfectly

How to use LoadImage and DeleteObject properly?

I am working on a windows application with C++. I load a bmp file to a DC using LoadImage, and it shows up properly. However, when I call DeleteObject, the memory doesn't seem to be freed. (I use windows task manager to track the memory usage)
In the WM_INITDIALOG part I do this:
static HBITMAP hBitmap = 0;
char* tempPath = "tabView.bmp";
hBitmap = (HBITMAP)LoadImage(NULL,
tempPath, // file containing bitmap
IMAGE_BITMAP, // type = bitmap
0, 0, // original size
LR_LOADFROMFILE); // get image from a file
if(hBitmap)
{
SendMessage(GetDlgItem(hwndDlg, IDC_PICTURE),
STM_SETIMAGE, // message to send
(WPARAM)IMAGE_BITMAP, // bitmap type
(LPARAM)hBitmap); // bitmap handle
}
So the picture shows up in the DC, and memory increases. And in a button I do:
int result = DeleteObject(hBitmap);
When I press the button, I checked the result and it's a non-zero value, which is success. But IDC_PICTURE will still show the picture, and memory stays the same. I am wondering if the SendMessage() may increase the ref count on the hBitmap...
So my question is: What is the proper way to clean up?
You didn't mentioned what version of Windows you are using. Anyway, if you read "Important" part of STM_SETIMAGE, you will see next:
With Windows XP, if the bitmap passed in the STM_SETIMAGE message contains pixels with nonzero alpha, the static control takes a copy of the bitmap. This copied bitmap is returned by the next STM_SETIMAGE message. The client code may independently track the bitmaps passed to the static control, but if it does not check and release the bitmaps returned from STM_SETIMAGE messages, the bitmaps are leaked.
Maybe this applies not only for Windows XP, but for later version of Windows. Hope this will help you.