0
votes

I have a project in VC++ 6 using bitmaps . I want to extract few bitmaps programatically and save as .bmp file.

please give me some advice to do so.

These are few steps i want to do.

  1. I have a project in VC++ 6 having some bitmaps that were made by me in VC++ bitmap editor.
  2. I will click on a menu in the .exe.
  3. The program will extract all .bmp files from itself (it already has) and will save them on harddisk as .bmp

Thanks in advance regards

ulka

1
Do you want to extract the images from an external executable files resource section? Or from your own resources in the running program?Some programmer dude
There are methods like LoadResource, FindResource from binary. See codeproject.com/Articles/4221/…sameerkn
Please edit your question to show what you have tried so far. You should include a minimal reproducible example of the code that you are having problems with, then we can try to help with the specific problem. You should also read How to Ask.Toby Speight
Do you mind marking my answer as "accepted" if it works for you?zett42
Thank you zett42. The code you have suggested is working perfectly. Thank you for your efforts.ulkaNCST

1 Answers

5
votes

A bitmap resource in the executable is just the bitmap file with the BITMAPFILEHEADER stripped off. See also: https://blogs.msdn.microsoft.com/oldnewthing/20091211-00/?p=15693

So what you need to do is create this header yourself and write it to the file first. It's relatively easy for the most common 24 bpp bitmaps but a little bit more involved if you want to support other bit depths too.

Next write the data obtained via FindResource() / LoadResource() / LockResource() calls.

Code example (tested with 1 bpp, 4 bpp, 8 bpp and 24 bpp bitmaps):

int main()
{
    // Obtain a handle to the current executable
    HMODULE hInst = ::GetModuleHandle( nullptr );

    // Locate and load a bitmap resource of the executable
    if( HRSRC hr = ::FindResource( hInst, MAKEINTRESOURCE( IDB_BITMAP1 ), RT_BITMAP ) )
        if( HGLOBAL hg = ::LoadResource( hInst, hr ) )
            if( auto pData = reinterpret_cast<const char*>( ::LockResource( hg ) ) )
            {
                DWORD resourceSize = ::SizeofResource( hInst, hr );

                // Check if we safely read the complete BITMAPINFOHEADER 
                // (to prevent a GPF in case the resource data is corrupt).
                if( resourceSize >= sizeof( BITMAPINFOHEADER ) )
                {
                    auto& bmih = reinterpret_cast<const BITMAPINFOHEADER&>( *pData );

                    // For simplicitly we can only save uncompressed bitmaps.
                    if( bmih.biCompression == BI_RGB )
                    {
                        // Calculate the size of the bitmap pixels in bytes.
                        // We use this to calculate BITMAPFILEHEADER::bfOffBits correctly.
                        // This is much easier than calculating the size of the color table.   
                        DWORD widthBytes = ( bmih.biBitCount * bmih.biWidth + 31 ) / 32 * 4;
                        DWORD heightAbs = abs( bmih.biHeight );  // height can be negative for a top-down bitmap!
                        DWORD pixelSizeBytes = widthBytes * heightAbs;

                        // Create the bitmap file header.
                        BITMAPFILEHEADER bfh = { 0 };
                        bfh.bfType = 0x4D42;                         // magic bytes: "BM"
                        bfh.bfSize = sizeof( bfh ) + resourceSize;   // total file size
                        bfh.bfOffBits = bfh.bfSize - pixelSizeBytes; // offset to bitmap pixels

                        // Write file header and bitmap resource data to file.
                        std::ofstream of( "mybitmap1.bmp", std::ios::binary );
                        of.write( reinterpret_cast<const char*>( &bfh ), sizeof( bfh ) );
                        of.write( pData, resourceSize );
                    }
                }
            }

    return 0;
}

Edit:

My original answer missed one crucial bit (literally), that is the ios::binary flag for the ofstream constructor. That's why the code didn't work for Arthur G.

So why did it actually work for me even without the flag? Funny thing is that it only worked because my test bitmap didn't have any bytes with the value of 10 (never trust a programmer testing his own code)!

One thing that may happen by default is that line endings will be converted according to the platform default. That is, '\n' (ASCII code = 10) will be converted to "\r\n" on the Windows platform. Of course this will totally mess up the bitmap data as any real bitmap will most likely contain this value somewhere.

So we have to tell ofstream explicitly that our data should not be messed with, which is exactly what the ios::binary flag does.

Edit 2:

Just for fun I extended my example to work correctly for 1-bit, 4-bit and 8-bit per pixel bitmaps too. This is a little bit more involved because for these bit depths the pixel array doesn't start immediately after the BITMAPINFOHEADER. Before the pixel array comes the color table, whose size must be added to BITMAPFILEHEADER::bfOffBits.

According to MSDN, matters are further complicated because even if the bit depth is 16 or greater, there can be an optional color table ("to optimize performance of the system color palettes" - whatever that means)! See https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx (under "biClrUsed")

So instead of wrapping my head around all the dirty details of when and how a color table is used, I simply calculate the BITMAPFILEHEADER::bfOffBits by subtracting the size of the pixel array from the total resource size (which is already known).

Calculating the size of the pixel array is fairly straightforward but you must take care that the width in bytes is rounded up to the next multiple of 4 (one DWORD). Otherwise you will get errors when saving bitmaps whose width in bytes is not a multiple of 4.

Bonus read

Wikipedia has quite an in-depth description of the bitmap file format with a nice diagram of the structure: https://en.wikipedia.org/wiki/BMP_file_format