0

Possible Duplicate:
How to read a binary file in c? (video, images, or text)

I am trying to read the contents of a bmp file using a C program. I am able to read the contents but the values read are on contradiction to what I expected. My code is :


FILE *fp=NULL;
fp=fopen("C:\\Users\\Saurabh\\Pictures\\nice.bmp","r");

if(fp!=NULL)
{
    printf("%c\n",fgetc(fp));
    printf("%c\n",fgetc(fp));

    printf("%c\n",fgetc(fp));
    printf("%c\n",fgetc(fp));
    printf("%c\n",fgetc(fp));
    printf("%c\n",fgetc(fp));
}

else
    printf("Error reading the file");

I am just reading byte by byte here, just for the sake of understanding. The first two bytes read BM which is correct. The next four byte reads *t. The value expected is 40. Please see the format. Can someone please explain waht is happening and how can I get the value 40 if I need to perform some conversions.

Community
  • 1
  • 1
OneMoreError
  • 7,518
  • 20
  • 73
  • 112
  • And what are you getting...? I'd half expect `BM(***` or something similar, if your expected value is correct. – cHao Sep 25 '12 at 16:08
  • Bytes 3 to 6 give the file size, "All of the integer values are stored in little-endian format (i.e. least-significant byte first)." Can you print out the values of bytes 3-6 as numbers and check whether that matches the file size? – Daniel Fischer Sep 25 '12 at 16:36
  • Now from here, how do I get the file size. How do I marge the four bytes to get a single integral value ? – OneMoreError Sep 25 '12 at 16:43

2 Answers2

2

I believe your problem is how you opened the file:

fp=fopen("C:\\Users\\Saurabh\\Pictures\\nice.bmp","r"); 

The "r" is for ASCII reading, you want to open it in binary:

fp=fopen("C:\\Users\\Saurabh\\Pictures\\nice.bmp","rb"); 

EDIT: fgetc() returns an int, so I tried using an int to get the return value, also you want to see the results in hex, so let's use a hex output format:

FILE *readf;
int i;
unsigned int size = 0;

//Open file
readf = fopen("blackbuck.bmp", "rb");

i = fgetc(readf);
printf("%#x\n",i);   // 0x42
i = fgetc(readf);
printf("%#x\n",i);   // 0x4D
for(i=0; i<3; i++)
    size |= fgetc(readf) << (i*8); // 0xC0036

This update gives the first two values as 0x42 0x4D, then concatinates the next 3 bytes giving the size of the bitmap (0xC0036 = 786486 bytes)

I used this image for the test: http://people.sc.fsu.edu/~jburkardt/data/bmp/blackbuck.bmp

You can see the result has the correct byte code for a bmp header 0x42 0x4d the header field used to identify the BMP & DIB file is 0x42 0x4D in hexadecimal, same as BM in ASCII

Mike
  • 47,263
  • 29
  • 113
  • 177
  • This typically only matters if there's a char typically found in line endings (`\n`, `\r`) in the input. I wouldn't expect it to mangle input this early. – cHao Sep 25 '12 at 16:02
  • Even with "rb", i get the same output.. – OneMoreError Sep 25 '12 at 16:05
  • @CSSS - Give the code/pic combo I just posted a try and let me know if it's still not working for you. – Mike Sep 25 '12 at 16:18
  • @Mike: I tried your code and it prints well in hexadecimal. But how do i print it in decimal ? – OneMoreError Sep 25 '12 at 16:53
  • @CSSS - Just change the format specifier `printf("%d\n",i);`. I just figured since the page you're looking at for format is reporting values in hex, that would be easier on you. – Mike Sep 25 '12 at 16:58
  • @Mike: I get 42 116 7 0 in bytes 3 to 6. Can you please explain as to how to get one integer value from these four bytes !! – OneMoreError Sep 25 '12 at 17:07
  • @CSSS - I updated the code to show you how. It's read the bytes from the stream and bitwise OR (|) them together, after each read you have to shift by a multiple of 8 (<<) – Mike Sep 25 '12 at 18:29
1

While i agree with Mike that you should be reading this file in binary mode, it shouldn't be causing you problems just yet. It will, eventually, but the first 6 chars should not break unless any byte of the size contains a 10 or 13.

In order to read an int, you could do something like

int result;
fread(fp, sizeof (int), 1, &result);

but be aware that this is not portable. (It assumes 32-bit ints and native byte order, at the least. BMPs, due to their origin, are little-endian...and the size would be all wacky if you just read it in all at once on a big-endian machine.)

Another way:

unsigned long result = 0;
for (int i = 0; i < 4; ++i) {
     result |= (unsigned long) fgetc(fp) << (i * 8);
}

This should at least always read the right number of bytes and account for endianness. And unsigned long is long enough to hold any 32-bit number, whereas int (even unsigned) is not guaranteed to be.

cHao
  • 84,970
  • 20
  • 145
  • 172