00001 #include "puma2config.h"
00002 #include "ImageWriter.h"
00003 #include "PumaException.h"
00004 #include "PumaMessages.h"
00005
00006 #include <cstdio>
00007 #include <cerrno>
00008 #include <cstring>
00009
00010 using namespace std;
00011 using namespace puma2;
00012
00013 #ifdef HAVE_IMAGEMAGICK
00014 # include <Magick++/Image.h>
00015 static bool writeImageGrayMagick(const GrayLevelImage8 &img, string filename);
00016 static bool writeImageGrayMagick(const GrayLevelImage16 &img, string filename);
00017 static bool writeImageColorMagick(const ColorImageRGB8 &img, string filename);
00018 static bool writeImageColorMagick(const ColorImageRGBa8 &img, string filename);
00019 #endif
00020
00021
00022 static bool writeImageGrayBuiltinPNM(const GrayLevelImage8 &img, string &filename);
00023 static bool writeImageColorBuiltinPNM(const ColorImageRGB8 &img, string &filename);
00024 #define USE_BUILTIN_PNM_WRITER 1
00025
00026
00027 bool ImageWriter::writeImage(const GrayLevelImage8 &img, string filename)
00028 {
00029 bool success = false;
00030
00031 #ifdef USE_BUILTIN_PNM_WRITER
00032 int slen = filename.length();
00033 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00034 || (filename.compare(slen-4, 4, ".pgm") == 0)
00035 || (filename.compare(slen-4, 4, ".ppm") == 0)
00036 || (filename.compare(slen-4, 4, ".pnm") == 0)) {
00037 success = writeImageGrayBuiltinPNM(img, filename);
00038 }
00039 #endif
00040
00041 #ifdef HAVE_IMAGEMAGICK
00042 if (! success) {
00043 success = writeImageGrayMagick(img, filename);
00044 }
00045 #endif
00046 if (! success) {
00047 string msg ("failed to write file.");
00048 throw PumaException(PumaException::intolerable, msg);
00049 success = false;
00050 }
00051 return success;
00052 }
00053
00054 bool ImageWriter::writeImage(const GrayLevelImage16 &img, string filename)
00055 {
00056 bool success = false;
00057
00058 #ifdef HAVE_IMAGEMAGICK
00059 if (! success) {
00060 success = writeImageGrayMagick(img, filename);
00061 }
00062 #endif
00063 if (! success) {
00064 string msg ("failed to write file.");
00065 throw PumaException(PumaException::intolerable, msg);
00066 success = false;
00067 }
00068 return success;
00069 }
00070
00071 bool ImageWriter::writeImage(const ColorImageRGB8 &img, string filename)
00072 {
00073 bool success = false;
00074
00075 #ifdef USE_BUILTIN_PNM_WRITER
00076 int slen = filename.length();
00077 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00078 || (filename.compare(slen-4, 4, ".pgm") == 0)
00079 || (filename.compare(slen-4, 4, ".ppm") == 0)
00080 || (filename.compare(slen-4, 4, ".pnm") == 0)) {
00081 success = writeImageColorBuiltinPNM(img, filename);
00082 }
00083 #endif
00084
00085 #ifdef HAVE_IMAGEMAGICK
00086 if (! success) {
00087 success = writeImageColorMagick(img, filename);
00088 }
00089 #endif
00090 if (! success) {
00091 string msg ("failed to write file.");
00092 throw PumaException(PumaException::intolerable, msg);
00093 success = false;
00094 }
00095 return success;
00096 }
00097
00098 bool ImageWriter::writeImage(const ColorImageRGBa8 &img, string filename)
00099 {
00100 bool success = false;
00101
00102 #ifdef USE_BUILTIN_PNM_WRITER_NOAPLHAINPNM
00103 int slen = filename.length();
00104 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00105 || (filename.compare(slen-4, 4, ".pgm") == 0)
00106 || (filename.compare(slen-4, 4, ".ppm") == 0)
00107 || (filename.compare(slen-4, 4, ".pnm") == 0)) {
00108 success = writeImageColorBuiltinPNM(img, filename);
00109 }
00110 #endif
00111
00112 #ifdef HAVE_IMAGEMAGICK
00113 if (! success) {
00114 success = writeImageColorMagick(img, filename);
00115 }
00116 #endif
00117 if (! success) {
00118 string msg ("failed to write file.");
00119 throw PumaException(PumaException::intolerable, msg);
00120 success = false;
00121 }
00122 return success;
00123 }
00124
00125
00126
00127
00128
00129 static bool writeImageGrayBuiltinPNM(const GrayLevelImage8 &img, string &filename)
00130 {
00131 FILE *filePointer = fopen (filename.c_str(), "wb");
00132 if (filePointer == NULL) {
00133 string msg ("cannot write to file: ");
00134 msg += filename;
00135 msg += strerror(errno);
00136 throw PumaException(PumaException::intolerable, msg);
00137 return false;
00138 }
00139
00140 bool success = true;
00141 int wid = img.getWidth();
00142 int hig = img.getHeight();
00143 char outputMode = filename[filename.length()-2];
00144 int valMax = int(img.getValueRangeMaximum());
00145 int depth = 255;
00146 int denominator = 1;
00147 int bytesPerRow, bytesWritten = 0;
00148 if (valMax < 255) {
00149 depth = valMax;
00150 assert (valMax > 0);
00151 }
00152 else {
00153 denominator = valMax / 255;
00154 assert (valMax == 255);
00155 }
00156 switch (outputMode) {
00157 case 'g':
00158 case 'G':
00159 case 'n':
00160 case 'N':
00161 {
00162 fprintf (filePointer, "P5\n%d %d\n%d\n", wid, hig, depth);
00163
00164
00165 const GrayLevelImage8::ElementType **ptr = img.unsafeRowPointerArray();
00166 for (int y = 0; y < hig; y++) {
00167 bytesWritten += fwrite (ptr[y], 1, wid, filePointer);
00168 }
00169 }
00170 break;
00171
00172 case 'p':
00173 case 'P':
00174 {
00175 fprintf (filePointer, "P6\n%d %d\n%d\n", wid, hig, depth);
00176 const GrayLevelImage8::ElementType **ptr = img.unsafeRowPointerArray();
00177 for (int y = 0; y < hig; y++) {
00178 const GrayLevelImage8::ElementType *linePtr = ptr[y];
00179 for (int x = 0; x < wid; x++) {
00180
00181 byte val = *linePtr++ / denominator;
00182 putc(val, filePointer);
00183 putc(val, filePointer);
00184 putc(val, filePointer);
00185 }
00186 bytesWritten += 3 * wid;
00187 }
00188 }
00189 break;
00190
00191 case 'b':
00192 case 'B':
00193 {
00194 fprintf (filePointer, "P4\n%d %d\n", wid, hig);
00195 denominator = (valMax + 1) / 2;
00196 bytesPerRow = (wid + 7) / 8;
00197 byte bitRow[bytesPerRow+10];
00198 const GrayLevelImage8::ElementType **ptr = img.unsafeRowPointerArray();
00199 for (int y = 0; y < hig; y++) {
00200 const GrayLevelImage8::ElementType *linePtr = ptr[y];
00201 byte *bitPtr = bitRow;
00202 byte curByte = 0;
00203 int x;
00204 for (x = 0; x < wid; x++) {
00205
00206 curByte <<= 1;
00207 int val = (unsigned(*linePtr++) / denominator);
00208 curByte |= (val > 0) ? 0 : 1;
00209 if ((x & 0x07) == 7) {
00210 *bitPtr++ = curByte;
00211 curByte = 0;
00212 }
00213 }
00214 if ((x & 0x07) != 0) {
00215 curByte <<= (8 - (x & 0x07));
00216 *bitPtr++ = curByte;
00217 }
00218 bytesWritten += fwrite (bitRow, 1, bytesPerRow, filePointer);
00219 }
00220 }
00221 break;
00222
00223 default:
00224
00225 success = false;
00226 break;
00227 }
00228 fclose (filePointer);
00229 return success;
00230 }
00231
00232 static bool writeImageColorBuiltinPNM(const ColorImageRGB8 &img, string &filename)
00233 {
00234 FILE *filePointer = fopen (filename.c_str(), "wb");
00235 if (filePointer == NULL) {
00236 string msg ("cannot write to file: ");
00237 msg += filename;
00238 msg += strerror(errno);
00239 throw PumaException(PumaException::intolerable, msg);
00240 return false;
00241 }
00242
00243 bool success = true;
00244 int wid = img.getWidth();
00245 int hig = img.getHeight();
00246 char outputMode = filename[filename.length()-2];
00247 int valMax = int(img.getValueRangeMaximum());
00248 int depth = 255;
00249 int denominator = 1;
00250 int bytesWritten = 0;
00251 if (valMax < 255) {
00252 depth = valMax;
00253 assert (valMax > 0);
00254 }
00255 else {
00256 denominator = valMax / 255;
00257 assert (valMax == 255);
00258 }
00259 switch (outputMode) {
00260 case 'g':
00261 case 'G':
00262 {
00263 denominator *= 1000;
00264 fprintf (filePointer, "P5\n%d %d\n%d\n", wid, hig, depth);
00265
00266
00267 const ColorImageRGB8::PixelType **ptr = img.unsafeRowPointerArray();
00268 for (int y = 0; y < hig; y++) {
00269 const ColorImageRGB8::ElementType *linePtr = (ColorImageRGB8::ElementType*)(ptr[y]);
00270 for (int x = 0; x < wid; x++) {
00271 int val = 299 * *linePtr++;
00272 val += 587 * *linePtr++;
00273 val += 114 * *linePtr++;
00274 putc(val / denominator, filePointer);
00275 }
00276 bytesWritten += wid;
00277 }
00278 }
00279 break;
00280
00281 case 'p':
00282 case 'P':
00283 case 'n':
00284 case 'N':
00285 {
00286 fprintf (filePointer, "P6\n%d %d\n%d\n", wid, hig, depth);
00287 const ColorImageRGB8::PixelType **ptr = img.unsafeRowPointerArray();
00288 for (int y = 0; y < hig; y++) {
00289
00290
00291 bytesWritten += fwrite (ptr[y], 1, wid * 3, filePointer);
00292 }
00293 }
00294 break;
00295
00296 case 'b':
00297 case 'B':
00298 {
00299 fprintf (filePointer, "P4\n%d %d\n", wid, hig);
00300 denominator = (valMax + 1) / 2;
00301 denominator *= 1000;
00302 const ColorImageRGB8::PixelType **ptr = img.unsafeRowPointerArray();
00303 for (int y = 0; y < hig; y++) {
00304 const ColorImageRGB8::ElementType *linePtr = (ColorImageRGB8::ElementType*)(ptr[y]);
00305 int bytesPerRow = (wid + 7) / 8;
00306 byte bitRow[bytesPerRow];
00307 byte *bitPtr = bitRow;
00308 byte curByte = 0;
00309 int x;
00310 for (x = 0; x < wid; x++) {
00311
00312 curByte <<= 1;
00313 int val = 299 * *linePtr++;
00314 val += 587 * *linePtr++;
00315 val += 114 * *linePtr++;
00316 curByte |= ((val / denominator) > 0) ? 0 : 1;
00317 if ((x & 0x07) == 7) {
00318 *bitPtr++ = curByte;
00319 curByte = 0;
00320 }
00321 }
00322 if ((x & 0x07) != 0) {
00323 curByte <<= (8 - (x & 0x07));
00324 *bitPtr++ = curByte;
00325 }
00326 bytesWritten += fwrite (bitRow, 1, bytesPerRow, filePointer);
00327 }
00328 }
00329 break;
00330
00331 default:
00332
00333 success = false;
00334 break;
00335 }
00336 fclose (filePointer);
00337 return success;
00338 }
00339
00340
00341
00342
00343
00344 #ifdef HAVE_IMAGEMAGICK
00345
00346 static bool writeImageGrayMagick(const GrayLevelImage8 &img, string filename)
00347 {
00348 Magick::Image *magickImage;
00349 const GrayLevelImage8::PixelType *byteDataPointer = img.unsafeRowPointerArray()[0];
00350 byte *copiedData = NULL;
00351
00352 if (img.isSubImage()) {
00353
00354
00355
00356 const int lineWid = img.getWidth() * sizeof(GrayLevelImage8::PixelType);
00357 copiedData = new byte[img.getHeight() * lineWid];
00358 for (int y = 0; y < img.getHeight(); y ++) {
00359 memcpy (&(copiedData[y*lineWid]), img.unsafeRowPointerArray()[y], lineWid);
00360 }
00361 byteDataPointer = (GrayLevelImage8::PixelType*)copiedData;
00362 }
00363 try {
00364 magickImage = new Magick::Image(
00365 img.getWidth(),
00366 img.getHeight(),
00367 "I",
00368 Magick::CharPixel,
00369 byteDataPointer
00370 );
00371 }
00372
00373
00374
00375 catch( Magick::Exception &error_ ) {
00376 string msg ("Caught Image Magic Exception: ");
00377 msg += error_.what();
00378 throw PumaException(PumaException::intolerable, msg);
00379 }
00380
00381
00382
00383 int slen = filename.length();
00384 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00385 || (filename.compare(slen-4, 4, ".pgm") == 0)
00386 || (filename.compare(slen-4, 4, ".ppm") == 0)
00387 || (filename.compare(slen-4, 4, ".pnm") == 0))
00388 magickImage->compressType(Magick::ZipCompression);
00389
00390 int bitDepth = sizeof(img[0][0]) * 8;
00391 if (0 ) {
00392 unsigned int valMax = int(img.getValueRangeMaximum());
00393 while (valMax > 0) {
00394 bitDepth++;
00395 valMax >>= 1;
00396 }
00397 }
00398 magickImage->compressType(Magick::ZipCompression);
00399 magickImage->depth(bitDepth);
00400 magickImage->write(filename);
00401 if (copiedData)
00402 delete [] copiedData;
00403 delete magickImage;
00404 return true;
00405 }
00406
00407 static bool writeImageGrayMagick(const GrayLevelImage16 &img, string filename)
00408 {
00409 Magick::Image *magickImage;
00410 const GrayLevelImage16::PixelType *byteDataPointer = img.unsafeRowPointerArray()[0];
00411 byte *copiedData = NULL;
00412
00413 if (img.isSubImage()) {
00414
00415
00416
00417 const int lineWid = img.getWidth() * sizeof(GrayLevelImage16::PixelType);
00418 copiedData = new byte[img.getHeight() * lineWid];
00419 for (int y = 0; y < img.getHeight(); y ++) {
00420 memcpy (&(copiedData[y*lineWid]), img.unsafeRowPointerArray()[y], lineWid);
00421 }
00422 byteDataPointer = (GrayLevelImage16::PixelType*)copiedData;
00423 }
00424
00425 try {
00426 magickImage = new Magick::Image(
00427 img.getWidth(),
00428 img.getHeight(),
00429 "I",
00430 Magick::ShortPixel,
00431 byteDataPointer
00432 );
00433 }
00434
00435
00436
00437 catch( Magick::Exception &error_ ) {
00438 string msg ("Caught Image Magic Exception: ");
00439 msg += error_.what();
00440 throw PumaException(PumaException::intolerable, msg);
00441 }
00442
00443
00444
00445 int slen = filename.length();
00446 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00447 || (filename.compare(slen-4, 4, ".pgm") == 0)
00448 || (filename.compare(slen-4, 4, ".ppm") == 0)
00449 || (filename.compare(slen-4, 4, ".pnm") == 0))
00450 magickImage->compressType(Magick::ZipCompression);
00451
00452 int bitDepth = sizeof(img[0][0]) * 8;
00453 if (0 ) {
00454 unsigned int valMax = int(img.getValueRangeMaximum());
00455 while (valMax > 0) {
00456 bitDepth++;
00457 valMax >>= 1;
00458 }
00459 }
00460 magickImage->compressType(Magick::ZipCompression);
00461 magickImage->depth(bitDepth);
00462 magickImage->write(filename);
00463 if (copiedData)
00464 delete [] copiedData;
00465 delete magickImage;
00466 return true;
00467 }
00468
00469 static bool writeImageColorMagick(const ColorImageRGB8 &img, string filename)
00470 {
00471 Magick::Image *magickImage;
00472 const ColorImageRGB8::PixelType *byteDataPointer = img.unsafeRowPointerArray()[0];
00473 byte *copiedData = NULL;
00474
00475 if (img.isSubImage()) {
00476
00477
00478
00479 const int lineWid = img.getWidth() * sizeof(ColorImageRGB8::PixelType);
00480 copiedData = new byte[img.getHeight() * lineWid];
00481 for (int y = 0; y < img.getHeight(); y ++) {
00482 memcpy (&(copiedData[y*lineWid]), img.unsafeRowPointerArray()[y], lineWid);
00483 }
00484 byteDataPointer = (ColorImageRGB8::PixelType*)copiedData;
00485 }
00486
00487 try {
00488 magickImage = new Magick::Image(
00489 img.getWidth(),
00490 img.getHeight(),
00491 "RGB",
00492 Magick::CharPixel,
00493 byteDataPointer
00494 );
00495 }
00496
00497
00498
00499 catch( Magick::Exception &error_ ) {
00500 string msg ("Caught Image Magic Exception: ");
00501 msg += error_.what();
00502 throw PumaException(PumaException::intolerable, msg);
00503 }
00504
00505
00506
00507 int slen = filename.length();
00508 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00509 || (filename.compare(slen-4, 4, ".pgm") == 0)
00510 || (filename.compare(slen-4, 4, ".ppm") == 0)
00511 || (filename.compare(slen-4, 4, ".pnm") == 0))
00512 magickImage->compressType(Magick::ZipCompression);
00513
00514 magickImage->compressType(Magick::ZipCompression);
00515 magickImage->depth(8);
00516 magickImage->write(filename);
00517 if (copiedData)
00518 delete [] copiedData;
00519 delete magickImage;
00520 return true;
00521 }
00522
00523 static bool writeImageColorMagick(const ColorImageRGBa8 &img, string filename)
00524 {
00525 Magick::Image *magickImage;
00526 const ColorImageRGBa8::PixelType *byteDataPointer = img.unsafeRowPointerArray()[0];
00527 byte *copiedData = NULL;
00528
00529 if (img.isSubImage()) {
00530
00531
00532
00533 const int lineWid = img.getWidth() * sizeof(ColorImageRGBa8::PixelType);
00534 copiedData = new byte[img.getHeight() * lineWid];
00535 for (int y = 0; y < img.getHeight(); y ++) {
00536 memcpy (&(copiedData[y*lineWid]), img.unsafeRowPointerArray()[y], lineWid);
00537 }
00538 byteDataPointer = (ColorImageRGBa8::PixelType*)copiedData;
00539 }
00540
00541 try {
00542 magickImage = new Magick::Image(
00543 img.getWidth(),
00544 img.getHeight(),
00545 "RGBA",
00546 Magick::CharPixel,
00547 byteDataPointer
00548 );
00549 }
00550
00551
00552
00553 catch( Magick::Exception &error_ ) {
00554 string msg ("Caught Image Magic Exception: ");
00555 msg += error_.what();
00556 throw PumaException(PumaException::intolerable, msg);
00557 }
00558
00559
00560
00561 int slen = filename.length();
00562 if ((filename.compare(slen-4, 4, ".pbm") == 0)
00563 || (filename.compare(slen-4, 4, ".pgm") == 0)
00564 || (filename.compare(slen-4, 4, ".ppm") == 0)
00565 || (filename.compare(slen-4, 4, ".pnm") == 0))
00566 magickImage->compressType(Magick::ZipCompression);
00567
00568 magickImage->compressType(Magick::ZipCompression);
00569 magickImage->depth(8);
00570 magickImage->write(filename);
00571 if (copiedData)
00572 delete [] copiedData;
00573 delete magickImage;
00574 return true;
00575 }
00576 #endif