// Bmp.h // NKU CSC 480/580 - Kirby // --------------------------------------------------------------------------- // A bare bones encapsulation of a 24-bit Windows .bmp file as an immutable class. // by K. Kirby, Fall 1996; revised Fall 2004. // --------------------------------------------------------------------------- #include #include #include #include #include using namespace std ; #ifndef _WINDEF_ // Types - defined as in WinDef.h typedef int LONG ; typedef unsigned int DWORD ; typedef unsigned short WORD ; #endif #ifndef _WINGDI_ // Types - defined as in WinGDI.h #pragma pack(2) /* align structure fields on 2-byte boundaries */ typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{ // bmih DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount ; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; #pragma pack() /* return to default packing of structure fields*/ #endif class Bmp { public: Bmp( const string& filename ) ; ~Bmp() ; int getWidth() const { return _bmih.biWidth ; } int getHeight() const { return _bmih.biHeight ; } void getPixel( int row, int column, unsigned char rgb[3] ) const ; private: BITMAPFILEHEADER _bmfh ; BITMAPINFOHEADER _bmih ; int _pixelCount ; int _imageSize ; unsigned char* _image ; // the actual data // Helper- convert row and column to offset. int _rcToOffset( int row, int col ) const ; } ; inline void errorExit( const string& message ) { cerr << "Error: " << message << endl ; exit( 1 ) ; } inline Bmp::Bmp( const string& filename ) // // Constructs a Bmp objects from a 24-bit uncompressed Windows BMP file. // See Petzold & Yao, PROGRAMMING WINDOWS 95, pp.176-178 for file format description. { // Open the .BMP file for input // ifstream infile( filename.c_str(), ios::in | ios::binary ) ; if ( ! infile ) errorExit( "Cannot open file " + filename ) ; // Read the first header information // infile.read( (char*) &_bmfh, sizeof( BITMAPFILEHEADER ) ) ; unsigned char* pc= (unsigned char*) &_bmfh ; if ( ! ( pc[0]=='B' && pc[1]=='M' ) ) errorExit( filename + " is not a BMP file" ) ; infile.read( (char*) &_bmih, sizeof( BITMAPINFOHEADER ) ) ; // Check to see if this kind of BMP file can be handled by this class // if ( sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER ) != _bmfh.bfOffBits ) errorExit( "BMP file " + filename + " has unknown extra header" ) ; if ( _bmih.biCompression != 0 ) errorExit( "BMP file " + filename + " is compressed and cannot be processed" ) ; if ( _bmih.biBitCount != 24 ) errorExit( "BMP file " + filename + " is not a 24-bit color bitmap" ) ; // Read the image bytes into memory // int _imageSize= _bmfh.bfSize - _bmfh.bfOffBits ; int _pixelCount= _bmih.biWidth * _bmih.biHeight ; _image= new unsigned char[ _imageSize ] ; if ( ! _image ) errorExit( "Insufficient memory to store BMP file " + filename ) ; infile.read( (char*) _image, _imageSize ) ; infile.close() ; } inline Bmp::~Bmp() // // Destroy the current Bmp object { delete [] _image ; } inline void Bmp::getPixel( int row, int column, unsigned char rgb[3] ) const // // Store red, green, blue values (0-255) at pixel in rgb[]. { assert( row >= 0 && row < _bmih.biHeight && column >= 0 && column < _bmih.biWidth ) ; unsigned char* ppix= _image + _rcToOffset( row, column ) ; rgb[0]= ppix[2] ; rgb[1]= ppix[1] ; rgb[2]= ppix[0] ; } inline int Bmp::_rcToOffset( int row, int column ) const // // Offset of start of RGB value for pixel at given row and column, from start of image bytes. { int displayedBytesPerRow= _bmih.biWidth * 3 ; int shortfall= displayedBytesPerRow % 4 ; int pad= ( shortfall > 0 ) ? 4 - shortfall : 0 ; int rowLength= displayedBytesPerRow + pad ; int rowsDown= _bmih.biHeight - row - 1 ; return rowsDown * rowLength + 3*column ; } /* HEADERS referred to above-- from WinGDI.h ( # < Windows.h ). typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{ // bmih DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount ; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; Example header contents for a 182x134 BMP file: {19778, 73986, 0, 0, 54 } {40, 134, 183, 1, 24, 0, 73932, 4724, 4724, 0, 0 } */