Thread: Manually Loading Bitmap Files

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    4

    Manually Loading Bitmap Files

    Hello, I was wondering if guys could help me out here, im trying to manually a load a bitmap file in a C++ program but am a little confused. After searching through various tutorials on this subject I dont seem to be doing anything wrong but for some reason the values I am getting in my bitmap headers seem to be wrong (or maybe its just me).

    Here is the code i have to read a bitmap, admitedly it is not complete as it only opens the file and reads in to my "custom" BitmapFileHeader and BitmapInfoHeader structures.
    Code:
     //structure to contain bitmap file header information. It is the same as the win32 version except its my own.. if that makes sense
    struct BitmapFileHeader {
    	unsigned short	Type;
    	unsigned int	Size;
    	unsigned short	Reserved1;
    	unsigned short	Reserved2;
    	unsigned int	OffBits;
    };
    
    struct BitmapInfoHeader {
    	unsigned int	Size;
    	long		Width;
    	long		Height;
    	unsigned short	Planes;
    	unsigned short	BitCount;
    	unsigned int	Compression;
    	unsigned int	SizeImage;
    	long		XPelsPerMeter;
    	long		YPelsPerMeter;
    	unsigned int	ClrUsed;
    	unsigned int	ClrImrportant;
    };
    
    // Read bitmap file
    void Bitmap::Read( const char* file )
    {
    	// open file for reading
    	std::ifstream f( file, std::ios::binary );
    	if ( !f.is_open( ) )
    	{
    		std::cout << "Error: File not found.";
    		f.close( );
    	}
    
    	// read in the file and info headers
    	f.read( reinterpret_cast<char*>(&mFileHeader), sizeof( BitmapFileHeader ) );
    	f.read( reinterpret_cast<char*>(&mInfoHeader), sizeof( BitmapInfoHeader ) );
    }
    Here is the list of values that shows up when "stepping through" my code with the vs debugger:

    mFileHeader.Type = 19778 < (Thats probably the only value that looks correct to me.. when cast into char* it produces "BM")
    mFileHeader.Size = 0
    mFileHeader.Reserved1 = 0
    mFileHeader.Reserved2 = 54
    mFileHeader.OffBits = 2621440

    mInfoHeader.Size = 131072
    mInfoHeader.Width = 131072
    mInfoHeader.Height = 65536
    mInfoHeader.Planes = 24
    mInfoHeader.BitCount = 0
    mInfoHeader.Compression = 1048576
    mInfoHeader.SizeImage = 0
    mInfoHeader.XPelsPerMeter = 0
    mInfoHeader.YPelsPerMeter = 0
    mInfoHeader.ClrUsed = 0
    mInfoHeader.ClrImrportant = 0

    Im not sure but i think the compression might be the problem, however i did try another type of .bmp that had compression 0 but still had the same problems so maybe not (and im guessing compression only deals with the actual data, not the headers).

    Anywho, Thanks in advance.
    ~CC


    PS: The image I am loading is a simple 2x2 24-bit .bmp created with windows 7 version of paint. Unless im a mistaken the mInfoHeader.Width/Height should be 2 x 2
    not 131072x65536, you get my point :P
    Last edited by CodeCriminal; 10-30-2009 at 02:12 PM.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Post your code.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You are trying the "newbie method" of reading an on-disk binary data structure. The problem is that the data structure on disk contains no padding, whereas the compiler struct does. For instance:

    Code:
    struct BitmapFileHeader {
    	unsigned short	Type;
    	unsigned int	Size;
    	unsigned short	Reserved1;
    	unsigned short	Reserved2;
    	unsigned int	OffBits;
    };
    The first element of the struct is a short. It is followed by a 32-bit int. That means the compiler will insert two pad bytes between these data members, breaking your "read a whole chunk at once" method.

    The correct method is to individually load the values and put them, one by one, into the structure members.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Registered User
    Join Date
    Oct 2009
    Posts
    4
    Ah.. well thats disappointing.. ill give it whirl thanks.

    EDIT:
    Ok so that works, ill try to remember that for the future
    still though, it is kind of disapointing that i have the read each member of the structs individually is there not another way around that?
    Last edited by CodeCriminal; 10-30-2009 at 02:32 PM.

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by CodeCriminal View Post
    Ah.. well thats disappointing.. ill give it whirl thanks.

    EDIT:
    Ok so that works, ill try to remember that for the future
    still though, it is kind of disapointing that i have the read each member of the structs individually is there not another way around that?
    Most compilers support some sort of 'packing' directive. The most common one:

    Code:
    
    #pragma pack(push, 1) // the '1' means 'byte boundary'
    // structure(s) defined here
    #pragma pack(pop)

  6. #6
    Registered User
    Join Date
    Oct 2009
    Posts
    4
    Quote Originally Posted by Sebastiani View Post
    Most compilers support some sort of 'packing' directive. The most common one:

    Code:
    
    #pragma pack(push, 1) // the '1' means 'byte boundary'
    // structure(s) defined here
    #pragma pack(pop)
    Hmm, Ive never used "packing directives" before, perhaps its time a take a look at em. Thanks

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Sebastiani View Post
    Most compilers support some sort of 'packing' directive. The most common one:

    Code:
    
    #pragma pack(push, 1) // the '1' means 'byte boundary'
    // structure(s) defined here
    #pragma pack(pop)
    True. However, 1) it's non-portable and 2) it might slow down access to the structure members. The compiler aligns them for speed reasons, and you're defeating that.

    On some platforms, it's REQUIRED that certain data types have certain alignments, and on those architectures, forcing the compiler to omit the padding can actually cause crashing.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    True on both points, but nonetheless it is a fairly common practice and generally safe to do on most systems. That said, there are plenty of C++ tricks that be used to achieve a portable solution with minimal effort:

    Code:
    
    #include <iostream>
    #include <fstream>
    #include <stdexcept>
    
    struct read_binary_file_helper
    {
    	read_binary_file_helper( std::istream& in )
    	: in( in )
    	{	}
    
    	template < typename Type >
    	bool operator ( ) ( Type& value, bool throw_on_error = true )
    	{
    		if( in.read( ( char* )&value, sizeof( value ) ) )
    			return true;
    		if( throw_on_error )	
    			throw std::runtime_error( "read_binary_file_helper: file read error" );
    		return false;	
    	}
    
    	template < typename Type >
    	inline operator Type ( void )
    	{
    		Type
    			value;
    		( *this )( value );
    		return value;	
    	}
    
    	std::istream&
    		in;
    };	
    
    struct BitmapFileHeader {
    	unsigned short	Type;
    	unsigned int	Size;
    	unsigned short	Reserved1;
    	unsigned short	Reserved2;
    	unsigned int	OffBits;
    };
    
    struct BitmapInfoHeader {
    	unsigned int	Size;
    	long		Width;
    	long		Height;
    	unsigned short	Planes;
    	unsigned short	BitCount;
    	unsigned int	Compression;
    	unsigned int	SizeImage;
    	long		XPelsPerMeter;
    	long		YPelsPerMeter;
    	unsigned int	ClrUsed;
    	unsigned int	ClrImrportant;
    };
    
    template < typename Type >
    void print( char const* text, Type const& value )
    {
    	std::cout << text << ": " << std::hex << "0x" << value << std::endl;
    }
    
    int main( int, char** argv )
    {
    	using namespace 
    		std;
    	while( *( ++argv ) )
    	{
    		cout << "File: '" << *argv << "'" << endl;
    		try
    		{
    			ifstream
    				in( *argv, ios::binary );
    			if( !in )
    				throw std::runtime_error( "cannot open file" );
    			BitmapFileHeader
    				bfh;
    			BitmapInfoHeader
    				bih;
    			read_binary_file_helper
    				rbh( in );
    			print( "bfh.Type", bfh.Type = rbh );
    			print( "bfh.Size", bfh.Size = rbh );
    			print( "bfh.Reserved1", bfh.Reserved1 = rbh );
    			print( "bfh.Reserved2", bfh.Reserved2 = rbh );
    			print( "bfh.OffBits", bfh.OffBits = rbh );
    			print( "bih.Size", bih.Size = rbh );
    			print( "bih.Width", bih.Width = rbh );
    			print( "bih.Height", bih.Height = rbh );
    			print( "bih.Planes", bih.Planes = rbh );
    			print( "bih.BitCount", bih.BitCount = rbh );
    			print( "bih.Compression", bih.Compression = rbh );
    			print( "bih.SizeImage", bih.SizeImage = rbh );
    			print( "bih.XPelsPerMeter", bih.XPelsPerMeter = rbh );
    			print( "bih.YPelsPerMeter", bih.YPelsPerMeter = rbh );
    			print( "bih.ClrUsed", bih.ClrUsed = rbh );
    			print( "bih.ClrImrportant", bih.ClrImrportant = rbh );			
    		}
    		catch( exception const& error )
    		{
    			cerr << "Error: " << error.what( ) << endl;
    		}
    	}	
    	return 0;
    }

    Isn't C++ great?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Loading multiple files
    By SanDiego619SDSU in forum C Programming
    Replies: 4
    Last Post: 10-29-2006, 01:37 AM
  2. Loading Bitmap Problem
    By loopshot in forum Game Programming
    Replies: 1
    Last Post: 04-15-2005, 12:26 PM
  3. OpenGL -- Bitmaps
    By HQSneaker in forum Game Programming
    Replies: 14
    Last Post: 09-06-2004, 04:04 PM
  4. Loading X Files with DirectX 8 ??
    By MrWizard in forum Game Programming
    Replies: 2
    Last Post: 07-24-2002, 02:48 AM

Tags for this Thread