3
votes

I am trying to count number of pixels in BMP image and thus the no of bytes per pixel, by using the information I gathered from struct BITMAPINFOHEADER . But whenever I run my code I get number of bytes per pixel = 0

struct BITMAPFILEHEADER             // File header
{
char bfType[2];                   // File type: should be BM ( 0x42 0x4D ) 
int bfSize;                       // File size in bytes
short bfReserved1;                // Reserved - for what i have no idea :P 
short bfReserved2;                // -||-
int bfOffBits;                    // Offset, adress of the beginning of the information about image (pixels )
};

struct BITMAPINFOHEADER             // Bitmap header
{
unsigned int biSize;              // Size of this header
unsigned int biWidth;             // Width of image ( in pixels)
unsigned int biHeight;            // Height of this image ( in pixels )
unsigned short biPlanes;          // Numer of color planes, always 1
unsigned short biBitCount;        // Number of bytes for pixel.  Possibility values :1,4,8,16, 24 and 32
unsigned int biCompression;       // Used compression (0 -none)
unsigned int biSizeImage;         // Size of image 
signed int biXPelsPerMeter;       // Horizontal resolution of the image (pixel per meter)
signed int biYPelsPerMeter;       // Vertical resolution of the image (pixel per meter)
unsigned int biClrUsed;           // Number of colors in the color palette, or 0 to default to 2^n ( 0- no palette)
unsigned int biClrImportant;      // Number of important colors used
 };

struct Pixel{
unsigned int blue;  // or double?
unsigned int green;
unsigned int red;
//unsigned char reserved;
};


void Image::conversiontoBRG(const char* filename)
{
ifstream brgfile;
brgfile.open(filename, ios::in | ios::binary);


char *bmpheadinfo = new char[sizeof(BITMAPFILEHEADER)];
brgfile.read(bmpheadinfo, sizeof(BITMAPFILEHEADER));
BITMAPFILEHEADER* bmpheader = (BITMAPFILEHEADER*)bmpheadinfo;

cout << "File type : " << bmpheader->bfType << endl;
cout << "File size : " << bmpheader->bfSize << endl;
cout << "File Offset for the beginning of image info : " << bmpheader->bfOffBits << endl << endl;


bmpheadinfo = new char[sizeof(BITMAPINFOHEADER)];
brgfile.read(bmpheadinfo, sizeof(BITMAPINFOHEADER));
BITMAPINFOHEADER* bmpinfo = (BITMAPINFOHEADER*)bmpheadinfo;

cout << "File Header Size : " << bmpinfo->biSize << endl;
cout << "Width : " << bmpinfo->biWidth << endl;
cout << "Height : " << bmpinfo->biHeight << endl;
cout << "No of bytes per pixel : " << bmpinfo->biBitCount << endl;
cout << "Used compression: " << bmpinfo->biCompression << endl;
cout << "Image size: " << bmpinfo->biSizeImage << endl;
cout << "Horizontal resolution: " << bmpinfo->biXPelsPerMeter << endl;
cout << "Vertical resolution: " << bmpinfo->biYPelsPerMeter << endl;
cout << "Number of colors in the color palette: " << bmpinfo->biClrUsed << endl;
cout << "Number of important colors used: " << bmpinfo->biClrImportant << endl;
}

I am trying to work on a bitmap image called index.bmp

Dimension : 275x184
Width : 275 pixels
Height : 184 pixels
Bit Depth : 24
Name : index.bmp
Item Type : BMP file
Size : 148 KB

But whenever I run the above code I get the following output. I am not sure where I am going wrong. Please help me.

File type : BMVS
File size : 2
File Offset for the beginning of image info : 2621440

File Header Size : 18022400
Width : 12058624
Height : 65536
No of bytes per pixel : 0
Used compression: 1394606080
Image size: 2
Horizontal resolution: 0
Vertical resolution: 0
Number of colors in the color palette: 0
Number of important colors used: 973078528
2
12058624 is 0xB80000. 0xB8 is 184. 18022400 is 0x1130000. 0x113 is 275. You're out of sync.molbdnilo
BMVS is 0x424d5653 in big endian hex. The string VS appears because bfType isn't a null terminated string like TonyD said and it's the 2 MSBs of bfSize. As you didn't specify the padding, because of alignment bfSize starts at the next 4 byte boundary and reads 2 or 0x02000000 in big endian. Therefore it's actual value is 0x00025356 = 152,406 bytes = 148.834KBphuclv
Just use the #pragma pack(push, 1) and #pragma pack(pop) macro. You will get the result that you expected.Farhad Reza
@PureProgrammer That was answered already by legends2k and no, it won't work as that just fixes one problem in the codephuclv
@LưuVĩnhPhúc Sorry, I did not think about that. However, I think bfType should be type of unsigned short right?Farhad Reza

2 Answers

2
votes

As well the packing issue legends2k mentions:

  • you're not considering endianness (Google it, then use ntohs et al in your code),

  • you should create a local BITMAPFILEHEADER bmpheader; object then brgfile.read((char*)&bmpheader, sizeof bmpheader); - that way you know the embedded multi-byte integers will be properly aligned for access - otherwise you may get SIGBUS or similar on some systems; do something similar for BITMAPINFOHEADER

  • don't just print bfType either - as an array, it decays to a const char* for <<, and it's not NUL terminated so you get garbage extra characters.

1
votes

The BMP file will have no padding bits within the header data, while you're structs have been defined with no tight packing macros; this will lead to your file data members and struct data members to be not aligned correctly. Fix this and you'll be able to see the fields rightly

#pragma pack(push, 1)       // macro to avoid padding bytes within a struct

struct BITMAPFILEHEADER             // File header
{
    char bfType[2];                   // File type: should be BM ( 0x42 0x4D ) 
    int bfSize;                       // File size in bytes
    short bfReserved1;                // Reserved - for what i have no idea :P 
    short bfReserved2;                // -||-
    int bfOffBits;                    // Offset, adress of the beginning of the information about image (pixels )
};

struct BITMAPINFOHEADER             // Bitmap header
{
    unsigned int biSize;              // Size of this header
    unsigned int biWidth;             // Width of image ( in pixels)
    unsigned int biHeight;            // Height of this image ( in pixels )
    unsigned short biPlanes;          // Numer of color planes, always 1
    unsigned short biBitCount;        // Number of bytes for pixel.  Possibility values :1,4,8,16, 24 and 32
    unsigned int biCompression;       // Used compression (0 -none)
    unsigned int biSizeImage;         // Size of image 
    signed int biXPelsPerMeter;       // Horizontal resolution of the image (pixel per meter)
    signed int biYPelsPerMeter;       // Vertical resolution of the image (pixel per meter)
    unsigned int biClrUsed;           // Number of colors in the color palette, or 0 to default to 2^n ( 0- no palette)
    unsigned int biClrImportant;      // Number of important colors used
};

#pragma pack(pop)         // stop doing the tight packing

It can be verified that there're no padding bits now

std::cout << sizeof BITMAPFILEHEADER << '\n';

would print 14 now; try it by disabling the macros and you would see something more than 14. On this live example it shows 16.