00001
00015 #include <fstream>
00016
00017 #include <png.h>
00018
00019 #include <dlrCommon/byteOrder.h>
00020 #include <dlrComputerVision/imageIO.h>
00021
00022 namespace {
00023
00024 void
00025 discardComments(std::istream& inputStream,
00026 std::istream::char_type commentCharacter)
00027 {
00028 std::istream::char_type inputCharacter;
00029 while(1) {
00030 inputStream >> inputCharacter;
00031 if(inputCharacter == commentCharacter) {
00032 std::string dummyString;
00033 getline(inputStream, dummyString);
00034 } else {
00035 inputStream.putback(inputCharacter);
00036 break;
00037 }
00038 }
00039 }
00040
00041
00042 std::string
00043 readComments(std::istream& inputStream,
00044 std::istream::char_type commentCharacter)
00045 {
00046 std::istream::char_type inputCharacter;
00047 std::ostringstream commentStream;
00048 while(1) {
00049 inputStream >> inputCharacter;
00050 if(inputCharacter == commentCharacter) {
00051 std::string dummyString;
00052 getline(inputStream, dummyString);
00053 commentStream << dummyString;
00054 } else {
00055 inputStream.putback(inputCharacter);
00056 break;
00057 }
00058 }
00059 return commentStream.str();
00060 }
00061
00062 }
00063
00064
00065 namespace dlr {
00066
00067 namespace computerVision {
00068
00069
00070 #if 0
00071
00072
00073 ImageReader::
00074 ImageReader()
00075 {
00076
00077 }
00078
00079
00080
00081 ImageReader::
00082 ~ImageReader()
00083 {
00084
00085 }
00086
00087
00088 void
00089 ImageReader::
00090 readFile(std::string const& fileName)
00091 {
00092
00093 }
00094
00095
00096 ImageFormat
00097 ImageReader::
00098 getNativeFormat()
00099 {
00100 return GRAY8;
00101 }
00102
00103 #endif
00104
00105 Image<GRAY8>
00106 readPGM8(const std::string& fileName)
00107 {
00108 std::string commentString;
00109 return readPGM8(fileName, commentString);
00110 }
00111
00112
00113 Image<GRAY8>
00114 readPGM8(const std::string& fileName, std::string& commentString)
00115 {
00116 std::ifstream inputStream(fileName.c_str(), std::ios::binary);
00117 if(!inputStream) {
00118 std::ostringstream message;
00119 message << "Couldn't open input file: " << fileName;
00120 DLR_THROW(IOException, "readPGM8()", message.str().c_str());
00121 }
00122
00123
00124 commentString.clear();
00125 std::string magic;
00126 size_t columns;
00127 size_t rows;
00128 long long int imageMax;
00129 inputStream >> magic;
00130 commentString += readComments(inputStream, '#');
00131 inputStream >> columns >> rows;
00132 commentString += readComments(inputStream, '#');
00133 inputStream >> imageMax;
00134
00135
00136 std::string dummy;
00137 std::getline(inputStream, dummy);
00138
00139
00140 if(!inputStream) {
00141 std::ostringstream message;
00142 message << "Couldn't read image header from file: " << fileName;
00143 DLR_THROW(IOException, "readPGM8()", message.str().c_str());
00144 }
00145
00146
00147 if(imageMax > 255LL) {
00148 std::ostringstream message;
00149 message << "File " << fileName << " has max value of " << imageMax
00150 << ", which is too big for an 8-bit image.";
00151 DLR_THROW(IOException, "readPGM8()", message.str().c_str());
00152 }
00153
00154
00155 Image<GRAY8> newImage(rows, columns);
00156
00157
00158 if(magic == "P5") {
00159
00160 inputStream.read(reinterpret_cast<char*>(newImage.data()),
00161 newImage.size());
00162 } else if(magic == "P2") {
00163
00164 unsigned short interpreter;
00165 for(size_t pixelIndex = 0; pixelIndex < newImage.size(); ++pixelIndex) {
00166
00167
00168
00169 inputStream >> interpreter;
00170 newImage(pixelIndex) =
00171 static_cast<Image<GRAY8>::PixelType>(interpreter);
00172 }
00173 } else {
00174 std::ostringstream message;
00175 message << "Incorrect magic, " << magic << " in file " << fileName
00176 << ".";
00177 DLR_THROW(IOException, "readPGM8()", message.str().c_str());
00178 }
00179
00180
00181 if(!inputStream) {
00182 std::ostringstream message;
00183 message << "Error reading image data from input file: " << fileName;
00184 DLR_THROW(IOException, "readPGM8()", message.str().c_str());
00185 }
00186
00187
00188 inputStream.close();
00189 return newImage;
00190 }
00191
00192
00193 Image<GRAY16>
00194 readPGM16(const std::string& fileName)
00195 {
00196 std::ifstream inputStream(fileName.c_str(), std::ios::binary);
00197 if(!inputStream) {
00198 std::ostringstream message;
00199 message << "Couldn't open input file: " << fileName;
00200 DLR_THROW(IOException, "readPGM16()", message.str().c_str());
00201 }
00202
00203
00204 std::string magic;
00205 size_t columns;
00206 size_t rows;
00207 long long int imageMax;
00208 inputStream >> magic;
00209 discardComments(inputStream, '#');
00210 inputStream >> columns >> rows;
00211 discardComments(inputStream, '#');
00212 inputStream >> imageMax;
00213
00214
00215 std::string dummy;
00216 std::getline(inputStream, dummy);
00217
00218
00219 if(!inputStream) {
00220 std::ostringstream message;
00221 message << "Couldn't read image header from file: " << fileName;
00222 DLR_THROW(IOException, "readPGM16()", message.str().c_str());
00223 }
00224
00225
00226 if(imageMax > 65535LL) {
00227 std::ostringstream message;
00228 message << "File " << fileName << " has max value of " << imageMax
00229 << ", which is too big for an 16-bit image.";
00230 DLR_THROW(IOException, "readPGM16()", message.str().c_str());
00231 }
00232
00233
00234 Image<GRAY16> newImage(rows, columns);
00235
00236
00237 if(magic == "P5") {
00238
00239 if(imageMax <= 255LL) {
00240
00241 DLR_THROW(NotImplementedException, "readPGM16()",
00242 "This routine currently cannot read 8-bit PGMs");
00243 } else {
00244 size_t numberOfBytes = 2 * newImage.size();
00245 inputStream.read(
00246 reinterpret_cast<char*>(newImage.data()), numberOfBytes);
00247 switchByteOrder(newImage.data(), newImage.size(),
00248 DLR_BIG_ENDIAN, getByteOrder());
00249 }
00250 } else if(magic == "P2") {
00251
00252 unsigned short interpreter;
00253 for(size_t pixelIndex = 0; pixelIndex < newImage.size(); ++pixelIndex) {
00254
00255
00256
00257 inputStream >> interpreter;
00258 newImage(pixelIndex) =
00259 static_cast<Image<GRAY16>::PixelType>(interpreter);
00260 }
00261 } else {
00262 std::ostringstream message;
00263 message << "Incorrect magic, " << magic << " in file " << fileName
00264 << ".";
00265 DLR_THROW(IOException, "readPGM16()", message.str().c_str());
00266 }
00267
00268
00269 if(!inputStream) {
00270 std::ostringstream message;
00271 message << "Error reading image data from input file: " << fileName;
00272 DLR_THROW(IOException, "readPGM16()", message.str().c_str());
00273 }
00274
00275
00276 inputStream.close();
00277 return newImage;
00278 }
00279
00280
00281 Image<RGB8>
00282 readPPM8(const std::string& fileName)
00283 {
00284 std::string commentString;
00285 return readPPM8(fileName, commentString);
00286 }
00287
00288
00289 Image<RGB8>
00290 readPPM8(const std::string& fileName,
00291 std::string& commentString)
00292 {
00293 std::ifstream inputStream(fileName.c_str(), std::ios::binary);
00294 if(!inputStream) {
00295 std::ostringstream message;
00296 message << "Couldn't open input file: " << fileName;
00297 DLR_THROW(IOException, "readPPM8()", message.str().c_str());
00298 }
00299
00300
00301 commentString.clear();
00302 std::string magic;
00303 size_t columns;
00304 size_t rows;
00305 long long int imageMax;
00306 inputStream >> magic;
00307 commentString += readComments(inputStream, '#');
00308 inputStream >> columns >> rows;
00309 commentString += readComments(inputStream, '#');
00310 inputStream >> imageMax;
00311
00312
00313 std::string dummy;
00314 std::getline(inputStream, dummy);
00315
00316
00317 if(!inputStream) {
00318 std::ostringstream message;
00319 message << "Couldn't read image header from file: " << fileName;
00320 DLR_THROW(IOException, "readPPM8()", message.str().c_str());
00321 }
00322
00323
00324 if(imageMax > 255LL) {
00325 std::ostringstream message;
00326 message << "File " << fileName << " has max value of " << imageMax
00327 << ", which is too big for an 8-bit image.";
00328 DLR_THROW(IOException, "readPPM8()", message.str().c_str());
00329 }
00330
00331
00332 Image<RGB8> newImage(rows, columns);
00333
00334
00335 if(magic == "P6") {
00336
00337 inputStream.read(reinterpret_cast<char*>(newImage.data()),
00338 newImage.size() * 3);
00339 } else if(magic == "P3") {
00340
00341 unsigned short interpreterRed;
00342 unsigned short interpreterGreen;
00343 unsigned short interpreterBlue;
00344 for(size_t pixelIndex = 0; pixelIndex < newImage.size(); ++pixelIndex) {
00345
00346
00347
00348 inputStream >> interpreterRed >> interpreterGreen >> interpreterBlue;
00349 newImage(pixelIndex).red =
00350 static_cast<UnsignedInt8>(interpreterRed);
00351 newImage(pixelIndex).green =
00352 static_cast<UnsignedInt8>(interpreterGreen);
00353 newImage(pixelIndex).blue =
00354 static_cast<UnsignedInt8>(interpreterBlue);
00355 }
00356 } else {
00357 std::ostringstream message;
00358 message << "Incorrect magic, " << magic << " in file " << fileName
00359 << ".";
00360 DLR_THROW(IOException, "readPPM8()", message.str().c_str());
00361 }
00362
00363
00364 if(!inputStream) {
00365 std::ostringstream message;
00366 message << "Error reading image data from input file: " << fileName;
00367 DLR_THROW(IOException, "readPPM8()", message.str().c_str());
00368 }
00369
00370
00371 inputStream.close();
00372 return newImage;
00373 }
00374
00375
00376 void
00377 writePGM8(const std::string& fileName,
00378 const Image<GRAY8>& outputImage,
00379 const std::string& comment)
00380 {
00381 std::ofstream outputStream(fileName.c_str(), std::ios::binary);
00382 if(!outputStream) {
00383 std::ostringstream message;
00384 message << "Couldn't open output file: " << fileName;
00385 DLR_THROW(IOException, "writePGM8()", message.str().c_str());
00386 }
00387
00388
00389 outputStream << "P5\n";
00390 if(comment != "") {
00391 outputStream << "# " << comment << "\n";
00392 }
00393 outputStream << outputImage.columns() << " " << outputImage.rows() << "\n"
00394 << "255\n";
00395
00396
00397 if(!outputStream) {
00398 std::ostringstream message;
00399 message << "Couldn't write image header to file: " << fileName;
00400 DLR_THROW(IOException, "writePGM8()", message.str().c_str());
00401 }
00402
00403
00404 outputStream.write(reinterpret_cast<const char*>(outputImage.data()),
00405 outputImage.size());
00406
00407
00408 if(!outputStream) {
00409 std::ostringstream message;
00410 message << "Error writeing image data to output file: " << fileName;
00411 DLR_THROW(IOException, "writePGM8()", message.str().c_str());
00412 }
00413
00414
00415 outputStream.close();
00416 }
00417
00418
00419 void
00420 writePGM16(const std::string& fileName,
00421 const Image<GRAY16>& outputImage,
00422 const std::string& comment)
00423 {
00424 std::ofstream outputStream(fileName.c_str(), std::ios::binary);
00425 if(!outputStream) {
00426 std::ostringstream message;
00427 message << "Couldn't open output file: " << fileName;
00428 DLR_THROW(IOException, "writePGM16()", message.str().c_str());
00429 }
00430
00431
00432 outputStream << "P5\n";
00433 if(comment != "") {
00434 outputStream << "# " << comment << "\n";
00435 }
00436 outputStream << outputImage.columns() << " " << outputImage.rows() << "\n"
00437 << "65535\n";
00438
00439
00440 if(!outputStream) {
00441 std::ostringstream message;
00442 message << "Couldn't write image header to file: " << fileName;
00443 DLR_THROW(IOException, "writePGM16()", message.str().c_str());
00444 }
00445
00446
00447 size_t numberOfElements = outputImage.size();
00448 size_t numberOfBytes =
00449 numberOfElements * sizeof(Image<GRAY16>::value_type);
00450 if(getByteOrder() == DLR_BIG_ENDIAN) {
00451 outputStream.write(
00452 reinterpret_cast<const char*>(outputImage.data()), numberOfBytes);
00453 } else {
00454 char* swabbedData = new char[numberOfBytes];
00455 switchByteOrder(
00456 outputImage.data(), numberOfElements,
00457 reinterpret_cast<Image<GRAY16>::value_type*>(swabbedData),
00458 getByteOrder(), DLR_BIG_ENDIAN);
00459 outputStream.write(swabbedData, numberOfBytes);
00460 delete[] swabbedData;
00461 }
00462
00463
00464 if(!outputStream) {
00465 outputStream.close();
00466 std::ostringstream message;
00467 message << "Error writeing image data to output file: " << fileName;
00468 DLR_THROW(IOException, "writePGM16()", message.str().c_str());
00469 }
00470
00471
00472 outputStream.close();
00473 }
00474
00475
00476 void
00477 writePPM8(const std::string& fileName,
00478 const Image<RGB8>& outputImage,
00479 const std::string& comment)
00480 {
00481 std::ofstream outputStream(fileName.c_str(), std::ios::binary);
00482 if(!outputStream) {
00483 std::ostringstream message;
00484 message << "Couldn't open output file: " << fileName;
00485 DLR_THROW(IOException, "writePPM8()", message.str().c_str());
00486 }
00487
00488
00489 outputStream << "P6\n";
00490 if(comment != "") {
00491 outputStream << "# " << comment << "\n";
00492 }
00493 outputStream << outputImage.columns() << " " << outputImage.rows() << "\n"
00494 << "255\n";
00495
00496
00497 if(!outputStream) {
00498 std::ostringstream message;
00499 message << "Couldn't write image header to file: " << fileName;
00500 DLR_THROW(IOException, "writePPM8()", message.str().c_str());
00501 }
00502
00503
00504 outputStream.write(reinterpret_cast<const char*>(outputImage.data()),
00505 3 * outputImage.size());
00506
00507
00508 if(!outputStream) {
00509 std::ostringstream message;
00510 message << "Error writeing image data to output file: " << fileName;
00511 DLR_THROW(IOException, "writePPM8()", message.str().c_str());
00512 }
00513
00514
00515 outputStream.close();
00516 }
00517
00518
00519 #if HAVE_LIBPNG
00520
00521 Image<GRAY8>
00522 readPNG8(const std::string& fileName,
00523 std::string& commentString)
00524 {
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 Image<GRAY8> result;
00536
00537
00538
00539 const size_t pngSignatureSize = 8;
00540
00541 FILE *fp = fopen(fileName.c_str(), "rb");
00542 if (fp == 0) {
00543 DLR_THROW(dlr::IOException, "dlr::computerVision::readPng8()",
00544 "Couldn't open input file.");
00545 }
00546
00547
00548 try {
00549
00550
00551
00552 unsigned char header[pngSignatureSize + 1];
00553 if(fread(header, 1, pngSignatureSize, fp) != pngSignatureSize) {
00554 DLR_THROW(IOException, "dlr::computerVision::readPng8()",
00555 "Couldn't read png signature from file.");
00556 }
00557 if(png_sig_cmp(header, 0, pngSignatureSize) != 0) {
00558 DLR_THROW(IOException, "dlr::computerVision::readPng8()",
00559 "Fiel doesn't seem to be a PNG image.");
00560 }
00561
00562
00563
00564 png_structp pngPtr = png_create_read_struct(
00565 PNG_LIBPNG_VER_STRING, 0, 0, 0);
00566 if(pngPtr == 0) {
00567 DLR_THROW(dlr::RunTimeException, "dlr::computerVision::readPng8()",
00568 "Couldn't initialize png_structp.");
00569 }
00570
00571
00572
00573 png_infop* infoPtrPtrForCleanup = png_infopp_NULL;
00574
00575
00576 try {
00577
00578
00579 png_infop infoPtr = png_create_info_struct(pngPtr);
00580 if (infoPtr == 0) {
00581 DLR_THROW(RunTimeException, "dlr::computerVision::readPng8()",
00582 "Couldn't initialize png_infop.");
00583 }
00584 infoPtrPtrForCleanup = &infoPtr;
00585
00586
00587 if(setjmp(png_jmpbuf(pngPtr))) {
00588 DLR_THROW(dlr::IOException, "dlr::computerVision::readPng8()",
00589 "Trouble reading from file.");
00590 }
00591
00592
00593 png_init_io(pngPtr, fp);
00594
00595
00596 png_set_sig_bytes(pngPtr, pngSignatureSize);
00597
00598
00599 png_read_png(pngPtr, infoPtr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
00600
00601
00602 png_uint_32 width, height;
00603 int bitDepth, colorType, interlaceType;
00604 int compressionType, filterMethod;
00605 png_get_IHDR(pngPtr, infoPtr, &width, &height, &bitDepth, &colorType,
00606 &interlaceType, &compressionType, &filterMethod);
00607 if(bitDepth != 8) {
00608 DLR_THROW(IOException, "dlr::computerVision::readPng8()",
00609 "Image file is not 8 bit.");
00610 }
00611 if(colorType != PNG_COLOR_TYPE_GRAY) {
00612 DLR_THROW(IOException, "dlr::computerVision::readPng8()",
00613 "Can currently only handle grayscale images.");
00614 }
00615 if(interlaceType != PNG_INTERLACE_NONE) {
00616 DLR_THROW(IOException, "dlr::computerVision::readPng8()",
00617 "Can currently only handle non-interlaced images.");
00618 }
00619
00620
00621 result.reinit(height, width);
00622 png_bytep* rowPointers = png_get_rows(pngPtr, infoPtr);
00623 for(size_t rowIndex = 0; rowIndex < height; ++rowIndex) {
00624 result.getRow(rowIndex).copy(rowPointers[rowIndex]);
00625 }
00626
00627 } catch(...) {
00628 png_destroy_read_struct(
00629 &pngPtr, infoPtrPtrForCleanup, png_infopp_NULL);
00630 throw;
00631 }
00632
00633
00634 png_destroy_read_struct(&pngPtr, infoPtrPtrForCleanup, png_infopp_NULL);
00635
00636 } catch(...) {
00637 fclose(fp);
00638 throw;
00639 }
00640 fclose(fp);
00641
00642 return result;
00643 }
00644
00645
00646 void
00647 writePNG8(const std::string& fileName,
00648 const Image<GRAY8>& outputImage,
00649 const std::string& comment)
00650 {
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 FILE* fp = fopen(fileName.c_str(), "wb");
00662 if (fp == 0) {
00663 DLR_THROW(dlr::IOException, "ImageIO::writePng()",
00664 "Couldn't open output file.");
00665 }
00666
00667
00668 try {
00669
00670
00671
00672 png_structp pngPtr = png_create_write_struct(
00673 PNG_LIBPNG_VER_STRING, 0, 0, 0);
00674 if (pngPtr == 0) {
00675 DLR_THROW(dlr::RunTimeException, "ImageIO::writePng()",
00676 "Couldn't initialize png_structp.");
00677 }
00678
00679
00680
00681 png_infop* infoPtrPtrForCleanup = png_infopp_NULL;
00682
00683
00684 try {
00685
00686
00687
00688 png_infop infoPtr = png_create_info_struct(pngPtr);
00689 if (infoPtr == 0) {
00690 DLR_THROW(dlr::RunTimeException, "ImageIO::writePng()",
00691 "Couldn't initialize png_infop.");
00692 }
00693 infoPtrPtrForCleanup = &infoPtr;
00694
00695
00696 if(setjmp(png_jmpbuf(pngPtr))) {
00697
00698 DLR_THROW(dlr::IOException, "ImageIO::writePng()",
00699 "Trouble reading from file.");
00700 }
00701
00702
00703 png_init_io(pngPtr, fp);
00704
00705
00706
00707
00708
00709 png_set_IHDR(
00710 pngPtr, infoPtr, outputImage.columns(), outputImage.rows(),
00711 sizeof(ImageFormatTraits<GRAY8>::PixelType) * 8,
00712 PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
00713 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00714
00715
00716
00717 png_bytep* rowPointers = (png_bytep*)png_malloc(
00718 pngPtr, outputImage.rows() * png_sizeof(png_bytep));
00719 if(rowPointers == 0) {
00720 DLR_THROW(dlr::RunTimeException, "ImageIO::writePng()",
00721 "Couldn't allocate row pointers.");
00722 }
00723
00724
00725 try {
00726 for(size_t rowIndex = 0; rowIndex < outputImage.rows();
00727 ++rowIndex) {
00728 rowPointers[rowIndex] = const_cast<unsigned char*>(
00729 outputImage.getRow(rowIndex).data());
00730 }
00731 png_set_rows(pngPtr, infoPtr, rowPointers);
00732 png_write_png(
00733 pngPtr, infoPtr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
00734 } catch(...) {
00735 png_free(pngPtr, rowPointers);
00736 }
00737 png_free(pngPtr, rowPointers);
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748 } catch(...) {
00749 png_destroy_write_struct(&pngPtr, infoPtrPtrForCleanup);
00750 throw;
00751 }
00752
00753
00754 png_destroy_write_struct(&pngPtr, infoPtrPtrForCleanup);
00755
00756 } catch(...) {
00757 fclose(fp);
00758 throw;
00759 }
00760
00761 fclose(fp);
00762
00763 }
00764
00765 #endif
00766
00767 }
00768
00769 }