Sign in to follow this  
Guest zip

Code: storing alpha images as a resource for GDI+ use

Recommended Posts

I ran into this recently and found very little reference to this problem, but with my luck, everyone probably knows about this already.The problem:in GDI+, you can easily handle images saved in different formats (GIF, TIF, TGA, PNG) with alpha channels for interesting effects. It's very nice to have the images stored in your gauge as resources because you don't have to distribute a ton of files that can get lost along the way, nor write the code that will locate the files on disk after installation.The RC.EXE compiler included in Visual Studio doesn't support images with an alpha channel very well, and some images are not supported at all (PNG, TIF, etc...). Even the 32 bit BMP format has problems and gets mysteriously converted (stored as 24 bit?). This makes the use of these images inside a gauge more difficult than it needs to be. Of course, this is a non-issue in .NET resources, but that doesn't do a whole lot for us in C or C++ for gauges (at least, right now) since we don't use managed code for gauges.My solution:Here's a routine that I wrote to help out to extract any image file (or any file for that matter) stored in binary form in the resource file (.RC)) as a user defined type. The type I selected is called "RAW". This means RC.EXE will not try to interpret the data and store it as is in binary form.Because it's stored in binary form, the RC compiler will not put a BITMAPINFO header in the resource, and you can't use Bitmap::FromResource() to load the bitmap. The routine returns a bitmap stored as a RAW type in the RC file. // loads a bitmap stored in RAW form in the resource// used when the res compiler doesn't support the bitmap format, such as PNG, TIF, etc...// example entry from RC file://// BMP_RES_ID RAW DISCARDABLE "bitmapsimage.png"//// call using : Bitmap* bmp = LoadImageFromRawResource(GetModuleHandle(NULL),BMP_RES_ID);// Bitmap * LoadImageFromRawResource(HINSTANCE hdll, UINT id){ Bitmap *bmp = NULL; // the return bitmap HRSRC hResInfo = FindResourceW(hdll,(LPWSTR)id,L"RAW"); // raw data if (hResInfo) { HGLOBAL hg = LoadResource(hdll, hResInfo); // load the resource DWORD count = SizeofResource(hdll, hResInfo); // number of bytes stored in the DLL LPVOID data = LockResource(hg); // lock the buffer WCHAR *tmp = NULL; if ( tmp = _wtmpnam(NULL)) { FILE *stream = _wfopen(tmp,L"w+b"); fwrite(data,count,sizeof(BYTE),stream); fclose(stream); bmp = Bitmap::FromFile(tmp); // read the data into memory _wremove(tmp); // kill tmp file free(tmp); // free alloc by _wtmpnam(NULL) } } else DISPLAYERROR(); return bmp;}Cheers,

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

Thanks, EtienneVery helpful code!!!Cheers, Christian

Share this post


Link to post
Share on other sites

Hi Etienne,I was waiting for more discussion on your topic but it seems to have run its course.I haven't played around with making gauges for quite some time, so the coding structure is somewhere in the ether for me. I looked at the FS2004_PANELS_SDK and Dai Griffiths examples but didn't understand the following:"Because it's stored in binary form, the RC compiler will notput a BITMAPINFO header in the resource, and you can't useBitmap::FromResource() to load the bitmap."Are you talking about the mygauge.rc file in this instance when you say the above? Secondly, do you actually save the bitmaps as RAW files:"The routine returns a bitmap stored as a RAW type in the RCfile"Call me gauge-LESS!:-lolW. Sieffert

Share this post


Link to post
Share on other sites

Background information on resources that are not covered in Dai's excellent tutorial.The resource compiler (RC.EXE) is used to embed resources, or binary data, into your executable (exe or dll - and thus gau since a gau = dll). As stated above, there are multiple advantages to do this, the drawback being that it can create huge executables because of all this added data that isn't code.You can create resources manually, or you can just add a resource to your Visual Studio solution. Either way, you specify the list of resources in the .RC source file. This file is compiled by the resource compiler and it creates object files from the binary data you specified. The linker then combines all of it into your executable or dynamic link library. A common use is to create "resource only" dlls, which don't have any code but they contain resources.The type of binary information the resource compiler understands and are useful in the FS context are:BITMAP - currently any valid windows bitmap except 32 bit (requires a .bmp extension. Trying to load a bitmap in other formats usually results in a compiler error "RC2170: bitmap file filename is not in 3.00 format".STRING - text strings, used to localize your program (the idea there is to store strings as resources and change the resource based on the country/locale you're in). This way, you write one code and one set of resource IDs, but they map to different things depending on which resource file you use.CURSOR - mouse cursors for exampleSOUND - wave filesWhen the compiler encounters a resource type, it tries to translate the known data types and from that parsing, adds a header that tells the runtime library that process resources (LoadResource, LoadBitmap, etc...) some information about the data. One of the things it does for bitmaps is place a BITMAPINFO structure header in the resource that gives things like image size and palette information.The problem is that the pre dotNET RC compiler can't handle certain types of resources because it doesn't understand how to parse the data (the .NET resource manager can handle many more types). So, if you have images (or any type of data) that RC can't read, and you get an RC2170 data, the only thing you can do resource wise is to save the data as a user defined type (mine is called RAW). You can then use the code above to extract the data into a temporary file and then do what you must with it (in this case, load the data into a GDI+ bitmap object). Once loaded, you can kill the file since it's in memory.In your gauge, you obviously do not want to keep on loading/unloading bitmaps, so I have a routine that goes through all the resources when the gauge is loaded (CONNECT event) and creates the appropriate bitmap objects, and when the gauge closes (DISCONECT event) I free up all the objects.Hope this helps,

Share this post


Link to post
Share on other sites

Hi Etienne,Thanks for the detail. It does help some but as I said I am gauge-less. I would have to study the gauge coding again to see if I completly understand.Just one last question. In the compiled gauges, the bitmaps are part of the gauge file. Is this the case with your method or do your bitmaps reside outside the gauge file and are called when the gauge is called for use?W. Sieffert

Share this post


Link to post
Share on other sites

By definition, if a resource, it is embedded in the executable file (in the case of a gauge, the .gau file).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this