diff --git a/include/exiv2/image.hpp b/include/exiv2/image.hpp index 83d15340..099d7c5e 100644 --- a/include/exiv2/image.hpp +++ b/include/exiv2/image.hpp @@ -74,7 +74,7 @@ namespace Exiv2 { /*! @brief Options for printStructure */ - typedef enum { kpsNone, kpsBasic, kpsXMP } PrintStructureOption; + typedef enum { kpsNone, kpsBasic, kpsXMP, kpsRecursive, kpsIccProfile } PrintStructureOption; /*! @brief Abstract base class defining the interface for an image. This is diff --git a/src/actions.cpp b/src/actions.cpp index 464c4bc1..2cb69aab 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -241,8 +241,10 @@ namespace Action { case Params::pmList: rc = printList(); break; case Params::pmComment: rc = printComment(); break; case Params::pmPreview: rc = printPreviewList(); break; - case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic); break; - case Params::pmXMP: rc = printStructure(std::cout,Exiv2::kpsXMP); break; + case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break; + case Params::pmXMP: rc = printStructure(std::cout,Exiv2::kpsXMP) ; break; + case Params::pmIccProfile:rc = printStructure(std::cout,Exiv2::kpsIccProfile); break; + case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break; } return rc; } @@ -1007,6 +1009,9 @@ namespace Action { if (Params::instance().target_ & Params::ctPreview) { rc = writePreviews(); } + if (Params::instance().target_ & Params::ctIccProfile) { + rc = writeIccProfile(); + } if ( !(Params::instance().target_ & Params::ctXmpSidecar) && !(Params::instance().target_ & Params::ctThumb) && !(Params::instance().target_ & Params::ctPreview)) { @@ -1098,6 +1103,32 @@ namespace Action { return 0; } // Extract::writePreviews + int Extract::writeIccProfile() const + { + if (!Exiv2::fileExists(path_, true)) { + std::cerr << path_ + << ": " << _("Failed to open the file\n"); + return -1; + } + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); + assert(image.get() != 0); + image->readMetadata(); + + std::string iccPath = newFilePath(path_,".icc"); + std::filebuf iccBuffer ; + iccBuffer.open(iccPath,std::ios::out); + std::ostream iccStream(&iccBuffer); + + image->printStructure(iccStream,Exiv2::kpsIccProfile); + + iccBuffer.close(); + if (Params::instance().verbose_) { + std::cout << _("Writing iccProfile: ") << iccPath << std::endl; + } + return 0; + } // Extract::writeIccProfile + + void Extract::writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const { std::string pvFile = newFilePath(path_, "-preview") + Exiv2::toString(num); diff --git a/src/actions.hpp b/src/actions.hpp index 747d31e0..89700922 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -309,6 +309,10 @@ namespace Action { depending on the format of the Exif thumbnail image. */ void writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const; + /*! + @brief Write embedded iccProfile files. + */ + int writeIccProfile() const; private: virtual Extract* clone_() const; diff --git a/src/exiv2.cpp b/src/exiv2.cpp index aad697ef..0f73823f 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -369,6 +369,7 @@ int Params::option(int opt, const std::string& optarg, int optopt) case 'P': rc = evalPrintFlags(optarg); break; case 'd': rc = evalDelete(optarg); break; case 'e': rc = evalExtract(optarg); break; + case 'C': rc = evalExtract(optarg); break; case 'i': rc = evalInsert(optarg); break; case 'c': rc = evalModify(opt, optarg); break; case 'm': rc = evalModify(opt, optarg); break; @@ -560,10 +561,12 @@ int Params::evalPrint(const std::string& optarg) case 'h': rc = evalPrintFlags("Exgnycsh"); break; case 'i': rc = evalPrintFlags("Ikyct"); break; case 'x': rc = evalPrintFlags("Xkyct"); break; - case 'c': action_ = Action::print; printMode_ = pmComment ; break; - case 'p': action_ = Action::print; printMode_ = pmPreview ; break; - case 'S': action_ = Action::print; printMode_ = pmStructure; break; - case 'X': action_ = Action::print; printMode_ = pmXMP ; break; + case 'c': action_ = Action::print; printMode_ = pmComment ; break; + case 'p': action_ = Action::print; printMode_ = pmPreview ; break; + case 'C': action_ = Action::print; printMode_ = pmIccProfile ; break; + case 'R': action_ = Action::print; printMode_ = pmRecursive ; break; + case 'S': action_ = Action::print; printMode_ = pmStructure ; break; + case 'X': action_ = Action::print; printMode_ = pmXMP ; break; default: std::cerr << progname() << ": " << _("Unrecognized print mode") << " `" << optarg << "'\n"; @@ -1017,6 +1020,7 @@ namespace { case 'x': target |= Params::ctXmp; break; case 'c': target |= Params::ctComment; break; case 't': target |= Params::ctThumb; break; + case 'C': target |= Params::ctIccProfile; break; case 'a': target |= Params::ctExif | Params::ctIptc | Params::ctComment diff --git a/src/exiv2app.hpp b/src/exiv2app.hpp index 980ecbd9..bd6b5517 100644 --- a/src/exiv2app.hpp +++ b/src/exiv2app.hpp @@ -148,7 +148,9 @@ public: pmComment, pmPreview, pmStructure, - pmXMP + pmXMP, + pmIccProfile, + pmRecursive }; //! Individual items to print, bitmap @@ -174,7 +176,8 @@ public: ctThumb = 8, ctXmp = 16, ctXmpSidecar = 32, - ctPreview = 64 + ctPreview = 64, + ctIccProfile =128 }; //! Enumerates the policies to handle existing files in rename action diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp index 37213901..4bc8c4c6 100644 --- a/src/jpgimage.cpp +++ b/src/jpgimage.cpp @@ -527,7 +527,7 @@ namespace Exiv2 { throw Error(15); } - if ( option == kpsBasic || option == kpsXMP ) { + if ( option == kpsBasic || option == kpsXMP || option == kpsIccProfile || option == kpsRecursive) { // nmonic for markers std::string nm[256] ; @@ -565,7 +565,7 @@ namespace Exiv2 { bool first= true; while (!done) { // print marker bytes - if ( first && option == kpsBasic ) { + if ( first && (option == kpsBasic||option==kpsRecursive) ) { out << "STRUCTURE OF JPEG FILE: " << io_->path() << std::endl; out << " address | marker | length | data" << std::endl ; REPORT_MARKER; @@ -597,7 +597,9 @@ namespace Exiv2 { char http[5]; http[4]=0; memcpy(http,buf.pData_+2,4); + if ( option == kpsXMP && std::strcmp(http,"http") == 0 ) { + // extract XMP // http://ns.adobe.com/xap/1.0/ if ( size > 0 ) { io_->seek(-bufRead , BasicIo::cur); @@ -624,6 +626,17 @@ namespace Exiv2 { delete [] xmp; bufRead = size; } + } else if ( option == kpsIccProfile && std::strcmp(http,"ICC_") == 0 ) { + // extract ICCProfile + if ( size > 0 ) { + io_->seek(-bufRead , BasicIo::cur); + byte* icc = new byte[size]; + io_->read(icc,size); + std::size_t start=16; + out.write( ((const char*)icc)+start,size-start); + bufRead = size; + delete [] icc; + } } else if ( option == kpsBasic ) { out << "| " << Internal::binaryToString(buf,32,size>0?2:0); } diff --git a/src/pngimage.cpp b/src/pngimage.cpp index 78d6ba45..6a4c8b42 100644 --- a/src/pngimage.cpp +++ b/src/pngimage.cpp @@ -104,6 +104,10 @@ namespace Exiv2 { throw Error(3, "PNG"); } + if ( option == kpsIccProfile || option == kpsRecursive ) { + throw Error(13, io_->path()); + } + char chType[5]; chType[0]=0; chType[4]=0; diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index f7899121..d6390941 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -455,6 +455,11 @@ namespace Exiv2 { throw Error(15); } + if ( option == kpsIccProfile || option == kpsRecursive ) { + throw Error(13, io_->path()); + } + + if ( option == kpsBasic || option == kpsXMP ) { io_->seek(0,BasicIo::beg); // buffer