Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Bmp.cpp

Go to the documentation of this file.
00001 //  ======================================================================== //
00002 //                                                                           //
00003 //    File      : Bmp.cpp                                                    //
00004 //    Purpose   :                                                            //
00005 //    Time-stamp: <Fri Nov/29/2002 13:45 MET Coder@ReallySoft.de>            //
00006 //                                                                           //
00007 //    (C) February 2002 by Ralf Westram                                      //
00008 //                                                                           //
00009 //    Permission to use, copy, modify, distribute and sell this software     //
00010 //    and its documentation for any purpose is hereby granted without fee,   //
00011 //    provided that the above copyright notice appear in all copies and      //
00012 //    that both that copyright notice and this permission notice appear      //
00013 //    in supporting documentation.                                           //
00014 //                                                                           //
00015 //    Ralf Westram makes no representations about the suitability of this    //
00016 //    software for any purpose.  It is provided "as is" without express or   //
00017 //    implied warranty.                                                      //
00018 //                                                                           //
00019 //  ======================================================================== //
00020 
00021 #include "Bmp.h"
00022 
00023 #include <cstdio>
00024 #include <Err.h>
00025 #include <Tools.h>
00026 
00027 
00028 using namespace std;
00029 using namespace rs;
00030 using namespace rs::err;
00031 using namespace rs::str;
00032 
00033 // start of implementation of class Pixel:
00034 
00035 unsigned char Pixel::transparent_red       = 0;
00036 unsigned char Pixel::transparent_green     = 0;
00037 unsigned char Pixel::transparent_blue      = 0;
00038 bool          Pixel::use_transparent_color = false;
00039 
00040 // -------------------------------------------------------------------------------------------------------
00041 //      void Pixel::defineTransparentColor(unsigned char red, unsigned char green, unsigned char blue)
00042 // -------------------------------------------------------------------------------------------------------
00043 void Pixel::defineTransparentColor(unsigned char red, unsigned char green, unsigned char blue)
00044 {
00045     transparent_red   = red;
00046     transparent_blue  = blue;
00047     transparent_green = green;
00048 }
00049 
00050 // -end- of implementation of class Pixel.
00051 
00052 // start of implementation of class Bmp:
00053 
00054 #define BUFFERSIZE 20
00055 // #define VERBOSE
00056 
00057 // -----------------------------------------------
00058 //      Bmp::Bmp(size_t xsize_, size_t ysize_)
00059 // -----------------------------------------------
00060 Bmp::Bmp(size_t xsize_, size_t ysize_)
00061     : loaded_from_file("")
00062     , xsize(xsize_)
00063     , ysize(ysize_)
00064     , offset_per_line(xsize*3)
00065 {
00066     hassert(xsize>0 && ysize>0);
00067 
00068     size_t datasize = ysize*offset_per_line;
00069 
00070     data = new unsigned char[datasize];
00071     memset(data, 0, datasize);
00072 }
00073 
00074 // -----------------------------------
00075 //      Bmp::Bmp(const Bmp& other)
00076 // -----------------------------------
00077 Bmp::Bmp(const Bmp& other)
00078     : loaded_from_file(other.loaded_from_file)
00079     , xsize(other.xsize)
00080     , ysize(other.ysize)
00081     , offset_per_line(other.offset_per_line)
00082 {
00083 
00084     size_t datasize = ysize*offset_per_line;
00085 
00086     data = new unsigned char[datasize];
00087     memcpy(data, other.data, datasize);
00088 }
00089 
00090 // -------------------------------------------------
00091 //      Bmp& Bmp::operator = (const Bmp& other)
00092 // -------------------------------------------------
00093 Bmp& Bmp::operator = (const Bmp& other) {
00094     if (this != &other) {
00095         delete data;
00096 
00097         loaded_from_file = other.loaded_from_file;
00098         xsize            = other.xsize;
00099         ysize            = other.ysize;
00100         offset_per_line  = other.offset_per_line;
00101 
00102         size_t datasize = ysize*offset_per_line;
00103 
00104         data = new unsigned char[datasize];
00105         memcpy(data, other.data, datasize);
00106     }
00107 
00108     return *this;
00109 }
00110 
00111 // ----------------------------------------------
00112 //      Bmp::Bmp(const std::string& filename)
00113 // ----------------------------------------------
00114 Bmp::Bmp(const std::string& filename)
00115 {
00116     assert(sizeof(UINT32) == 4);
00117     assert(sizeof(UINT16) == 2);
00118 
00119     data = 0;
00120 
00121     cout << "Reading " << filename << "\n";
00122 
00123     FILE *in = fopen(filename.c_str(), "rb");
00124     if (!in) throw IOError(filename);
00125 
00126     loaded_from_file = filename;
00127 
00128     char   buffer[BUFFERSIZE];
00129     size_t read;
00130 
00131 #define fill_buffer(x) do{                      \
00132         read = fread(buffer, 1, x, in);         \
00133         assert(read<BUFFERSIZE);                \
00134         if (read != x) throw IOError(filename); \
00135         buffer[x] = 0;                          \
00136     }while(0)
00137 
00138     try {
00139         // -------------------------
00140         //      BITMAPFILEHEADER
00141         // -------------------------
00142         fill_buffer(2);
00143         if (strcmp(buffer, "BM") != 0) {
00144             wrong_format :
00145             throw Error("Expected Windows-BMP Format");
00146         }
00147         fill_buffer(4); UINT32 size = *(UINT32*)buffer; // filesize
00148 
00149         fill_buffer(2); if (buffer[0] || buffer[1]) goto wrong_format; // reserved1
00150         fill_buffer(2); if (buffer[0] || buffer[1]) goto wrong_format; // reserved2
00151 
00152         fill_buffer(4); UINT32 offset = *(UINT32*)buffer; // bitmap offset
00153 
00154 #if defined(VERBOSE)
00155         cout << "size=" << size << " ";
00156         cout << "offset=" << offset << " ";
00157         cout << "\n";
00158 #endif // VERBOSE
00159 
00160         // -------------------------
00161         //      BITMAPINFOHEADER
00162         // -------------------------
00163 
00164         fill_buffer(4); UINT32 infoSize        = *(UINT32*)buffer;
00165         fill_buffer(4); xsize                  = *(UINT32*)buffer;
00166         fill_buffer(4); ysize                  = *(UINT32*)buffer;
00167         fill_buffer(2); UINT16 planes          = *(UINT16*)buffer;
00168         fill_buffer(2); UINT16 bitsPerPixel    = *(UINT16*)buffer;
00169         fill_buffer(4); UINT32 compression     = *(UINT32*)buffer;
00170         fill_buffer(4); UINT32 dataSize        = *(UINT32*)buffer;
00171         fill_buffer(4); UINT32 X_pixPerMeter   = *(UINT32*)buffer;
00172         fill_buffer(4); UINT32 Y_pixPerMeter   = *(UINT32*)buffer;
00173         fill_buffer(4); UINT32 colorsUsed      = *(UINT32*)buffer;
00174         fill_buffer(4); UINT32 colorsImportant = *(UINT32*)buffer;
00175 
00176         USE(colorsImportant);
00177         USE(colorsUsed);
00178         USE(X_pixPerMeter);
00179         USE(Y_pixPerMeter);
00180         USE(infoSize);
00181         USE(size);
00182         USE(dataSize);
00183 
00184 #if defined(VERBOSE)
00185         cout << "infoSize=" << infoSize << " ";
00186         cout << "xsize=" << xsize << " ";
00187         cout << "ysize=" << ysize << " ";
00188         cout << "\n";
00189         cout << "planes=" << planes << " ";
00190         cout << "bitsPerPixel=" << bitsPerPixel << " ";
00191         cout << "compression=" << compression << " ";
00192         cout << "dataSize=" << dataSize << " ";
00193         cout << "\n";
00194         cout << "X_pixPerMeter=" << X_pixPerMeter << " ";
00195         cout << "Y_pixPerMeter=" << Y_pixPerMeter << " ";
00196         cout << "\n";
00197         cout << "colorsUsed=" << colorsUsed << " ";
00198         cout << "colorsImportant=" << colorsImportant << " ";
00199         cout << "\n";
00200 #endif // VERBOSE
00201 
00202         if (planes != 1 || bitsPerPixel != 24) throw Error("Can only read 24-bit graphics");
00203         if (compression != 0) throw Error("Can't read compressed BMPs");
00204 
00205         if (fseek(in, offset, SEEK_SET) != 0) throw IOError(filename);
00206 
00207         offset_per_line = 3*xsize;
00208         data            = new unsigned char[offset_per_line*ysize];
00209 
00210         size_t file_offset_per_line = ((offset_per_line-1)/4+1)*4;
00211         size_t xtra_offset          = file_offset_per_line-offset_per_line;
00212 
00213 #if defined(VERBOSE)
00214         cout << "offset_per_line=" << offset_per_line << " ";
00215         cout << "file_offset_per_line=" << file_offset_per_line << " ";
00216         cout << "offset_per_line*ysize=" << offset_per_line*ysize << " ";
00217         cout << "\n";
00218 #endif // VERBOSE
00219         assert(dataSize == 0 || dataSize == (file_offset_per_line*ysize));
00220 
00221         {
00222             unsigned char *lineStart = data+(ysize-1)*offset_per_line;
00223             int            lines     = ysize;
00224 
00225             while (lines--) {
00226                 size_t bytes = fread(lineStart, 1, offset_per_line, in);
00227 //                 cout << "read: offset_per_line=" << offset_per_line << " bytes=" << bytes << endl;
00228                 if (bytes != offset_per_line) throw IOError(filename);
00229 
00230                 if (xtra_offset>0) fill_buffer(xtra_offset);
00231 
00232                 lineStart -= offset_per_line;
00233             }
00234         }
00235 
00236 #if defined(VERBOSE)
00237         cout << filename << " in memory!\n";
00238 #endif // VERBOSE
00239     }
00240 //     catch (IOError& err) {
00241 //         throw;
00242 //     }
00243     catch (Error& err) {
00244         throw Error(string("While reading ")+filename+": "+err.what());
00245     }
00246     fclose(in);
00247 #if defined(VERBOSE)
00248     cout << "--\n";
00249 #endif // VERBOSE
00250 }
00251 
00252 // ----------------------------------------------------------------------------
00253 //      inline void write_buffer(const char *buf, size_t bytes, FILE *out)
00254 // ----------------------------------------------------------------------------
00255 inline void write_buffer(const char *buf, size_t bytes, FILE *out) {
00256     size_t wrote = fwrite(buf, 1, bytes, out);
00257     if (wrote != bytes) throw IOError("write");
00258 }
00259 
00260 inline void write_UINT32(UINT32 ui, FILE *out) { write_buffer((char*)&ui, sizeof(ui), out); }
00261 inline void write_UINT16(UINT16 ui, FILE *out) { write_buffer((char*)&ui, sizeof(ui), out); }
00262 
00263 // ------------------------------------------------------------
00264 //      void Bmp::saveAs(const std::string& filename) const
00265 // ------------------------------------------------------------
00266 void Bmp::saveAs(const std::string& filename) const
00267 {
00268     cout << "Saving " << filename << "\n";
00269     FILE *out = fopen(filename.c_str(), "wb");
00270     if (!out) throw IOError(filename);
00271 
00272     try {
00273         // --------------------------
00274         //      BITMAPFILEHEADER:
00275         // --------------------------
00276 
00277         write_buffer("BM", 2, out); // filetype
00278         write_UINT32(0, out);   // file-size (@@@ calc!)
00279         write_UINT16(0, out);   // reserved1
00280         write_UINT16(0, out);   // reserved2
00281         write_UINT32(54, out);  // offset to bitmapstart
00282 
00283         // ----------------------------------
00284         //      BITMAPINFOHEADER:
00285         // ----------------------------------
00286 
00287         write_UINT32(40, out);  // size of BITMAPINFOHEADER
00288         write_UINT32(Xsize(), out); // xsize of bitmap
00289         write_UINT32(Ysize(), out); // ysize of bitmap
00290         write_UINT16(1, out);   // all data in one plane
00291         write_UINT16(24, out);   // 24-bit per pixel
00292         write_UINT32(0, out);   // no compression
00293         write_UINT32(0, out);   // size of compressed data
00294         write_UINT32(0, out);   // X_pixPerMeter
00295         write_UINT32(0, out);   // Y_pixPerMeter
00296         write_UINT32(0, out);   // colors used
00297         write_UINT32(0, out);   // colors important
00298 
00299         // ------------------
00300         //      bitmap :
00301         // ------------------
00302 
00303 
00304         {
00305             unsigned char *lineStart            = data+(ysize-1)*offset_per_line;
00306             int            lines                = ysize;
00307             size_t         file_offset_per_line = ((offset_per_line-1)/4+1)*4;
00308             size_t         xtra_offset          = file_offset_per_line-offset_per_line;
00309             char           xtra_buffer[4];
00310 
00311             for (int x = 0; x<4; ++x) xtra_buffer[x] = 0;
00312 
00313             while (lines--) {
00314                 size_t bytes = fwrite(lineStart, 1, offset_per_line, out);
00315 //                 cout << "read: offset_per_line=" << offset_per_line << " bytes=" << bytes << endl;
00316                 if (bytes != offset_per_line) throw IOError(filename);
00317 
00318                 if (xtra_offset>0) write_buffer(xtra_buffer, xtra_offset, out);
00319 
00320                 lineStart -= offset_per_line;
00321             }
00322         }
00323 
00324     }
00325     catch (Error& err) {
00326         throw Error(string("While writing ")+filename+": "+err.what());
00327     }
00328 
00329     fclose(out);
00330 }
00331 
00332 // -----------------------------------------
00333 //      void Bmp::throw_wrong_pix_pos()
00334 // -----------------------------------------
00335 void Bmp::throw_wrong_pix_pos()
00336 {
00337     throw InternalError("Pixel position outside bitmap");
00338 }
00339 
00340 // -end- of implementation of class Bmp.
00341 
00342 namespace rs {
00343     // --------------------------------------
00344     //      Bmp *halfBmp(const Bmp& bmp)
00345     // --------------------------------------
00346     Bmp *halfBmp(const Bmp& bmp) {
00347         int  hx   = bmp.Xsize()/2;
00348         int  hy   = bmp.Ysize()/2;
00349         Bmp *half = new Bmp(hx, hy);
00350 
00351         for (int x = 0; x<hx; ++x) {
00352             int x2 = x+x;
00353             for (int y = 0; y<hy; ++y) {
00354                 int   y2 = y+y;
00355                 Pixel p[4];
00356                 p[0]     = bmp.getPixel(x2, y2);
00357                 p[1]     = bmp.getPixel(x2+1, y2);
00358                 p[2]     = bmp.getPixel(x2+1, y2+1);
00359                 p[3]     = bmp.getPixel(x2, y2+1);
00360 
00361                 int new_value[3];
00362                 for (int c = 0; c<3; ++c) { // for all 3 colors
00363                     new_value[c] = 2; // this is equiv to round 'new_value[c]/4'
00364                     for (int pix = 0; pix<4; ++pix) { // of all 4 pixels
00365                         new_value[c] += p[pix].color(c); // build colors-sums
00366                     }
00367                 }
00368 
00369                 half->setPixel(x, y, new_value[0]/4, new_value[1]/4, new_value[2]/4);
00370             }
00371         }
00372 
00373         return half;
00374     }
00375 };
00376 

Contact me in case of errors or questions.
This documentation is powered by Doxygen.
(C) 2000-2002 Doxygen