Please help me with reading a BMP file header using ifstream

Apr 21, 2014 at 7:37am
I'm trying to read a .bmp file header using ifstream but my output isn't right, please help :<

From what I've researched a bmp file's header should have 14 bytes like the information in this image: http://imgur.com/BocfJuy

I have created my own struct to represent those:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <fstream>
using namespace std;

struct BmpSignature
{
	unsigned char data[2];
};

struct BmpHeader
{
	BmpSignature signature;
	unsigned int fileSize;
	unsigned short reserved1;
	unsigned short reserved2;
	unsigned int dataOffset;
};


I open a file using ifstream
1
2
ifstream fin;
fin.open("Untitled.bmp",ios::binary);


Here's how I read the header

1
2
3
4
5
6
7
8
void ReadHeader(ifstream &fin, BmpHeader &header)
{
	if(!fin)
		return;

	fin.seekg(0, ios::beg);
	fin.read((char*) &header, sizeof(header));
}


My output function
1
2
3
4
5
6
7
8
9
void PrintHeader(BmpHeader header)
{
	cout<<"==== BMP HEADER ===="<<endl;
	cout<<header.signature.data[0]<<header.signature.data[1]<<endl;
	cout<<"+ File Size  : "<<header.fileSize<<" byte(s)"<<endl;
	cout<<"+ Reserved1  : "<<header.reserved1<<endl;
	cout<<"+ Reserved2  : "<<header.reserved2<<endl;
	cout<<"+ Data Offset: "<<header.dataOffset<<" byte(s)"<<endl;
}


The problem is, I can't get the right output from my program, i.e. the file size is some random number completely different from my file's size in the hard disk.
I can get the right output if I change my reading function into this
1
2
3
4
5
6
7
8
9
10
11
void ReadHeader(ifstream &fin, BmpHeader &header)
{
	if(!fin)
		return;

	fin.seekg(2, ios::beg); //skipping the  first 'BM' 2 bytes
	fin.read((char*) &header.fileSize, sizeof(unsigned int)); //read file size
	fin.read((char*) &header.reserved1, sizeof(unsigned short)); //read reserved1
	fin.read((char*) &header.reserved2, sizeof(unsigned short)); //read reserved2
	fin.read((char*) &header.dataOffset, sizeof(unsigned int)); //read the data offset	
}


My question is, what's wrong with my first approach because I can still read the first 2 bytes as 'BM' but all information after that is all jacked up. How can I fix the first approach to be usable then?

Thank you for your help and sorry for my bad English
Apr 21, 2014 at 11:01am
Apr 21, 2014 at 12:00pm
Yes, there are probably padding bytes inserted into the struct so that for example a 4-byte integer is located on an appropriate memory boundary.

One workaround is to break the first two bytes into a completely separate struct, and read it separately from the rest of the header.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <fstream>
using namespace std;

struct BmpSignature
{
    unsigned char data[2];
    BmpSignature() { data[0] = data[1] = 0; }
};

struct BmpHeader
{
    unsigned int fileSize;
    unsigned short reserved1;
    unsigned short reserved2;
    unsigned int dataOffset;
    BmpHeader() : fileSize(0),  reserved1(0), reserved2(0), dataOffset(0) { }
};

void ReadHeader(ifstream &fin, BmpSignature & sig, BmpHeader &header)
{
    if(!fin)
        return;

    fin.seekg(0, ios::beg);
    
    fin.read((char*) &sig, sizeof(sig));
    fin.read((char*) &header, sizeof(header));
}

void PrintHeader(BmpSignature sig, BmpHeader header)
{
    cout<<"==== BMP HEADER ===="<<endl;
    cout<<"+ Signature  : " << sig.data[0]<<sig.data[1]<<endl;
    cout<<"+ File Size  : " << header.fileSize<<" byte(s)"<<endl;
    cout<<"+ Reserved1  : " << header.reserved1<<endl;
    cout<<"+ Reserved2  : " << header.reserved2<<endl;
    cout<<"+ Data Offset: " << header.dataOffset<<" byte(s)"<<endl;
}

int main()
{
    
    ifstream fin("untitled.bmp", ios::binary);
    
    BmpSignature sig;
    BmpHeader hdr;
    PrintHeader(sig, hdr);
    ReadHeader(fin, sig, hdr);
    PrintHeader(sig, hdr);
    
    return 0;  
}

Last edited on Apr 21, 2014 at 12:07pm
Apr 22, 2014 at 4:23pm
Thanks guys and sorry for the late reply x) Both of your solutions work wonderfully
Topic archived. No new replies allowed.