1

I am trying to find file size, file header size width, and height of a bmp file. I have studied the format of bmp file and the arrangement of bytes in file. When I try this code it shows wrong width and height for different files. I have tried this for three images so far. This one image results the right measurement.

Woman

This one did not:

enter image description here

I don't understand where I went wrong, but the bit depth showed the right value for all three images.

Here is my code:

#include<iostream>
#include<fstream>
#include<math.h>

using namespace std;


int main() {
    ifstream inputfile("bmp.bmp",ios::binary);
    char c; int imageheader[1024]; 

    double filesize=0; int width=0; int height=0;int bitCount = 0;

    for(int i=0; i<1024; i++) {
        inputfile.get(c); imageheader[i]=int(c);
    }

    filesize=filesize+(imageheader[2])*pow(2,0)+(imageheader[3])*pow(2,8)+(imageheader[4])*pow(2,16)+(imageheader[5])*pow(2,24);

    cout<<endl<<endl<<"File Size:  "<<(filesize/1024)<<" Kilo Bytes"<<endl;

    width=width+(imageheader[18])*pow(2,0)+(imageheader[19])*pow(2,8)+(imageheader[20])*pow(2,16)+(imageheader[21])*pow(2,24);

    cout<<endl<<"Width: "<<endl<<(width)<<endl;

    height=height+(imageheader[22])*pow(2,0)+(imageheader[23])*pow(2,8)+(imageheader[24])*pow(2,16)+(imageheader[25])*pow(2,24);
    cout<<endl<<"Height: "<<endl<<(height)<<endl;

    bitCount=bitCount+(imageheader[28])*pow(2,0)+(imageheader[29])*pow(2,8);
    cout<<endl<<"Bit Depth: "<<endl<<(bitCount)<<endl;
}
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
USERRR5
  • 430
  • 2
  • 10
  • 27
  • 3
    Usually, after a period or a comma, in English, people add a space. Moreover, capital letters should be used for the first word in a sentence. Finally, format your code so that it's readable and we do not lose time in trying to decipher it. – nbro Sep 30 '17 at 16:19
  • Sorry for the inconvenience – USERRR5 Sep 30 '17 at 16:23
  • 3
    code suggestion. Don't use `double`, the `pow` function or any floating point to represent something that is inherently an integral number of things – selbie Sep 30 '17 at 16:29
  • @USERRR5 -- Not using `pow` isn't just a code suggestion, the bug(s) may even come from using it. [See here](https://stackoverflow.com/questions/25678481/why-does-pown-2-return-24-when-n-5-with-my-compiler-and-os/25678721#25678721) – PaulMcKenzie Sep 30 '17 at 17:09
  • @USERRR5 - I've provided a solution for you, but it may not explain why you aren't getting the expected values for your BMPs. However the images you posted are PNG files. Send a link to the original BMP file for that Snoopy image and I'll take a look to see what's going wrong if the code below doesn't solve it. – selbie Sep 30 '17 at 17:12
  • https://www.google.com/search?q=snoopy+bmp&tbm=isch&imgil=K7zcNrrZDThBaM%253A%253BXXozJlKX3Sjg4M%253Bhttp%25253A%25252F%25252Fwww.dreamincode.net%25252Fforums%25252Ftopic%25252F261009-bitmap-printing-tutorial-in-c-win32%25252F&source=iu&pf=m&fir=K7zcNrrZDThBaM%253A%252CXXozJlKX3Sjg4M%252C_&usg=__CBM3Q5ViVvEIMUVfyccFHsws0Sc%3D&biw=1440&bih=794&ved=0ahUKEwivjMHSxM3WAhVEPY8KHbaSA6MQyjcINA&ei=AeLPWe-HEsT6vAS2pY6YCg#imgrc=K7zcNrrZDThBaM: here is the link for snoopy bmp image.. – USERRR5 Sep 30 '17 at 18:28
  • Thanks. The code sample I provided below works on the snoopy image. I just confirmed it. If you like the answer I provided, don't forget to "accept" it and give it the green check mark. – selbie Sep 30 '17 at 23:50

2 Answers2

3

Let's start by reading the BMP header in as a series of bytes, not integers. To make this code truly portable, we'll use <stdint> types.

#include <fstream>
#include <stdint.h>

int main()
{

    ifstream inputfile("D:/test.bmp", ios::binary);
    uint8_t headerbytes[54] = {};

    inputfile.read((char*)headerbytes, sizeof(headerbytes));

Now that we've got the header in memory as an array of bytes, we can simply cast the memory address of each header field back into a integer. Referencing the wikipedia page for bmp and the layout diagram.

    uint32_t filesize = *(uint32_t*)(headerbytes+2);
    uint32_t dibheadersize = *(uint32_t*)(headerbytes + 14);
    uint32_t width = *(uint32_t*)(headerbytes + 18);
    uint32_t height = *(uint32_t*)(headerbytes + 22);
    uint16_t planes = *(uint16_t*)(headerbytes + 26);
    uint16_t bitcount = *(uint16_t*)(headerbytes + 28);

Now an astute reader of the code will recognize that the individual fieds of a a BMP headers are stored in little endian format. And that the code above relies on you to have an x86 processor or any other architecture in which the byte layout is Little Endian. On a big endian machine, you'll have to apply a workaround to convert from LE to BE for each of the variables above.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • Bitmap header is only 54 bytes, you could use `inputfile.read((char*)headerbytes, 54);` – Barmak Shemirani Sep 30 '17 at 17:56
  • Than you so much..I wanted to use library functions as less I can so that I may understand the properties of bmp file . – USERRR5 Sep 30 '17 at 18:26
  • 1
    `operator>>` should not be used for reading binary data. As you have it, it will skip over bytes which are considered whitespace in the current encoding. You could use `noskipws`, but it would be better to use `read`, which is unambiguously for binary data. – Benjamin Lindley Sep 30 '17 at 19:54
  • @BenjaminLindley - fixed. – selbie Sep 30 '17 at 23:48
0

The bug is reading into signed char. This should fix it:

for(int i = 0; i < 1024; i++)
{
    //inputfile.get(c); imageheader[i] = int(c);

    // This version of get returns int, where -1 means EOF.  Should be checking for errors...
    imageheader[i] = inputfile.get();
}

Others have commented on improvements to the code so I won't bother.

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • I want to use library functions as less I can,would you kindly tell me how should I change my code..I did not get about the unsigned char.Could you help me with that. – USERRR5 Sep 30 '17 at 18:24
  • @USERRR5 I showed you exactly how to change your code. Replace the existing for loop reading in the data with the code above. `char` is default signed, so its value is not 0-255 but -128 to 127. Using an `int` can hold 0-255 correctly. – Mark Tolonen Oct 01 '17 at 00:58