From ef14bf1c31f72faa5ab5fc1411215afb81a16d64 Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Thu, 22 May 2008 02:12:24 +0000 Subject: [PATCH] Changed option -eX to write XMP sidecar file (corresponding insert not done yet). --- src/actions.cpp | 50 +++++++++++++++++++++++++++------------------- src/actions.hpp | 4 ++-- src/exiv2.cpp | 2 +- src/exiv2.hpp | 10 +++++++++- src/xmpsidecar.cpp | 37 ++++++++++++++++++---------------- src/xmpsidecar.hpp | 18 +++++++---------- 6 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index f9b9407c..2cf2f01c 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -44,6 +44,7 @@ EXIV2_RCSID("@(#) $Id$") #include "exiv2.hpp" #include "image.hpp" #include "jpgimage.hpp" +#include "xmpsidecar.hpp" #include "utils.hpp" #include "types.hpp" #include "exif.hpp" @@ -1020,10 +1021,11 @@ namespace Action { if (Params::instance().target_ & Params::ctThumb) { rc = writeThumbnail(); } - if (Params::instance().target_ & Params::ctXmpPacket) { - rc = writeXmp(); + if (Params::instance().target_ & Params::ctXmpSidecar) { + rc = writeXmpSidecar(); } - if (Params::instance().target_ & ~Params::ctThumb & ~Params::ctXmpPacket) { + if ( !(Params::instance().target_ & Params::ctXmpSidecar) + && !(Params::instance().target_ & Params::ctThumb)) { std::string exvPath = newFilePath(path_, ".exv"); if (dontOverwrite(exvPath)) return 0; rc = metacopy(path_, exvPath, false); @@ -1037,7 +1039,7 @@ namespace Action { return 1; } // Extract::run - int Extract::writeXmp() const + int Extract::writeXmpSidecar() const { if (!Exiv2::fileExists(path_, true)) { std::cerr << path_ @@ -1047,26 +1049,32 @@ namespace Action { Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_); assert(image.get() != 0); image->readMetadata(); - const std::string& xmpPacket = image->xmpPacket(); - if (xmpPacket.empty()) { - return -3; - } - std::string xmpPath = newFilePath(path_, ".xmp"); - if (dontOverwrite(xmpPath)) return 0; + + std::string sidecarPath = newFilePath(path_, ".xmp"); + if (dontOverwrite(sidecarPath)) return 0; + + // Apply any modification commands to the source image on-the-fly + Action::Modify::applyCommands(image.get()); + + Exiv2::Image::AutoPtr xmpSidecar = + Exiv2::ImageFactory::create(Exiv2::ImageType::xmp, sidecarPath); + assert(xmpSidecar.get() != 0); if (Params::instance().verbose_) { - std::cout << _("Writing XMP packet from") << " " << path_ - << " " << _("to") << " " << xmpPath << std::endl; + std::cout << _("Writing XMP sidecar file ") << " " + << sidecarPath << std::endl; } - std::ofstream file(xmpPath.c_str()); - if (!file) { - std::cerr << Params::instance().progname() << ": " - << _("Failed to open file ") << " " << xmpPath << ": " - << Exiv2::strError() << "\n"; - return 1; + if (Params::instance().target_ & Params::ctExif) { + xmpSidecar->setExifData(image->exifData()); + } + if (Params::instance().target_ & Params::ctIptc) { + xmpSidecar->setIptcData(image->iptcData()); + } + if (Params::instance().target_ & Params::ctXmp) { + xmpSidecar->setXmpData(image->xmpData()); } - file << xmpPacket; + xmpSidecar->writeMetadata(); return 0; - } // Extract::writeXmp + } // Extract::writeXmpSidecar int Extract::writeThumbnail() const { @@ -1143,7 +1151,7 @@ namespace Action { std::string exvPath = newFilePath(path, suffix); rc = metacopy(exvPath, path, true); } - if (0 == rc && Params::instance().target_ & Params::ctXmpPacket) { + if (0 == rc && Params::instance().target_ & Params::ctXmpSidecar) { rc = insertXmpPacket(path); } if (Params::instance().preserve_) { diff --git a/src/actions.hpp b/src/actions.hpp index 4bcddfe5..c2e6e89c 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -278,8 +278,8 @@ namespace Action { on the format of the Exif thumbnail image. */ int writeThumbnail() const; - //! Write the XMP packet to a file. - int writeXmp() const; + //! Write an XMP sidecar file. + int writeXmpSidecar() const; private: virtual Extract* clone_() const; diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 3884037f..4d5895a6 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -840,9 +840,9 @@ namespace { case 'e': target |= Params::ctExif; break; case 'i': target |= Params::ctIptc; break; case 'x': target |= Params::ctXmp; break; - case 'X': target |= Params::ctXmpPacket; break; case 'c': target |= Params::ctComment; break; case 't': target |= Params::ctThumb; break; + case 'X': target |= Params::ctXmpSidecar; // fall-through case 'a': target |= Params::ctExif | Params::ctIptc | Params::ctComment diff --git a/src/exiv2.hpp b/src/exiv2.hpp index ba6ac1e7..78026d2b 100644 --- a/src/exiv2.hpp +++ b/src/exiv2.hpp @@ -141,7 +141,15 @@ public: }; //! Enumerates common targets, bitmap - enum CommonTarget { ctExif = 1, ctIptc = 2, ctComment = 4, ctThumb = 8, ctXmp = 16, ctXmpPacket = 32 }; + enum CommonTarget { + ctExif = 1, + ctIptc = 2, + ctComment = 4, + ctThumb = 8, + ctXmp = 16, + ctXmpSidecar = 32 + }; + //! Enumerates the policies to handle existing files in rename action enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy }; diff --git a/src/xmpsidecar.cpp b/src/xmpsidecar.cpp index e40a80a2..9848df13 100644 --- a/src/xmpsidecar.cpp +++ b/src/xmpsidecar.cpp @@ -43,6 +43,7 @@ EXIV2_RCSID("@(#) $Id$") #include "error.hpp" #include "xmp.hpp" #include "futils.hpp" +#include "convert.hpp" // + standard includes #include @@ -53,23 +54,20 @@ EXIV2_RCSID("@(#) $Id$") // class member definitions namespace Exiv2 { - XmpSidecar::XmpSidecar(BasicIo::AutoPtr io) + const char* XmpSidecar::xmlHeader_ = "\n"; + const long XmpSidecar::xmlHdrCnt_ = 39; + + XmpSidecar::XmpSidecar(BasicIo::AutoPtr io, bool create) : Image(ImageType::xmp, mdXmp, io) { + if (create) { + if (io_->open() == 0) { + IoCloser closer(*io_); + io_->write(reinterpret_cast(xmlHeader_), xmlHdrCnt_); + } + } } // XmpSidecar::XmpSidecar - void XmpSidecar::setExifData(const ExifData& /*exifData*/) - { - // Todo: implement me! - throw(Error(32, "Exif metadata", "XMP")); - } - - void XmpSidecar::setIptcData(const IptcData& /*iptcData*/) - { - // Todo: implement me! - throw(Error(32, "IPTC metadata", "XMP")); - } - void XmpSidecar::setComment(const std::string& /*comment*/) { // not supported @@ -106,6 +104,8 @@ namespace Exiv2 { std::cerr << "Warning: Failed to decode XMP metadata.\n"; #endif } + copyXmpToIptc(xmpData_, iptcData_); + copyXmpToExif(xmpData_, exifData_); } // XmpSidecar::readMetadata void XmpSidecar::writeMetadata() @@ -116,7 +116,10 @@ namespace Exiv2 { IoCloser closer(*io_); if (writeXmpFromPacket() == false) { - if (XmpParser::encode(xmpPacket_, xmpData_, XmpParser::omitPacketWrapper|XmpParser::useCompactFormat)) { + copyExifToXmp(exifData_, xmpData_); + copyIptcToXmp(iptcData_, xmpData_); + if (XmpParser::encode(xmpPacket_, xmpData_, + XmpParser::omitPacketWrapper|XmpParser::useCompactFormat)) { #ifndef SUPPRESS_WARNINGS std::cerr << "Error: Failed to encode XMP metadata.\n"; #endif @@ -124,7 +127,7 @@ namespace Exiv2 { } if (xmpPacket_.size() > 0) { if (xmpPacket_.substr(0, 5) != "\n" + xmpPacket_; + xmpPacket_ = xmlHeader_ + xmpPacket_; } BasicIo::AutoPtr tempIo(io_->temporary()); // may throw assert(tempIo.get() != 0); @@ -140,9 +143,9 @@ namespace Exiv2 { // ************************************************************************* // free functions - Image::AutoPtr newXmpInstance(BasicIo::AutoPtr io, bool /*create*/) + Image::AutoPtr newXmpInstance(BasicIo::AutoPtr io, bool create) { - Image::AutoPtr image(new XmpSidecar(io)); + Image::AutoPtr image(new XmpSidecar(io, create)); if (!image->good()) { image.reset(); } diff --git a/src/xmpsidecar.hpp b/src/xmpsidecar.hpp index 1f45a4bf..3352594f 100644 --- a/src/xmpsidecar.hpp +++ b/src/xmpsidecar.hpp @@ -66,24 +66,16 @@ namespace Exiv2 { auto-pointer. Callers should not continue to use the BasicIo instance after it is passed to this method. Use the Image::io() method to get a temporary reference. + @param create Specifies if an existing image should be read (false) + or if a new image should be created (true). */ - XmpSidecar(BasicIo::AutoPtr io); + XmpSidecar(BasicIo::AutoPtr io, bool create); //@} //! @name Manipulators //@{ void readMetadata(); void writeMetadata(); - /*! - @brief Todo: Not supported yet, requires conversion from Exif to XMP. - Calling this function will throw an instance of Error(32). - */ - void setExifData(const ExifData& exifData); - /*! - @brief Todo: Not supported yet, requires conversion from IPTC to XMP. - Calling this function will throw an instance of Error(32). - */ - void setIptcData(const IptcData& iptcData); /*! @brief Not supported. XMP sidecar files do not contain a comment. Calling this function will throw an instance of Error(32). @@ -105,6 +97,10 @@ namespace Exiv2 { XmpSidecar& operator=(const XmpSidecar& rhs); //@} + // DATA + static const char* xmlHeader_; + static const long xmlHdrCnt_; + }; // class XmpSidecar // *****************************************************************************