C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 10-30-2009, 01:17 PM   #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.
CodeCriminal is offline   Reply With Quote
Old 10-30-2009, 01:39 PM   #2
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 4,923
Post your code.
Sebastiani is offline   Reply With Quote
Old 10-30-2009, 02:16 PM   #3
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,381
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.
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is offline   Reply With Quote
Old 10-30-2009, 02:24 PM   #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.
CodeCriminal is offline   Reply With Quote
Old 10-30-2009, 04:35 PM   #5
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 4,923
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)
Sebastiani is offline   Reply With Quote
Old 10-30-2009, 05:08 PM   #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
CodeCriminal is offline   Reply With Quote
Old 10-30-2009, 06:52 PM   #7
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,381
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.
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is offline   Reply With Quote
Old 10-30-2009, 09:19 PM   #8
Guest
 
Sebastiani's Avatar
 
Join Date: Aug 2001
Posts: 4,923
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?
Sebastiani is offline   Reply With Quote
Reply

Tags
code

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Loading multiple files SanDiego619SDSU C Programming 4 10-29-2006 01:37 AM
Loading Bitmap Problem loopshot Game Programming 1 04-15-2005 12:26 PM
OpenGL -- Bitmaps HQSneaker Game Programming 14 09-06-2004 04:04 PM
Loading X Files with DirectX 8 ?? MrWizard Game Programming 2 07-24-2002 02:48 AM
Loading all files in a directory steve_i83 Windows Programming 2 08-26-2001 02:18 PM


All times are GMT -6. The time now is 04:00 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22