RgbImage.cpp

Go to the documentation of this file.
00001 
00008 #include "RgbImage.h"
00009 
00010 #ifndef RGBIMAGE_DONT_USE_OPENGL
00011 #include <windows.h>
00012 #include "GL/gl.h"
00013 #endif
00014 
00019 RgbImage::RgbImage( int numRows, int numCols )
00020 {
00021         NumRows = numRows;
00022         NumCols = numCols;
00023         ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
00024         if ( !ImagePtr ) {
00025                 fprintf(stderr, "Unable to allocate memory for %ld x %ld bitmap.\n", 
00026                                 NumRows, NumCols);
00027                 Reset();
00028                 ErrorCode = MemoryError;
00029         }
00030         // Zero out the image
00031         unsigned char* c = ImagePtr;
00032         int rowLen = GetNumBytesPerRow();
00033         for ( int i=0; i<NumRows; i++ ) 
00034         {
00035                 for ( int j=0; j<rowLen; j++ ) 
00036                 {
00037                         *(c++) = 0;
00038                 }
00039         }
00040 }
00041 
00042 /* ********************************************************************
00043  *  LoadBmpFile
00044  *  Read into memory an RGB image from an uncompressed BMP file.
00045  *  Return true for success, false for failure.  Error code is available
00046  *     with a separate call.
00047  *  Author: Sam Buss December 2001.
00048  **********************************************************************/
00054 bool RgbImage::LoadBmpFile( const char* filename ) 
00055 {  
00056         Reset();
00057         FILE* infile = fopen( filename, "rb" );         // Open for reading binary data
00058         if ( !infile ) {
00059                 fprintf(stderr, "Unable to open file: %s\n", filename);
00060                 ErrorCode = OpenError;
00061                 return false;
00062         }
00063 
00064         bool fileFormatOK = false;
00065         int bChar = fgetc( infile );
00066         int mChar = fgetc( infile );
00067         if ( bChar=='B' && mChar=='M' ) {                       // If starts with "BM" for "BitMap"
00068                 skipChars( infile, 4+2+2+4+4 );                 // Skip 4 fields we don't care about
00069                 NumCols = readLong( infile );
00070                 NumRows = readLong( infile );
00071                 skipChars( infile, 2 );                                 // Skip one field
00072                 int bitsPerPixel = readShort( infile );
00073                 skipChars( infile, 4+4+4+4+4+4 );               // Skip 6 more fields
00074 
00075                 if ( NumCols>0 && NumCols<=100000 && NumRows>0 && NumRows<=100000  
00076                         && bitsPerPixel==24 && !feof(infile) ) {
00077                         fileFormatOK = true;
00078                 }
00079         }
00080         if ( !fileFormatOK ) {
00081                 Reset();
00082                 ErrorCode = FileFormatError;
00083                 fprintf(stderr, "Not a valid 24-bit bitmap file: %s.\n", filename);
00084                 fclose ( infile );
00085                 return false;
00086         }
00087 
00088         // Allocate memory
00089         ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
00090         if ( !ImagePtr ) {
00091                 fprintf(stderr, "Unable to allocate memory for %ld x %ld bitmap: %s.\n", 
00092                                 NumRows, NumCols, filename);
00093                 Reset();
00094                 ErrorCode = MemoryError;
00095                 fclose ( infile );
00096                 return false;
00097         }
00098 
00099         unsigned char* cPtr = ImagePtr;
00100         for ( int i=0; i<NumRows; i++ ) {
00101                 int j;
00102                 for ( j=0; j<NumCols; j++ ) {
00103                         *(cPtr+2) = fgetc( infile );    // Blue color value
00104                         *(cPtr+1) = fgetc( infile );    // Green color value
00105                         *cPtr = fgetc( infile );                // Red color value
00106                         cPtr += 3;
00107                 }
00108                 int k=3*NumCols;                                        // Num bytes already read
00109                 for ( ; k<GetNumBytesPerRow(); k++ ) {
00110                         fgetc( infile );                                // Read and ignore padding;
00111                         *(cPtr++) = 0;
00112                 }
00113         }
00114         if ( feof( infile ) ) {
00115                 fprintf( stderr, "Premature end of file: %s.\n", filename );
00116                 Reset();
00117                 ErrorCode = ReadError;
00118                 fclose ( infile );
00119                 return false;
00120         }
00121         fclose( infile );       // Close the file
00122         return true;
00123 }
00128 short RgbImage::readShort( FILE* infile )
00129 {
00130         // read a 16 bit integer
00131         unsigned char lowByte, hiByte;
00132         lowByte = fgetc(infile);                        // Read the low order byte (little endian form)
00133         hiByte = fgetc(infile);                 // Read the high order byte
00134 
00135         // Pack together
00136         short ret = hiByte;
00137         ret <<= 8;
00138         ret |= lowByte;
00139         return ret;
00140 }
00145 long RgbImage::readLong( FILE* infile )
00146 {  
00147         // Read in 32 bit integer
00148         unsigned char byte0, byte1, byte2, byte3;
00149         byte0 = fgetc(infile);                  // Read bytes, low order to high order
00150         byte1 = fgetc(infile);
00151         byte2 = fgetc(infile);
00152         byte3 = fgetc(infile);
00153 
00154         // Pack together
00155         long ret = byte3;
00156         ret <<= 8;
00157         ret |= byte2;
00158         ret <<= 8;
00159         ret |= byte1;
00160         ret <<= 8;
00161         ret |= byte0;
00162         return ret;
00163 }
00168 void RgbImage::skipChars( FILE* infile, int numChars )
00169 {
00170         for ( int i=0; i<numChars; i++ ) {
00171                 fgetc( infile );
00172         }
00173 }
00174 
00175 /* ********************************************************************
00176  *  WriteBmpFile
00177  *  Write an RGB image to an uncompressed BMP file.
00178  *  Return true for success, false for failure.  Error code is available
00179  *     with a separate call.
00180  *  Author: Sam Buss, January 2003.
00181  **********************************************************************/
00187 bool RgbImage::WriteBmpFile( const char* filename )
00188 {
00189         FILE* outfile = fopen( filename, "wb" );                // Open for reading binary data
00190         if ( !outfile ) {
00191                 fprintf(stderr, "Unable to open file: %s\n", filename);
00192                 ErrorCode = OpenError;
00193                 return false;
00194         }
00195 
00196         fputc('B',outfile);
00197         fputc('M',outfile);
00198         int rowLen = GetNumBytesPerRow();
00199         writeLong( 40+14+NumRows*rowLen, outfile );     // Length of file
00200         writeShort( 0, outfile );                                       // Reserved for future use
00201         writeShort( 0, outfile );
00202         writeLong( 40+14, outfile );                            // Offset to pixel data
00203         writeLong( 40, outfile );                                       // header length
00204         writeLong( NumCols, outfile );                          // width in pixels
00205         writeLong( NumRows, outfile );                          // height in pixels (pos for bottom up)
00206         writeShort( 1, outfile );               // number of planes
00207         writeShort( 24, outfile );              // bits per pixel
00208         writeLong( 0, outfile );                // no compression
00209         writeLong( 0, outfile );                // not used if no compression
00210         writeLong( 0, outfile );                // Pixels per meter
00211         writeLong( 0, outfile );                // Pixels per meter
00212         writeLong( 0, outfile );                // unused for 24 bits/pixel
00213         writeLong( 0, outfile );                // unused for 24 bits/pixel
00214 
00215         // Now write out the pixel data:
00216         unsigned char* cPtr = ImagePtr;
00217         for ( int i=0; i<NumRows; i++ ) {
00218                 // Write out i-th row's data
00219                 int j;
00220                 for ( j=0; j<NumCols; j++ ) {
00221                         fputc( *(cPtr+2), outfile);             // Blue color value
00222                         fputc( *(cPtr+1), outfile);             // Blue color value
00223                         fputc( *(cPtr+0), outfile);             // Blue color value
00224                         cPtr+=3;
00225                 }
00226                 // Pad row to word boundary
00227                 int k=3*NumCols;                                        // Num bytes already read
00228                 for ( ; k<GetNumBytesPerRow(); k++ ) {
00229                         fputc( 0, outfile );                            // Read and ignore padding;
00230                         cPtr++;
00231                 }
00232         }
00233 
00234         fclose( outfile );      // Close the file
00235         return true;
00236 }
00241 void RgbImage::writeLong( long data, FILE* outfile )
00242 {  
00243         // Read in 32 bit integer
00244         unsigned char byte0, byte1, byte2, byte3;
00245         byte0 = (unsigned char)(data&0x000000ff);               // Write bytes, low order to high order
00246         byte1 = (unsigned char)((data>>8)&0x000000ff);
00247         byte2 = (unsigned char)((data>>16)&0x000000ff);
00248         byte3 = (unsigned char)((data>>24)&0x000000ff);
00249 
00250         fputc( byte0, outfile );
00251         fputc( byte1, outfile );
00252         fputc( byte2, outfile );
00253         fputc( byte3, outfile );
00254 }
00259 void RgbImage::writeShort( short data, FILE* outfile )
00260 {  
00261         // Read in 32 bit integer
00262         unsigned char byte0, byte1;
00263         byte0 = data&0x000000ff;                // Write bytes, low order to high order
00264         byte1 = (data>>8)&0x000000ff;
00265 
00266         fputc( byte0, outfile );
00267         fputc( byte1, outfile );
00268 }
00269 
00270 
00271 /*********************************************************************
00272  * SetRgbPixel routines allow changing the contents of the RgbImage. *
00273  *********************************************************************/
00281 void RgbImage::SetRgbPixelf( long row, long col, double red, double green, double blue )
00282 {
00283         SetRgbPixelc( row, col, doubleToUnsignedChar(red), 
00284                                                         doubleToUnsignedChar(green),
00285                                                         doubleToUnsignedChar(blue) );
00286 }
00294 void RgbImage::SetRgbPixelc( long row, long col,
00295                                    unsigned char red, unsigned char green, unsigned char blue )
00296 {
00297         assert ( row<NumRows && col<NumCols );
00298         unsigned char* thePixel = GetRgbPixel( row, col );
00299         *(thePixel++) = red;
00300         *(thePixel++) = green;
00301         *(thePixel) = blue;
00302 }
00303 
00309 unsigned char RgbImage::doubleToUnsignedChar( double x )
00310 {
00311         if ( x>=1.0 ) {
00312                 return (unsigned char)255;
00313         }
00314         else if ( x<=0.0 ) {
00315                 return (unsigned char)0;
00316         }
00317         else {
00318                 return (unsigned char)(x*255.0);                // Rounds down
00319         }
00320 }
00321 // Bitmap file format  (24 bit/pixel form)              BITMAPFILEHEADER
00322 // Header (14 bytes)
00323 //       2 bytes: "BM"
00324 //   4 bytes: long int, file size
00325 //   4 bytes: reserved (actually 2 bytes twice)
00326 //   4 bytes: long int, offset to raster data
00327 // Info header (40 bytes)                                               BITMAPINFOHEADER
00328 //   4 bytes: long int, size of info header (=40)
00329 //       4 bytes: long int, bitmap width in pixels
00330 //   4 bytes: long int, bitmap height in pixels
00331 //   2 bytes: short int, number of planes (=1)
00332 //   2 bytes: short int, bits per pixel
00333 //   4 bytes: long int, type of compression (not applicable to 24 bits/pixel)
00334 //   4 bytes: long int, image size (not used unless compression is used)
00335 //   4 bytes: long int, x pixels per meter
00336 //   4 bytes: long int, y pixels per meter
00337 //   4 bytes: colors used (not applicable to 24 bit color)
00338 //   4 bytes: colors important (not applicable to 24 bit color)
00339 // "long int" really means "unsigned long int"
00340 // Pixel data: 3 bytes per pixel: RGB values (in reverse order).
00341 //      Rows padded to multiples of four.
00342 
00343 
00344 #ifndef RGBIMAGE_DONT_USE_OPENGL
00345 
00347 bool RgbImage::LoadFromOpenglBuffer()                                   // Load the bitmap from the current OpenGL buffer
00348 {
00349         int viewportData[4];
00350         glGetIntegerv( GL_VIEWPORT, viewportData );
00351         int& vWidth = viewportData[2];
00352         int& vHeight = viewportData[3];
00353         
00354         if ( ImagePtr==0 ) { // If no memory allocated
00355                 NumRows = vHeight;
00356                 NumCols = vWidth;
00357                 ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
00358                 if ( !ImagePtr ) {
00359                         fprintf(stderr, "Unable to allocate memory for %ld x %ld buffer.\n", 
00360                                         NumRows, NumCols);
00361                         Reset();
00362                         ErrorCode = MemoryError;
00363                         return false;
00364                 }
00365         }
00366         assert ( vWidth>=NumCols && vHeight>=NumRows );
00367         int oldGlRowLen;
00368         if ( vWidth>=NumCols ) {
00369                 glGetIntegerv( GL_UNPACK_ROW_LENGTH, &oldGlRowLen );
00370                 glPixelStorei( GL_UNPACK_ROW_LENGTH, NumCols );
00371         }
00372         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
00373 
00374         // Get the frame buffer data.
00375         glReadPixels( 0, 0, NumCols, NumRows, GL_RGB, GL_UNSIGNED_BYTE, ImagePtr);
00376 
00377         // Restore the row length in glPixelStorei  (really ought to restore alignment too).
00378         if ( vWidth>=NumCols ) {
00379                 glPixelStorei( GL_UNPACK_ROW_LENGTH, oldGlRowLen );
00380         }       
00381         return true;
00382 }
00383 
00384 #endif   // RGBIMAGE_DONT_USE_OPENGL
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Defines