#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
class Image
{
public:
Image( char* ps, int w, int h );
~Image();
char* pixels;
int width;
int height;
};
//Reads a bitmap image from file.
Image* loadBMP( const char* filename );
Image::Image( char* ps, int w, int h )
:pixels( ps ), width( w ), height( h )
{ }
Image::~Image()
{
delete[] pixels;
}
namespace
{
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes)
{
return ( int )( ( ( unsigned char )bytes[ 3 ] << 24 ) |
( ( unsigned char )bytes[ 2 ] << 16 ) |
( ( unsigned char )bytes[ 1 ] << 8 ) |
( ( unsigned char )bytes[ 0 ] ) |
);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes)
{
return ( short )( ( ( unsigned char )bytes[ 1 ] << 8 ) |
( ( unsigned char )bytes[ 0 ] )
);
}
//Reads the next four bytes as an integer, using little-endian form
int readInt( ifstream &input )
{
char buffer[ 4 ];
input.read( buffer, 4 );
return toInt( buffer );
}
//Reads the next two bytes as a short, using little-endian form
short readShort( ifstream &input )
{
char buffer[ 2 ];
input.read( buffer, 2 );
return toShort( buffer );
}
//Just like auto_ptr, but for arrays
template< class T >
class auto_array
{
private:
T* array;
mutable bool isReleased;
public:
explicit auto_array( T* array_ = NULL )
:array( array_ ), isReleased( false )
{ }
auto_array( const auto_array< T >& aarray )
{
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
~auto_array()
{
if (!isReleased && array != NULL)
{
delete[] array;
}
}
T* get() const
{
return array;
}
T &operator*() const
{
return *array;
}
void operator =( const auto_array< T >& aarray )
{
if (!isReleased && array != NULL)
{
delete[] array;
}
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
T* operator ->() const
{
return array;
}
T* release()
{
isReleased = true;
return array;
}
void reset( T* array_ = NULL )
{
if( !isReleased && array != NULL )
{
delete[] array;
}
array = array_;
}
T* operator +( int i )
{
return array + i;
}
T& operator[]( int i )
{
return array[i];
}
};
}
Image* loadBMP( const char* filename )
{
ifstream input;
char buffer[2];
int dataOffset
input.open( filename, ifstream::binary );
assert( !input.fail() || !"Could not find file" );
input.read(buffer, 2);
assert( buffer[ 0 ] == 'B' && buffer[ 1 ] == 'M' || !"Not a bitmap file" );
input.ignore( 8 );
dataOffset = readInt( input );
//Read the header
int headerSize = readInt( input );
int width;
int height;
switch( headerSize )
{
case 40:
width = readInt( input );
height = readInt( input );
input.ignore( 2 );
assert( readShort( input ) == 24 || !"Image is not 24 bits per pixel" );
assert( readShort( input ) == 0 || !"Image is compressed" );
break;
case 12:
width = readInt( input );
height = readInt( input );
input.ignore( 2 );
assert( readShort( input ) == 24 || !"Image is not 24 bits per pixel" );
break;
case 64:
assert( !"Can't load OS/2 V2 bitmaps" );
break;
case 108:
assert( !"Can't load Windows V4 bitmaps" );
break;
case 124:
assert( !"Can't load Windows V5 bitmaps" );
break;
default:
assert( !"Unknown bitmap format" );
}
//Read the data
auto_array< char > pixels( new char[ size ] );
auto_array< char > pixels2( new char[ width * height * 3 ] );
int bytesPerRow = ( ( width * 3 + 3 ) / 4 ) * 4 - ( width * 3 % 4 );
int size = bytesPerRow * height;
input.seekg( dataOffset, ios_base::beg );
input.read( pixels.get(), size );
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
for (int c = 0; c < 3; c++)
{
pixels2[ 3 * ( width * y + x ) + c ] =
pixels[ bytesPerRow * y + 3 * x + (2 - c) ];
}
}
}
input.close();
return new Image( pixels2.release(), width, height );
}
int main()
{
Image* img;
string file_name;
cout << "Enter your filename please :"; getline( cin, file_name
);
img = loadBMP( file_name.c_str() );
delete img;
return 0;
}