From f01c919e14669e82849ae463736a91b1dde7fd03 Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Sun, 7 Feb 2010 13:53:00 +0000 Subject: [PATCH] Added -g option to exiv2 utility to 'grep' info for individual tags. --- src/actions.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++------- src/actions.hpp | 10 +++--- src/exiv2.cpp | 15 +++++++++ src/exiv2.hpp | 6 +++- 4 files changed, 103 insertions(+), 16 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 741a20de..849003ca 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -496,7 +496,6 @@ namespace Action { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); - bool const manyFiles = Params::instance().files_.size() > 1; // Set defaults for metadata types and data columns if (Params::instance().printTags_ == Exiv2::mdNone) { Params::instance().printTags_ = Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp; @@ -504,11 +503,79 @@ namespace Action { if (Params::instance().printItems_ == 0) { Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans; } + if (!Params::instance().keys_.empty()) { + for (Params::Keys::const_iterator key = Params::instance().keys_.begin(); + key != Params::instance().keys_.end(); ++key) { + rc |= grepTag(*key, image.get()); + } + } + else { + rc = printMetadata(image.get()); + } + return rc; + } // Print::printList + + int Print::grepTag(const std::string& key, const Exiv2::Image* image) + { + int rc = 0; + if (key.empty()) return rc; + switch (key[0]) { + case 'E': + if (Params::instance().printTags_ & Exiv2::mdExif) { + Exiv2::ExifKey ek(key); + const Exiv2::ExifData& exifData = image->exifData(); + Exiv2::ExifData::const_iterator md = exifData.findKey(ek); + if (md != exifData.end()) printMetadatum(*md, image); + if (exifData.empty()) { + if (Params::instance().verbose_) { + std::cerr << path_ << ": " << _("No Exif data found in the file\n"); + } + rc = -3; + } + } + break; + case 'I': + if (Params::instance().printTags_ & Exiv2::mdIptc) { + Exiv2::IptcKey ik(key); + const Exiv2::IptcData& iptcData = image->iptcData(); + Exiv2::IptcData::const_iterator md = iptcData.findKey(ik); + if (md != iptcData.end()) printMetadatum(*md, image); + if (iptcData.empty()) { + if (Params::instance().verbose_) { + std::cerr << path_ << ": " << _("No IPTC data found in the file\n"); + } + rc = -3; + } + } + break; + case 'X': + if (Params::instance().printTags_ & Exiv2::mdXmp) { + Exiv2::XmpKey xk(key); + const Exiv2::XmpData& xmpData = image->xmpData(); + Exiv2::XmpData::const_iterator md = xmpData.findKey(xk); + if (md != xmpData.end()) printMetadatum(*md, image); + if (xmpData.empty()) { + if (Params::instance().verbose_) { + std::cerr << path_ << ": " << _("No XMP data found in the file\n"); + } + rc = -3; + } + } + break; + default: + throw Exiv2::Error(1, std::string(_("Invalid key")) + " `" + key + "'"); + } + return rc; + } // Print::grepTag + + int Print::printMetadata(const Exiv2::Image* image) + { + int rc = 0; if (Params::instance().printTags_ & Exiv2::mdExif) { - Exiv2::ExifData& exifData = image->exifData(); + const Exiv2::ExifData& exifData = image->exifData(); for (Exiv2::ExifData::const_iterator md = exifData.begin(); md != exifData.end(); ++md) { - printMetadatum(*md, image.get(), manyFiles); + printMetadatum(*md, image); } if (exifData.empty()) { if (Params::instance().verbose_) { @@ -518,10 +585,10 @@ namespace Action { } } if (Params::instance().printTags_ & Exiv2::mdIptc) { - Exiv2::IptcData& iptcData = image->iptcData(); + const Exiv2::IptcData& iptcData = image->iptcData(); for (Exiv2::IptcData::const_iterator md = iptcData.begin(); md != iptcData.end(); ++md) { - printMetadatum(*md, image.get(), manyFiles); + printMetadatum(*md, image); } if (iptcData.empty()) { if (Params::instance().verbose_) { @@ -531,10 +598,10 @@ namespace Action { } } if (Params::instance().printTags_ & Exiv2::mdXmp) { - Exiv2::XmpData& xmpData = image->xmpData(); + const Exiv2::XmpData& xmpData = image->xmpData(); for (Exiv2::XmpData::const_iterator md = xmpData.begin(); md != xmpData.end(); ++md) { - printMetadatum(*md, image.get(), manyFiles); + printMetadatum(*md, image); } if (xmpData.empty()) { if (Params::instance().verbose_) { @@ -544,16 +611,15 @@ namespace Action { } } return rc; - } // Print::printList + } // Print::printMetadata - void Print::printMetadatum(const Exiv2::Metadatum& md, - const Exiv2::Image* pImage, - bool const manyFiles) + void Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage) { if ( Params::instance().unknown_ && md.tagName().substr(0, 2) == "0x") { return; } + bool const manyFiles = Params::instance().files_.size() > 1; if (manyFiles) { std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; diff --git a/src/actions.hpp b/src/actions.hpp index 0b0042b5..08fa0573 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -61,7 +61,7 @@ namespace Action { //! Enumerates all tasks enum TaskType { none, adjust, print, rename, erase, extract, insert, - modify, fixiso }; + modify, fixiso, fixcom }; // ***************************************************************************** // class definitions @@ -170,10 +170,12 @@ namespace Action { int printSummary(); //! Print Exif, IPTC and XMP metadata in user defined format int printList(); + //! Print info for an individual tag specified by its key in a user defined format + int grepTag(const std::string& key, const Exiv2::Image* image); + //! Print all metadata in a user defined format + int printMetadata(const Exiv2::Image* image); //! Print a metadatum in a user defined format - void printMetadatum(const Exiv2::Metadatum& md, - const Exiv2::Image* pImage, - bool const manyFiles); + void printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image); //! Print the label for a summary line void printLabel(const std::string& label) const; /*! diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 0203ed95..30df50a8 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -250,12 +250,16 @@ void Params::help(std::ostream& os) const " Requires option -c, -m or -M.\n") << _(" fi | fixiso Copy ISO setting from the Nikon Makernote to the regular\n" " Exif tag.\n") + << _(" fc | fixcom Convert the UNICODE Exif user comment to UCS-2. Its current\n" + " character encoding can be specified with the -n option.\n") << _("\nOptions:\n") << _(" -h Display this help and exit.\n") << _(" -V Show the program version and exit.\n") << _(" -v Be verbose during the program run.\n") << _(" -b Show large binary values.\n") << _(" -u Show unknown tags.\n") + << _(" -g key Only output info for this key (grep).\n") + << _(" -n enc Charset to use to decode UNICODE Exif user comments.\n") << _(" -k Preserve file timestamps (keep).\n") << _(" -t Also set the file timestamp in 'rename' action (overrides -k).\n") << _(" -T Only set the file timestamp in 'rename' action, do not rename\n" @@ -337,6 +341,8 @@ int Params::option(int opt, const std::string& optarg, int optopt) case 'u': unknown_ = false; break; case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break; case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break; + case 'g': keys_.push_back(optarg); printMode_ = pmList; break; + case 'n': charset_ = optarg; break; case 'r': rc = evalRename(opt, optarg); break; case 't': rc = evalRename(opt, optarg); break; case 'T': rc = evalRename(opt, optarg); break; @@ -738,6 +744,15 @@ int Params::nonoption(const std::string& argv) action = true; action_ = Action::fixiso; } + if (argv == "fc" || argv == "fixcom") { + if (action_ != Action::none && action_ != Action::fixcom) { + std::cerr << progname() << ": " + << _("Action fixcom is not compatible with the given options\n"); + rc = 1; + } + action = true; + action_ = Action::fixcom; + } if (action_ == Action::none) { // if everything else fails, assume print as the default action action_ = Action::print; diff --git a/src/exiv2.hpp b/src/exiv2.hpp index 951147ed..b7745dbd 100644 --- a/src/exiv2.hpp +++ b/src/exiv2.hpp @@ -116,6 +116,8 @@ public: typedef std::vector Files; //! Container for preview image numbers typedef std::set PreviewNumbers; + //! Container for keys + typedef std::vector Keys; /*! @brief Controls all access to the global Params instance. @@ -202,6 +204,8 @@ public: std::string suffix_; //!< File extension of the file to insert Files files_; //!< List of non-option arguments. PreviewNumbers previewNumbers_; //!< List of preview numbers + Keys keys_; //!< List of keys to 'grep' from the metadata + std::string charset_; //!< Charset to use for UNICODE Exif user comment private: //! Pointer to the global Params object. @@ -216,7 +220,7 @@ private: @brief Default constructor. Note that optstring_ is initialized here. The c'tor is private to force instantiation through instance(). */ - Params() : optstring_(":hVvfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:"), + Params() : optstring_(":hVvfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:n:"), help_(false), version_(false), verbose_(false),