Save Bitmap-Resource


Introduction:

This function saves a bitmap resource to disk as a bmp-file. As arguments you have to specify the name of the file to save the resource to and the handle of the resource you want to save. You get the handle of the resource using the FindResource function.

Note that this function does not implement error handling for the sake of simplicity.

The Code:

void CreateBMFileFromResource(const char* file, HRSRC hres)
{
   // get pointer to bitmap resource
   HGLOBAL hresbm = LoadResource(GetModuleHandle(0), hres);
   LPVOID lpresbm = LockResource(hresbm);

   // use BITMAPINFO structure to read info about resource
   BITMAPINFO *bmInfo = (BITMAPINFO *) lpresbm;

   // calculate the size (in bytes) of the palette and the pixel data
   int sizeclrtbl=0;
   switch (bmInfo->bmiHeader.biBitCount) {
      case 1: sizeclrtbl=2*4; break;
      case 4: sizeclrtbl=16*4; break;
      case 8: sizeclrtbl=256*4; break;
   }

   int bpl = (bmInfo->bmiHeader.biWidth * bmInfo->bmiHeader.biBitCount) / 8;
   int rest=4-(bpl % 4);
   if (rest==4) rest=0;
   int BytesPerLine = bpl + rest;
   int sizepxldata = BytesPerLine * bmInfo->bmiHeader.biHeight;

   // fill the BITMAPFILEHEADER for the file
   BITMAPFILEHEADER bmFileHeader;
   bmFileHeader.bfType = 19778;
   bmFileHeader.bfSize = 14 + 40 + sizeclrtbl + sizepxldata;
   bmFileHeader.bfReserved1 = 0;
   bmFileHeader.bfReserved2 = 0;
   bmFileHeader.bfOffBits = 54;

   // write BITMAPFILEHEADER and bitmap data to file
   int bmfile = open(file, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE);
   write(bmfile, &bmFileHeader, 14);
   write(bmfile, lpresbm, 40 + sizeclrtbl + sizepxldata);

   // clean up
   close(bmfile);
   HGLOBAL dummy = GlobalFree(hresbm);
}

Explanation:

The function LoadResource loads the given resource into global memory. The function call GetModuleHandle(0) returns the handle of the current module, which is needed as the first parameter in the LoadResource call. The return value of LoadResource is the handle of a global memory object. The next thing to do is to get a pointer to the resource (in the global memory) using the LockResource function. The LPVOID value in lpresbm points to the location in the global memory at which the bitmap resource starts.
In the next line of code, the value in lpresbm is used to initialize a BITMAPINFO structure. This works because a bitmap resource in the global memory consists of the following elements: a BITMAPINFO structure (including the palette, if there is one) and the pixel data itself.
The next thing to do is to find out how many bytes the colortable uses. This is done using the biBitCount member of the BITMAPINFOHEADER-structure which itself is a member of the BITMAPINFO-structure (see the bmp-format). Every entry in a colortable uses four bytes. The number of entries in a colortable is 2 in 1-Bit images, 16 in 4-Bit images and 256 in 8-Bit images. So the absolute size of the colortable in bytes is the number of entries multiplied with 4. In 24-Bit (truecolor) images there is no colortable so sizeclrtbl will contain the value zero.
The next part of the function calculates the size of the pixel data. This is rather complicated because different values of biBitCount, as well as the rule that the number of bytes in a line must be a multiple of four must be taken into consideration (see the bmp-format). The variable bpl is the number of bytes per line without taking into consideration the rule mentioned above. For example: for a 4-bit bitmap with a width of 42 pixel bpl would contain a value of (42 * 4) / 8 = 21 bytes. The variable rest contains the number of bytes needed to add to bpl to reach the next 4-byte boundary. For the example above, rest would contain a value of 4 - (21 % 4) = 3. That means that 3 bytes must be added to a line of 21 bytes to reach the next 4-byte boundary (24 bytes). The byte number of the next 4-byte boundary is stored in BytesPerLine. The absolute size of the pixel data is calculated by simply multiplying BytesPerLine with the number of Lines (biHeight).
In the next section a BITMAPFILEHEADER-structure, which is the first structure in a bitmap file, is prepared and filled with the appropriate values.
Then the file specified as parameter is opened. The first write command writes the BITMAPFILEHEADER-structure to the file. The second write command uses the pointer to the resource (in the global memory) to write the whole resource (the BITMAPINFO-structure (with colortable, if a colortable is used) and the pixeldata) to the file. This simple way of saving a bitmap resource to a file by just using a pointer to the resource is only possible because of the internal format of bitmap resources, as described above.
In the 'clean up' section of the function the file is closed and the memory which was allocated for the bitmap resource by LoadResource is set free.

Back to the main page



Copyright 1998 Stefan Hetzl. If you have questions or comments or have discovered an error, send mail to [email protected]. You may forward this document or publish it on your webpage as long as you don't change it and leave this notice at the end.