Skip navigation
Currently Being Moderated


Nov 23, 2010 11:45 AM



What is the formula that you use to calculate the size of Photoshop bitmap files and the BITMAPFILEHEADER.bfSize member in these files?



I am asking because I am using the formula below and my BITMAPFILEHEADER.bfSize comes out 2 bytes shorter than the bitmap files produced by Photoshop.



BITMAPFILEHEADER.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAP*INFOHEADER) + cbExtraBitFields + cbColorTable + cbGap + BitmapInfoHdr.biSizeImage;




cbExtraBitFields = (BitmapInfoHdr.biSize == sizeof(BITMAP*INFOHEADER)) ? ((BitmapInfoHdr.biCompression == BI_BITFIELDS) ? 3*sizeof(RGBQUAD):0) : 0;


cbGap = BITMAPFILEHEADER.bfOffBits - sizeof(BITMAPFILEHEADER) - sizeof(BITMAP*INFOHEADER) - cbExtraBitFields - cbColorTable;


BitmapInfoHdr.biSizeImage = ( (BitmapInfoHdr.biCompression == BI_RGB) || (BitmapInfoHdr.biCompression == BI_BITFIELDS) ) ? (ROUNDUP32(BitmapInfoHdr.biWidth * BitmapInfoHdr.biBitCount) >> 3) * ((DWORD)(abs(BitmapInfoHdr.biHeight))) : BitmapInfoHdr.biSizeImage ; //For BI_RGB or BI_BITFIELDS round up to the nearest DWORD boundary. Shift by 3 because there are 8 bits in a byte. (2^3=8)



//BITMAP*INFOHEADER means either BITMAPINFOHEADER or BITMAPV3INFOHEADER. The asterisk is used as a wild card (non-C notation!)
// The variable name prefix cb... denotes "Count of Bytes".
BITMAP*INFOHEADER BitmapInfoHdr;  //The Declaration of BitmapInfoHdr. Will not compile because of the wildcard asterisk
#define ROUNDUP32(x) ( ((x) + 0x1F)  & (~(0x1F)) )  //The macro to round up to the next multiple of 32.



The following file is a 32bpp, 32x32px image without an Alpha channel generated by Photoshop:



According to my formula:

BITMAPFILEHEADER.bfSize = sizeof(BITMAPFILEHEADER) +  sizeof(BITMAPINFOHEADER) + cbExtraBitFields + cbColorTable + cbGap +  BitmapInfoHdr.biSizeImage;


BITMAPFILEHEADER.bfSize = 0x0e + 0x28 + 0x00 + 0x00 + 0x00 + 0x1000;  // == 0x1036 bytes



Yet in this file the BitmapInfoHdr.biSizeImage == 0x1002 and consequently BITMAPFILEHEADER.bfSize  == 0x1038 bytes.  Why ?


At 32bpp, the 32x32px image should take 32*32*4=4096 bytes (0x1000).

I don't understand the origin of the number 0x1002 appearing in that file.  It is not even divisible by DWORD (4 bytes) - not that it needs to be a multiple of 4 for file storage purposes.







I noticed that in Photoshop bitmap files the cbGap == 0  (which is OK).

  • Currently Being Moderated
    Nov 23, 2010 12:35 PM   in reply to verpies

    Hmm, looks sort of like this:


    write a header and palette

    save position of the size field

    save position of dataStart field

    write image contents

    if compression is RLE4 or RLE8, write the EOF marker 0x0001

    pad the current position to a multiple of 4 (writing bytes of zero), save that position as EOF

    seek back to beginning of file+2 and write the EOF position DWORD as the total file size

    seek to the size field position and write (EOF - dataStart) as the image size DWORD



    There are also a few notes in the code about observations that most BMP implementations just ignore the size fields.

    Mark as:
  • Currently Being Moderated
    Nov 23, 2010 3:53 PM   in reply to verpies

    Padding the size value and failing to write bytes for that adjusted size could cause problems.

    That's why we pad the position by writing zeros.

    Mark as:
  • Currently Being Moderated
    Nov 24, 2010 12:22 PM   in reply to verpies

    Again, we extend the data to a multiple of 4, and account for that in the size.


    You suggested what I already said we did...

    Mark as:
  • Currently Being Moderated
    Nov 24, 2010 3:16 PM   in reply to verpies

    Worst case, you can play with different size images or image content to see exactly what we're doing.

    And what we're doing has been working well with other apps for about 18 years now.

    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points