Error Reading File BMP File Size ?

I’m doing some image processing (with OpenGL) on a 465Kb Windows bitmap file, and it appears that the file size in the header section of the file is incorrect - or I do not know how to interprete it.

Like I said the file is 465Kb in size (according to windows explorer) but when I query the header like thus:

(BITMAPFILEHEADER File_header


File_header.bfSize

I get 7! Which is a far cry from 465!

Or is it that File_header is the size of the header section? cos that is what it seem like:


typedef struct {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;

My Observation: The size of BITMAPFILEHEADER is 7 Double words!


Alrighty then. What am I doing wrong …

http://www.wotsit.org/search.asp -> BMP

OpenGL != BMP loading API

You’re reading the header wrong I think. The first member of the structure, bfType, is an unsigned int, not an unsigned short. This means you’re only reading two bytes before the size, when it should actually be four.

Originally posted by Bob:
The first member of the structure, bfType, is an unsigned int, not an unsigned short.

Er…Hi Bob

I just checked. The first member of the BITMAPFILEHEADER structure (i.e. bfType) should be 2 bytes large. On my machine short ints and unsigned shorts fulfill this condition.

However, to ensure that negative numbers(?!) are not written to bfType, I belive unsigned shorts are prefered.

(NOTE: bfType can be ‘BM’, ‘BA’, ‘CI’, ‘CP’, ‘IC’ or ‘PT’)

As you see size is not all that matters :wink:

Guess I was wrong then.

Anyways, now when you mention it, in my bitmap loader, I check the type and see if it’s ‘BM’ or not. That must mean the type is two bytes.

Although this is largely off-topic, I thought I’d try to help: it is very common in the Windows API structures that one of the member is actually the size of the structure.

It is indeed the case for BITMAPINFOHEADER, which description can be found on the MS web site.

But it is not the case for the BITMAPFILEHEADER which is the one you are referring to !!! According to MS doc, the bfSize member “specifies the size, in bytes, of the bitmap file”.

I suppose the program you use to create your BMPs did not know that…

Regards.

Eric

To get the size of your image, read in the BITMAPINFOHEADER directly after the BITMAPFILEHEADER and look at the biSizeImage member of the BITMAPINFOHEADER struct. This will contain the size of the bitmap data (minus the header stuff).

You can read in these two structures, then move the file pointer to BITMAPFILEHEADER.bfOffBits and read BITMAPINFOHEADER.biSizeImage bytes, which will be the actual image.

In the case where biSizeImage is zero (happens with some paint programs) you have to manually calculate the size of the image, based on its width, height, and colordepth.

It is also possible that you’re running into an alignment problem. If the program that wrote out the bitmap file did something like:
fwrite(&bfh , sizeof(BITMAPFILEHEADER), 1, fp)
then there may be a couple of extra bytes between the bfType member and the bfSize since MS likes to align struct members on 4 byte boundaries. It is also possible that the reverse problem is true. i.e. the BITMAPFILE header was written out a member at a time, but you’re trying to read the whole thing in at once. i.e.
fread(&bfh,sizeof(BITMAPFILEHEADER),1,fp)
Anyway, I believe the correct way to read and write the BMP structures is to do it a member at a time to avoid alignment problems.

The only place you are likely to run into alignment problems is in the actual image data. For example, say you have a 24bpp image that has a width of 257. Each line in the image would take 771 bytes, which would get padded an additional byte to make it align on a 4byte boundary (772/4 = 193 4byte chunks).

If you were to do something like flip this bitmap line by line, you would have to make sure you account for the padding bytes on the end of each line or else (in this case) the information in the blue channel would get “pushed” into the green channel (since they are right next to each other in memory).

This also has to be taken into account if you manually calculate the image size instead of using BITMAPINFOHEADER.biSizeImage.

All of this alignment stuff only really applies to 1, 4, 8, 16, 24 bit BMP’s. 32bpp images are 4bytes per pixel so they are automatically aligned.

jup, it’s an alignment problem, you read th bytes 4 till 7 instead of 2 till 5
the bytes are:
xx xx 07 00 00 00
the first 4 are the size (the 07 00 result from the about 465k file size) the trailing 00 00 is the reserved (always 00)

Originally posted by dslater:
Anyway, I believe the correct way to read and write the BMP structures is to do it a member at a time to avoid alignment problems.

Didn’t know that so thanks a lot for this post: that’s spot on and that will avoid headaches if I ever have such a problem !

Regards.

Eric

Originally posted by dslater:
I believe the correct way to read and write the BMP structures is to do it a member at a time to avoid alignment problems.

dslater, … you’re a “G”! I just tried this. It worked like magic!!!

ThanX


Comment
(For Geeks and Bitmap Phreaks)

Ever wondered why an unsigned short (bfType) is tested against ‘MB’ (which looks like a string)? …

Well, I did too; for a while, till I disovered that since:

‘M’ = 0100 1101
‘B’ = 0100 0010

‘BM’ is a concatenatation of ‘M’ and ‘B’ (as shown below):

‘BM’ = 0100 1101 0100 0010 = 19778 = 0x4D42

(Dont tell me these numbers dont look familair …)

Originally posted by Olumide:
[b]Comment
(For Geeks and Bitmap Phreaks)

Ever wondered why an unsigned short (bfType) is tested against ‘MB’ (which looks like a string)? …

Well, I did too; for a while, till I disovered that since:

‘M’ = 0100 1101
‘B’ = 0100 0010

‘BM’ is a concatenatation of ‘M’ and ‘B’ (as shown below):

‘BM’ = 0100 1101 0100 0010 = 19778 = 0x4D42

(Dont tell me these numbers dont look familair …)[/b]

in fact it is not a string (“MB”), it’s a a 2 byte charachter literal (‘MB’)

but this is NOT portable! e.g. try it with MinGW and it will fail, because MinGW compiles this the other way round, so you have to test against ‘BM’
always test against the hex-number (and write a nice comment to explain g)
i learned that the hard way when i changed from borland compiler (what a f*** stupid optimizer) to MinGW and wondered why my image class failed loading a simple BMP…

Hi Tron

I see your point. But mind you my statement about ‘MB’ was that it “…looks like a string” - I never said it was! (Surely a string cannot be compared to an integral type variable ?!?)

I say, these “character literal” thingies; arent they also called “multibyte characters” ?