diff --git a/src/actions.cpp b/src/actions.cpp index 847f4fb7..d96cf210 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -676,16 +676,38 @@ namespace Action { int Erase::run(const std::string& path) try { path_ = path; - Exiv2::ExifData exifData; - int rc = exifData.read(path); + + Exiv2::Image::AutoPtr image + = Exiv2::ImageFactory::instance().open(path_); + if (image.get() == 0) { + std::cerr << path_ + << ": The file contains data of an unknown image type\n"; + return -2; + } + int rc = image->readMetadata(); if (rc) { - std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; - return rc; + std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n"; + } + // Thumbnail must be before Exif + if (0 == rc && Params::instance().target_ & Params::ctThumb) { + rc = eraseThumbnail(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctExif) { + rc = eraseExifData(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctIptc) { + rc = eraseIptcData(image.get()); + } + if (0 == rc && Params::instance().target_ & Params::ctComment) { + rc = eraseComment(image.get()); } - switch (Params::instance().target_) { - case Params::ctExif: rc = eraseExifData(exifData); break; - case Params::ctThumb: rc = eraseThumbnail(exifData); break; + if (0 == rc) { + rc = image->writeMetadata(); + if (rc) { + std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n"; + } } + return rc; } catch(const Exiv2::Error& e) @@ -695,37 +717,57 @@ namespace Action { return 1; } // Erase::run - int Erase::eraseThumbnail(Exiv2::ExifData& exifData) const + int Erase::eraseThumbnail(Exiv2::Image* image) const { + if (image->sizeExifData() == 0) { + return 0; + } int rc = 0; - std::string thumbExt = exifData.thumbnailExtension(); - if (thumbExt.empty()) { - std::cerr << path_ << ": Image does not contain an Exif thumbnail\n"; + Exiv2::ExifData exifData; + rc = exifData.read(image->exifData(), image->sizeExifData()); + if (rc) { + std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n"; } - else { - long delta = exifData.eraseThumbnail(); - if (Params::instance().verbose_) { - std::cout << "Erasing " << delta << " Bytes of thumbnail data" - << std::endl; - } - rc = exifData.write(path_); - if (rc) { - std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n"; + if (0 == rc) { + std::string thumbExt = exifData.thumbnailExtension(); + if (!thumbExt.empty()) { + long delta = exifData.eraseThumbnail(); + if (Params::instance().verbose_) { + std::cout << "Erasing " << delta + << " Bytes of thumbnail data" << std::endl; + } + Exiv2::DataBuf buf(exifData.copy()); + image->setExifData(buf.pData_, buf.size_); } } return rc; } - int Erase::eraseExifData(Exiv2::ExifData& exifData) const + int Erase::eraseExifData(Exiv2::Image* image) const { - if (Params::instance().verbose_) { + if (Params::instance().verbose_ && image->sizeExifData() > 0) { std::cout << "Erasing Exif data from the file" << std::endl; } - int rc = exifData.erase(path_); - if (rc) { - std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n"; + image->clearExifData(); + return 0; + } + + int Erase::eraseIptcData(Exiv2::Image* image) const + { + if (Params::instance().verbose_ && image->sizeIptcData() > 0) { + std::cout << "Erasing Iptc data from the file" << std::endl; } - return rc; + image->clearIptcData(); + return 0; + } + + int Erase::eraseComment(Exiv2::Image* image) const + { + if (Params::instance().verbose_ && image->comment().size() > 0) { + std::cout << "Erasing Jpeg comment from the file" << std::endl; + } + image->clearComment(); + return 0; } Erase::AutoPtr Erase::clone() const @@ -815,9 +857,19 @@ namespace Action { int Insert::run(const std::string& path) try { - std::string exvPath = Util::dirname(path) + SEPERATOR_STR - + Util::basename(path, true) + ".exv"; - return metacopy(exvPath, path); + int rc = 0; + if (Params::instance().target_ & Params::ctThumb) { + rc = insertThumbnail(path); + } + if ( rc == 0 + && Params::instance().target_ & Params::ctExif + || Params::instance().target_ & Params::ctIptc + || Params::instance().target_ & Params::ctComment) { + std::string exvPath = Util::dirname(path) + SEPERATOR_STR + + Util::basename(path, true) + ".exv"; + rc = metacopy(exvPath, path); + } + return rc; } catch(const Exiv2::Error& e) { @@ -826,6 +878,26 @@ namespace Action { return 1; } // Insert::run + int Insert::insertThumbnail(const std::string& path) const + { + std::string thumbPath = Util::dirname(path) + SEPERATOR_STR + + Util::basename(path, true) + "-thumb.jpg"; + if (!Util::fileExists(thumbPath, true)) { + std::cerr << thumbPath + << ": Failed to open the file\n"; + return -1; + } + Exiv2::ExifData exifData; + int rc = exifData.read(path); + if (rc) { + std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; + return rc; + } + exifData.setJpegThumbnail(thumbPath); + return exifData.write(path); + + } // Insert::insertThumbnail + Insert::AutoPtr Insert::clone() const { return AutoPtr(clone_()); diff --git a/src/actions.hpp b/src/actions.hpp index 9b020831..7bf100f0 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -42,6 +42,7 @@ namespace Exiv2 { class ExifData; + class Image; } // ***************************************************************************** @@ -222,11 +223,19 @@ namespace Action { /*! @brief Delete the thumbnail image, incl IFD1 metadata from the file. */ - int eraseThumbnail(Exiv2::ExifData& exifData) const; + int eraseThumbnail(Exiv2::Image* image) const; /*! @brief Erase the complete Exif data block from the file. */ - int eraseExifData(Exiv2::ExifData& exifData) const; + int eraseExifData(Exiv2::Image* image) const; + /*! + @brief Erase all Iptc data from the file. + */ + int eraseIptcData(Exiv2::Image* image) const; + /*! + @brief Erase Jpeg comment from the file. + */ + int eraseComment(Exiv2::Image* image) const; private: virtual Erase* clone_() const; @@ -268,6 +277,13 @@ namespace Action { typedef std::auto_ptr AutoPtr; AutoPtr clone() const; + /*! + @brief Insert a Jpeg thumbnail image from a file into file \path. + The filename of the thumbanail is expected to be the image + filename (\em path) minus its suffix plus "-thumb.jpg". + */ + int insertThumbnail(const std::string& path) const; + private: virtual Insert* clone_() const; diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 2a13d28e..8ff68370 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -162,17 +162,18 @@ void Params::help(std::ostream& os) const << " h : hexdump of the Exif data\n" << " i : Iptc data values\n" << " c : Jpeg comment\n" - << " -d tgt Delete target for the `delete' action. Possible targets are\n" - << " `e' to delete the whole Exif section (the default) and `t'\n" - << " to delete only the Exif thumbnail from the files.\n" - << " -i tgt Insert target(s) for the `insert' action. Possible targets are:\n" - << " a : all supported metadata (default)\n" - << " e : Exif data\n" + << " -d tgt Delete target(s) for the `delete' action. Possible targets are:\n" + << " a : all supported metadata (the default)\n" + << " e : Exif section\n" + << " t : Exif thumbnail only\n" << " i : Iptc data\n" << " c : Jpeg comment\n" + << " to delete only the Exif thumbnail from the files.\n" + << " -i tgt Insert target(s) for the `insert' action. Possible targets are\n" + << " the same as those for the -d option. Only Jpeg thumbnails can\n" + << " -thumb.jpg can be inserted.\n" << " -e tgt Extract target(s) for the `extract' action. Possible targets\n" - << " are the same as those for the -i option plus:\n" - << " t : extract the Exif thumbnail to an image file\n" + << " are the same as those for the -d option.\n" << " -r fmt Filename format for the `rename' action. The format string\n" << " follows strftime(3). Default filename format is " << format_ << ".\n\n"; @@ -258,20 +259,18 @@ int Params::option(int opt, const std::string& optarg, int optopt) switch (action_) { case Action::none: action_ = Action::erase; - switch (optarg[0]) { - case 'e': target_ = ctExif; break; - case 't': target_ = ctThumb; break; - default: - std::cerr << progname() << ": Unrecognized delete target `" - << optarg << "'\n"; + target_ = 0; + // fallthrough + case Action::erase: + rc = parseCommonTargets(optarg, "erase"); + if (rc > 0) { + target_ |= rc; + rc = 0; + } + else { rc = 1; - break; } break; - case Action::erase: - std::cerr << progname() - << ": Ignoring surplus option -d" << optarg << "\n"; - break; default: std::cerr << progname() << ": Option -d is not compatible with a previous option\n"; @@ -378,7 +377,6 @@ int Params::nonoption(const std::string& argv) } action = true; action_ = Action::erase; - target_ = ctExif; } if (argv == "ex" || argv == "extract") { if (action_ != Action::none && action_ != Action::extract) { @@ -489,7 +487,7 @@ namespace { { int rc = 0; int target = 0; - for (size_t i = 0; i < optarg.size(); ++i) { + for (size_t i = 0; rc == 0 && i < optarg.size(); ++i) { switch (optarg[i]) { case 'e': target |= Params::ctExif; break; case 'i': target |= Params::ctIptc; break; @@ -500,7 +498,7 @@ namespace { | Params::ctComment; break; default: std::cerr << Params::instance().progname() << ": Unrecognized " - << action << " target `" << optarg << "'\n"; + << action << " target `" << optarg[i] << "'\n"; rc = -1; break; } diff --git a/test/data/exiv2-test.out b/test/data/exiv2-test.out index 83635ca9..5e8d9dff 100644 --- a/test/data/exiv2-test.out +++ b/test/data/exiv2-test.out @@ -37,17 +37,18 @@ Options: h : hexdump of the Exif data i : Iptc data values c : Jpeg comment - -d tgt Delete target for the `delete' action. Possible targets are - `e' to delete the whole Exif section (the default) and `t' - to delete only the Exif thumbnail from the files. - -i tgt Insert target(s) for the `insert' action. Possible targets are: - a : all supported metadata (default) - e : Exif data + -d tgt Delete target(s) for the `delete' action. Possible targets are: + a : all supported metadata (the default) + e : Exif section + t : Exif thumbnail only i : Iptc data c : Jpeg comment + to delete only the Exif thumbnail from the files. + -i tgt Insert target(s) for the `insert' action. Possible targets are + the same as those for the -d option. Only Jpeg thumbnails can + -thumb.jpg can be inserted. -e tgt Extract target(s) for the `extract' action. Possible targets - are the same as those for the -i option plus: - t : extract the Exif thumbnail to an image file + are the same as those for the -d option. -r fmt Filename format for the `rename' action. The format string follows strftime(3). Default filename format is %Y%m%d_%H%M%S. @@ -991,63 +992,64 @@ Compare image data and extracted data ------------------------------------ Delete Thumbnail --------------------------------------------------------- File 1/9: exiv2-empty.jpg -exiv2-empty.jpg: No Exif data found in the file File 2/9: 20031214_000043.jpg -Erasing Exif data from the file +Erasing 6200 Bytes of thumbnail data File 3/9: 20000506_020544.jpg -Erasing Exif data from the file +Erasing 7923 Bytes of thumbnail data File 4/9: 20040329_224245.jpg -Erasing Exif data from the file +Erasing 9038 Bytes of thumbnail data File 5/9: 20010405_235039.jpg -Erasing Exif data from the file +Erasing 4756 Bytes of thumbnail data File 6/9: 20030925_201850.jpg Warning: Upper boundary of data for Makernote entry 25 is out of bounds: Offset = 1384, size = 48, exceeds buffer size by 24 Bytes; Truncating the data. -Erasing Exif data from the file +Erasing 9858 Bytes of thumbnail data File 7/9: 20001026_044550.jpg -Erasing Exif data from the file +Erasing 20910 Bytes of thumbnail data File 8/9: 20030926_111535.jpg -Erasing Exif data from the file +Erasing 9696 Bytes of thumbnail data File 9/9: 20040316_075137.jpg -Erasing Exif data from the file +Erasing 12104 Bytes of thumbnail data File 1/9: exiv2-empty.jpg exiv2-empty.jpg: No Exif data found in the file File 2/9: 20031214_000043.jpg -20031214_000043.jpg: No Exif data found in the file +20031214_000043.jpg: Image does not contain an Exif thumbnail File 3/9: 20000506_020544.jpg -20000506_020544.jpg: No Exif data found in the file +20000506_020544.jpg: Image does not contain an Exif thumbnail File 4/9: 20040329_224245.jpg -20040329_224245.jpg: No Exif data found in the file +20040329_224245.jpg: Image does not contain an Exif thumbnail File 5/9: 20010405_235039.jpg -20010405_235039.jpg: No Exif data found in the file +20010405_235039.jpg: Image does not contain an Exif thumbnail File 6/9: 20030925_201850.jpg -20030925_201850.jpg: No Exif data found in the file +Warning: Upper boundary of data for Makernote entry 25 is out of bounds: + Offset = 1384, size = 48, exceeds buffer size by 24 Bytes; Truncating the data. +20030925_201850.jpg: Image does not contain an Exif thumbnail File 7/9: 20001026_044550.jpg -20001026_044550.jpg: No Exif data found in the file +20001026_044550.jpg: Image does not contain an Exif thumbnail File 8/9: 20030926_111535.jpg -20030926_111535.jpg: No Exif data found in the file +20030926_111535.jpg: Image does not contain an Exif thumbnail File 9/9: 20040316_075137.jpg -20040316_075137.jpg: No Exif data found in the file +20040316_075137.jpg: Image does not contain an Exif thumbnail Delete Exif data --------------------------------------------------------- File 1/9: exiv2-empty.jpg -exiv2-empty.jpg: No Exif data found in the file File 2/9: 20031214_000043.jpg -20031214_000043.jpg: No Exif data found in the file +Erasing Exif data from the file File 3/9: 20000506_020544.jpg -20000506_020544.jpg: No Exif data found in the file +Erasing Exif data from the file File 4/9: 20040329_224245.jpg -20040329_224245.jpg: No Exif data found in the file +Erasing Exif data from the file File 5/9: 20010405_235039.jpg -20010405_235039.jpg: No Exif data found in the file +Erasing Exif data from the file File 6/9: 20030925_201850.jpg -20030925_201850.jpg: No Exif data found in the file +Erasing Exif data from the file File 7/9: 20001026_044550.jpg -20001026_044550.jpg: No Exif data found in the file +Erasing Exif data from the file +Erasing Jpeg comment from the file File 8/9: 20030926_111535.jpg -20030926_111535.jpg: No Exif data found in the file +Erasing Exif data from the file File 9/9: 20040316_075137.jpg -20040316_075137.jpg: No Exif data found in the file +Erasing Exif data from the file File 1/9: exiv2-empty.jpg exiv2-empty.jpg: No Exif data found in the file File 2/9: 20031214_000043.jpg