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 . |
(C) 2000-2002 |