Selecting icon image for icon resource Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Kerry
Experienced Solver
Experienced Solver
Posts: 58
Joined: Fri Mar 07, 2008 5:44 pm

Selecting icon image for icon resource

Post by Kerry »

Hello all,

Is there a way to specify which image to use when loading a wxBITMAP_TYPE_ICO_RESOURCE? There is a constructor for wxImage that takes a file name, image type and index, but the index parameter only seems to work when loading icons from file - for resources this parameter has no effect.

For example:

Code: Select all

wxInitAllImageHandlers();
wxImage img1(_T("ICON_ID_TEST"), wxBITMAP_TYPE_ICO_RESOURCE, 0);
int w = img1.GetWidth();// returns 32

wxImage img2(_T("ICON_ID_TEST"), wxBITMAP_TYPE_ICO_RESOURCE, 1);
w = img2.GetWidth();// returns 32

wxImage img3(_T("path/to/file.ico"), wxBITMAP_TYPE_ICO, 0);// same file that's used for the embedded resource
w = img3.GetWidth();// returns 48

wxImage img4(_T("path/to/file.ico"), wxBITMAP_TYPE_ICO, 1);// same file that's used for the embedded resource
w = img4.GetWidth();// returns 32
Thanks,

Kerry
Kerry
Experienced Solver
Experienced Solver
Posts: 58
Joined: Fri Mar 07, 2008 5:44 pm

Re: Selecting icon image for icon resource

Post by Kerry »

It turns out this can be achieved by using wxIcon instead of wxImage. Instead of specifying the index of the desired image, the constructor takes arguments for width and height and properly chooses the image that best fits the specified dimensions.

-Kerry
feng
Earned a small fee
Earned a small fee
Posts: 14
Joined: Sat Jun 24, 2017 8:36 am

Re: Selecting icon image for icon resource

Post by feng »

The approach is not always satisfying and primarily depends on your ico-files.
In my case, I started off with the attached ico-file containing three images with 16x16, 24x24 and 32x32 sizes.

These are the images of the ico-file placed next to each other:
stop.png
stop.png (328 Bytes) Viewed 3712 times
And that's how it's rendered, when trying to get the 32x32 image:
rendered result
rendered result
stop-result.png (282 Bytes) Viewed 3712 times
The top image is loaded from file system by index.

Code: Select all

wxImage img;
img.LoadFile("icons\\stop.ico", wxBITMAP_TYPE_ICO, 2);
The bottom image is loaded from resource by wxIcon constructor.

Code: Select all

wxIcon icon = wxIcon(L"ICON_STOP", wxBITMAP_TYPE_ICO_RESOURCE, 32, 32);
What happens?
I created the ico-file with Gimp and exported it with different bits per pixel (at this point I wasn't aware of the trouble it makes):
16x16 => 32bpp, 8-Bit Alpha, no palette
24x24 => 32bpp, 8-Bit Alpha, no palette
32x32 => 4bpp, 1-Bit Alpha, 16 slot palette.

The ico-file then contains the images in the following order:
24x24 - 32bit
16x16 - 32bit
32x32 - 4bit

At some point under the hood of the wxIcon constructor the function LoadIcon of Winapi is called, which selects the best fitting image, which turns out to be the 24x24 32bit image and not the one with fitting size. And then it gets rescaled to 32x32. In total it leads to a bad result.


There are three options to get desired results.
1. Do not embed ico files and provide them with your application on release.
2. Do not mix up the bits per pixel of your icons and stick with Kerry's solution.
3. If you can't change your icons anymore and have the problem, I struggled with, you can use following approach, which allows to load embedded icons from resource by index:

I copied the code from https://wiki.wxwidgets.org/Embedding_PN ... ource_file and adjusted it a little bit.

At the end it looks like this:

The resource entry in your_app.rc:

Code: Select all

ICON_STOP				RCDATA		"icons\\stop.ico"

The modified code from the above mentioned wiki:

Code: Select all

bool LoadDataFromResource(char*& t_data, DWORD& t_dataSize, const wxString& t_name)
{
	bool     r_result = false;
	HGLOBAL  a_resHandle = 0;
	HRSRC    a_resource;

	a_resource = FindResource(0, t_name.wchar_str(), RT_RCDATA);

	if (0 != a_resource) {
		a_resHandle = LoadResource(NULL, a_resource);
		if (0 != a_resHandle) {
			t_data = (char*)LockResource(a_resHandle);
			t_dataSize = SizeofResource(NULL, a_resource);
			r_result = true;
		}
	}

	return r_result;
}

wxImage* GetImageFromMemory(const char* t_data, const DWORD t_size, int index = -1)
{
	wxMemoryInputStream a_is(t_data, t_size); // requires #include <wx/mstream.h>
	return new wxImage(a_is, wxBITMAP_TYPE_ICO, index);
}

wxImage* CreateImageFromIcoResource(const wxString& t_name, int index = -1)
{
	wxImage*   r_bitmapPtr = 0;

	char*       a_data = 0;
	DWORD       a_dataSize = 0;

	if (LoadDataFromResource(a_data, a_dataSize, t_name)) {
		r_bitmapPtr = GetImageFromMemory(a_data, a_dataSize, index);
	}

	return r_bitmapPtr;
}
Usage:

Code: Select all

wxImage* iconStop = CreateImageFromIcoResource(L"ICON_STOP", 2);
toolbar->AddTool(ID_TOOLBAR_BTN_STOP, wxEmptyString, *iconStop, _(L"Stop"));
delete iconStop;
The code just loads the ico resource as RC_DATA instead of RC_ICON and allows to use the ico data in an input stream. And this allows using wxImage as if it was loading up a file from the file system, as you see in the wxImage instantiation with wxBITMAP_TYPE_ICO instead of wxBITMAP_TYPE_ICO_RESOURCE.

For now, I will export my icons with consistent bits per pixel and use Kerry's solution, which seems the appropriate way. Wish, I had figured it out earlier.
Attachments
stop.zip
direct ico upload is not allowed, therefore zipped
(386 Bytes) Downloaded 119 times
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: Selecting icon image for icon resource

Post by PB »

BTW, there is wxIconBundle that deals with loading icons with different sizes from a file or a Windows resource:
http://docs.wxwidgets.org/trunk/classwx ... undle.html

The support for loading the bundle from MS Windows group icon resource has been added relatively recently, the code posted here can be used in older versions:
viewtopic.php?f=23&t=43475&p=177370#p177370
Post Reply