00001
00011 #pragma once
00012
00013 #include "standard.h"
00014
00015
00016 #pragma warning (push, 3)
00017 #include <vector>
00018 #include <string>
00019 #include <algorithm>
00020 #include <limits>
00021 #pragma warning (pop)
00022
00023 #include "MatrixTypes.h"
00024
00025 template< typename T >
00026 class typeTest
00027 { public: enum {isFloat = 0}; enum {isDouble = 0}; };
00028
00029 template<>
00030 class typeTest< float >
00031 { public: enum {isFloat = 1}; enum {isDouble = 0}; };
00032
00033 template<>
00034 class typeTest< double >
00035 { public: enum {isFloat = 0}; enum {isDouble = 1}; };
00036
00037
00040 typedef struct
00041 {
00043 char magicNumber;
00044
00046 int width;
00047
00049 int height;
00050
00052 bool bAscii;
00053
00055 double maximum;
00056
00058 int numChannels;
00059
00060 } PictureHeaderInfo;
00061
00062 char *fileErrorString(FILE *fp, const char *filename, const char *function_name);
00063 std::string getNextLine(FILE *fp, const char *filename);
00064 void removeFirstToken(std::string &str);
00065 PictureHeaderInfo readHeader(FILE *fp, const char *filename);
00066 void readBinaryBytes (FILE *fp, const char *filename, PictureHeaderInfo info, std::vector< RgbByte > &picture);
00067 void readBinaryFloats(FILE *fp, const char *filename, PictureHeaderInfo info, std::vector< RgbFloat > &picture);
00068 void readAscii (FILE *fp, const char *filename, PictureHeaderInfo info, std::vector< RgbByte > &picture);
00069
00070
00074 class File
00075 {
00076 public:
00077
00078 File() { fp = NULL; }
00079
00080 void openForWriting(const char *filename)
00081 {
00082 fp = fopen(filename, "wb");
00083 if (!fp) throw DiskError(fp, "File::openForWriting()");
00084 }
00085 void openForReading(const char *filename)
00086 {
00087 fp = fopen(filename, "rb");
00088 if (!fp) throw DiskError (fp, "File::openForReading()");
00089 }
00090
00091 ~File() { if (fp) fclose(fp); }
00092
00093 FILE *fp;
00094
00095 };
00096
00097
00098 #define PBM_ASCII '1'
00099 #define PGM_ASCII '2'
00100 #define PPM_ASCII '3'
00101 #define PBM_BINARY '4'
00102 #define PGM_BINARY '5'
00103 #define PPM_BINARY '6'
00104 #define PFM_BINARY 'F'
00105
00106
00107
00108
00114 template< typename T >
00115 class PortablePicture
00116 {
00117 typedef RgbColor< T > ColorType;
00118
00119 public:
00120
00122 PortablePicture()
00123 {
00124 width = 0;
00125 height = 0;
00126 }
00127
00129 PortablePicture(int width_in, int height_in)
00130 {
00131 width = width_in;
00132 height = height_in;
00133 colorBuffer.resize(width*height);
00134 }
00135
00136
00141 void getRange (T &our_min, T &our_max)
00142 {
00143 if (typeTest< T >::isFloat || typeTest< T >::isDouble)
00144 {
00145 our_min = (T)0.;
00146 our_max = (T)1.;
00147 }
00148 else
00149 {
00150 our_min = std::numeric_limits< T >::min();
00151 our_max = std::numeric_limits< T >::max();
00152 }
00153 }
00154
00155
00161 void loadFile (const char *filename)
00162 {
00163 if (strlen(filename) < 4)
00164 throw Error("PortableFloatMap::saveAs(): extension not supported.");
00165
00166
00167 std::string ext = filename + strlen(filename) - 4;
00168
00169 if (!(ext == ".pfm" ||
00170 ext == ".ppm" ||
00171 ext == ".pgm"))
00172 {
00173 PortablePicture< unsigned char > pixmap;
00174 loadBits (filename, pixmap);
00175 T our_min, our_max;
00176 getRange (our_min, our_max);
00177
00178 width = pixmap.getWidth();
00179 height = pixmap.getHeight();
00180 colorBuffer.resize (pixmap.getWidth() * pixmap.getHeight());
00181 copyData(pixmap.colorBuffer, 0, 255, our_min, our_max, colorBuffer);
00182 return;
00183 }
00184
00185
00186 assert(filename);
00187 File f;
00188
00189 f.openForReading(filename);
00190
00191
00192 PictureHeaderInfo header = readHeader(f.fp, filename);
00193
00194
00195 std::vector< ColorType > picture;
00196
00197 readPixels (
00198 f.fp,
00199 filename,
00200 header,
00201 picture);
00202
00203
00204
00205 width = header.width;
00206 height = header.height;
00207 colorBuffer = picture;
00208 }
00209
00211 void setDimensions (int width_in, int height_in)
00212 {
00213 if (width_in <= 0 || height_in <= 0)
00214 throw ArgError("PortablePicture::setDimensions(): the width and height must be >= 0.");
00215
00216 width = width_in;
00217 height = height_in;
00218
00219 colorBuffer.resize(width*height);
00220
00221
00222 memset(&colorBuffer[0], 0, sizeof(ColorType) * width * height);
00223 }
00224
00225
00227 int getWidth() const { return width; }
00228
00230 int getHeight() const { return height; }
00231
00232
00233
00234 T getMaxColor() const
00235 {
00236 T theMax = 0;
00237 for (unsigned int i = 0; i < colorBuffer.size(); i++)
00238 {
00239 theMax = MAX (theMax, colorBuffer[i].r());
00240 theMax = MAX (theMax, colorBuffer[i].g());
00241 theMax = MAX (theMax, colorBuffer[i].b());
00242 }
00243 return theMax;
00244 }
00245
00246
00247
00249 ColorType getInterpolated (float y, float x) const
00250 {
00251 assert (y <= getHeight() - 1);
00252 assert (x <= getWidth() - 1);
00253
00254
00255 int xLower = (int)MAX(floor(x), 0);
00256 int xUpper = (int)MIN(ceil(x),getWidth()-1);
00257
00258 int yLower = (int)MAX(floor(y), 0);
00259 int yUpper = (int)MIN(ceil(y),getHeight()-1);
00260
00261 double pctX = x - xLower;
00262 double pctY = y - yLower;
00263
00264 PortablePicture< T > & pp = const_cast< PortablePicture< T >& >(*this);
00265 ColorType & aColor = pp[yUpper][xLower];
00266 ColorType & bColor = pp[yUpper][xUpper];
00267 ColorType & cColor = pp[yLower][xLower];
00268 ColorType & dColor = pp[yLower][xUpper];
00269
00270 ColorType ab;
00271 ab = aColor*(1-pctX) + bColor*(pctX);
00272 ColorType cd;
00273 cd = cColor*(1-pctX) + dColor*(pctX);
00274
00275 ColorType abcd;
00276 abcd = ab*(pctY) + cd*(1-pctY);
00277
00278 return abcd;
00279 }
00280
00281
00282
00284 ColorType at (unsigned int y, unsigned int x) const
00285 {
00286 return colorBuffer[width*y + x];
00287 }
00288
00289
00291 ColorType * operator[] (int row) { return &colorBuffer[width*row]; }
00292
00293
00299 void saveAs (const char *filename) const
00300 {
00301 if (strlen(filename) < 4)
00302 throw ArgError("PortablePicture::saveAs(): extension not supported.");
00303
00304
00305 std::string ext = filename + strlen(filename) - 4;
00306
00307 if (!(ext == ".pfm" ||
00308 ext == ".ppm" ||
00309 ext == ".pgm"))
00310 {
00311 throw ArgError("PortableFloatMap::saveAs(): unsupported file type. Supported types are .ppm, .pgm, and .pfm.");
00312 }
00313
00314 File f;
00315 f.openForWriting (filename);
00316
00317 if (ext == ".pfm")
00318 {
00319 writeHeader(f.fp, "PF", "-1.0000", getWidth(), getHeight(), filename);
00320
00321 if (colorBuffer.size() != fwrite(&colorBuffer[0], sizeof(colorBuffer[0]), colorBuffer.size(), f.fp))
00322 throw DiskError(f.fp, "PortableFloatMap::saveAs");
00323
00324 return;
00325 }
00326
00327 bool bIsPixmap = (ext == ".ppm");
00328 char *magicNumber;
00329
00330 if (bIsPixmap)
00331 magicNumber = "P6";
00332 else
00333 magicNumber = "P5";
00334
00335 writeHeader(f.fp,
00336 magicNumber,
00337 "255",
00338 getWidth(), getHeight(),
00339 filename);
00340
00341 T our_min, our_max;
00342
00343 if (typeTest< T >::isFloat || typeTest< T >::isDouble)
00344 {
00345 our_min = (T)0.;
00346 our_max = (T)1.;
00347 }
00348 else
00349 {
00350 our_min = std::numeric_limits< T >::min();
00351 our_max = std::numeric_limits< T >::max();
00352 }
00353
00354
00355 for (int row = getHeight()-1; row >= 0; row--)
00356 {
00357 for (int col = 0; col < getWidth(); col++)
00358 {
00359 const ColorType & curColor = colorBuffer[row*getWidth()+col];
00360
00361 RgbByte newColor;
00362 newColor.r() = (unsigned char)RESCALE(curColor.r(), our_min, our_max, 0, 255);
00363 newColor.g() = (unsigned char)RESCALE(curColor.g(), our_min, our_max, 0, 255);
00364 newColor.b() = (unsigned char)RESCALE(curColor.b(), our_min, our_max, 0, 255);
00365 if (bIsPixmap)
00366 {
00367 fputc(newColor.r(), f.fp);
00368 fputc(newColor.g(), f.fp);
00369 fputc(newColor.b(), f.fp);
00370 }
00371 else
00372 {
00373 fputc((newColor.r()+newColor.g()+newColor.b())/3, f.fp);
00374 }
00375 }
00376 }
00377 }
00378
00379
00380
00382 std::vector< ColorType > colorBuffer;
00383
00384 private:
00385 int width;
00386 int height;
00387
00388
00389 template< typename N >
00390 void copyData (std::vector< RgbColor< N > > &data, double their_min, double their_max, T our_min, T our_max, std::vector< ColorType > &picture)
00391 {
00392 for (int row = 0; row < height; row++)
00393 {
00394 for (int col = 0; col < width; col++)
00395 {
00396 unsigned int index = row*width+col;
00397
00398 ColorType color;
00399
00400 color[0] = (T)RESCALE(data[index][0], their_min, their_max, our_min, our_max);
00401 color[1] = (T)RESCALE(data[index][1], their_min, their_max, our_min, our_max);
00402 color[2] = (T)RESCALE(data[index][2], their_min, their_max, our_min, our_max);
00403 picture[index] = color;
00404 }
00405 }
00406 }
00407
00408
00409
00421 void writeHeader (FILE *f, const char *magicNumber, const char *maxNumber, int width, int height, const char *filename) const
00422 {
00423 if (0 >= fprintf(f, "%s\n%d %d\n%s%s",
00424 magicNumber,
00425 width, height,
00426 maxNumber?maxNumber:"",
00427 maxNumber?"\n":""))
00428 {
00429 throw DiskError (f, "PortablePicture::saveAs()");
00430 }
00431 }
00432
00433
00434
00443 void readPixels (FILE *fp, const char *filename, PictureHeaderInfo info, std::vector< ColorType > & picture)
00444 {
00445 picture.resize(info.height * info.width);
00446 width = info.width;
00447 height = info.height;
00448
00449 T our_min, our_max;
00450
00451 getRange (our_min, our_max);
00452
00453 if (info.magicNumber == PFM_BINARY)
00454 {
00455
00456 if (typeTest< T >::isFloat)
00457 {
00458 if (picture.size() != (int)fread(&picture[0], sizeof(ColorType), picture.size(), fp))
00459 throw fileErrorString(fp, filename, "readPixels()");
00460 return;
00461 }
00462
00463
00464 std::vector< RgbFloat > floatPicture;
00465 readBinaryFloats (fp, filename, info, floatPicture);
00466
00467 copyData(floatPicture, 0, info.maximum, our_min, our_max, picture);
00468 return;
00469 }
00470
00471 std::vector< RgbByte > bytePicture;
00472 if (info.bAscii)
00473 readAscii (fp, filename, info, bytePicture);
00474 else
00475 readBinaryBytes (fp, filename, info, bytePicture);
00476
00477 copyData(bytePicture, 0, info.maximum, our_min, our_max, picture);
00478 }
00479 };
00480
00481
00482
00483
00485 typedef PortablePicture< float > PortableFloatMap;
00486
00488 typedef PortablePicture< unsigned char > PortablePixMap;
00489
00490 void loadBits (const char *filename, PortablePixMap &p);