Added metacopy and the ability to extract/insert different types of metadata

Added option to print the Jpeg comment
Changed semantics of print option `i' to Iptc (`t' for translated Exif data)
v0.27.3
Andreas Huggel 21 years ago
parent 79721d04e0
commit 41fbe55ebd

@ -20,13 +20,13 @@
*/
/*
File: actions.cpp
Version: $Name: $ $Revision: 1.36 $
Version: $Name: $ $Revision: 1.37 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 08-Dec-03, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.36 $ $RCSfile: actions.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.37 $ $RCSfile: actions.cpp,v $");
// *****************************************************************************
// included header files
@ -79,6 +79,15 @@ namespace {
// Convert a UTC time to a string "YYYY:MM:DD HH:MI:SS", "" on error
std::string time2Str(time_t time);
/*!
@brief Copy metadata from source to target according to Params::copyXyz
@param source Source file path
@param target Target file path. An *.exv file is created if target doesn't
exist.
@return 0 if successful, else an error code
*/
int metacopy(const std::string& source, const std::string& target);
}
// *****************************************************************************
@ -135,11 +144,12 @@ namespace Action {
path_ = path;
int rc = 0;
switch (Params::instance().printMode_) {
case Params::summary: rc = printSummary(); break;
case Params::interpreted: rc = printInterpreted(); break;
case Params::values: rc = printValues(); break;
case Params::hexdump: rc = printHexdump(); break;
case Params::iptc: rc = printIptc(); break;
case Params::pmSummary: rc = printSummary(); break;
case Params::pmInterpreted: rc = printInterpreted(); break;
case Params::pmValues: rc = printValues(); break;
case Params::pmHexdump: rc = printHexdump(); break;
case Params::pmIptc: rc = printIptc(); break;
case Params::pmComment: rc = printComment(); break;
}
return rc;
}
@ -509,7 +519,6 @@ namespace Action {
return 0;
} // Print::printIptc
int Print::printHexdump()
{
Exiv2::ExifData exifData;
@ -543,6 +552,34 @@ namespace Action {
return 0;
} // Print::printHexdump
int Print::printComment()
{
if (!Util::fileExists(path_, true)) {
std::cerr << path_
<< ": Failed to open the file\n";
return -1;
}
Exiv2::Image* pImage = Exiv2::ImageFactory::instance().open(path_);
if (!pImage) {
std::cerr << path_
<< ": The file contains data of an unknown image type\n";
return -2;
}
int rc = pImage->readMetadata();
pImage->detach();
if (rc) {
std::cerr << path_
<< ": Could not read metadata\n";
return 1;
}
if (Params::instance().verbose_) {
std::cout << "Jpeg comment: ";
}
std::cout << pImage->comment() << "\n";
delete pImage;
return 0;
} // Print::printComment
Print::AutoPtr Print::clone() const
{
return AutoPtr(clone_());
@ -645,9 +682,9 @@ namespace Action {
std::cerr << Exiv2::ExifData::strError(rc, path) << "\n";
return rc;
}
switch (Params::instance().delTarget_) {
case Params::delExif: rc = eraseExifData(exifData); break;
case Params::delThumb: rc = eraseThumbnail(exifData); break;
switch (Params::instance().target_) {
case Params::ctExif: rc = eraseExifData(exifData); break;
case Params::ctThumb: rc = eraseThumbnail(exifData); break;
}
return rc;
}
@ -703,32 +740,12 @@ namespace Action {
int Extract::run(const std::string& path)
try {
path_ = path;
Exiv2::ExifData exifData;
int rc = exifData.read(path);
if (rc) {
std::cerr << Exiv2::ExifData::strError(rc, path) << "\n";
return rc;
}
switch (Params::instance().extractTarget_) {
case Params::extExif: rc = writeExifData(exifData); break;
case Params::extThumb: rc = writeThumbnail(exifData); break;
int rc = 0;
if (Params::instance().target_ & Params::ctThumb) {
rc = writeThumbnail();
}
return rc;
}
catch(const Exiv2::Error& e)
{
std::cerr << "Exif exception in extract action for file " << path
<< ":\n" << e << "\n";
return 1;
} // Extract::run
int Extract::writeExifData(Exiv2::ExifData& exifData) const
{
std::string exvPath = Util::dirname(path_) + SEPERATOR_STR
+ Util::basename(path_, true) + ".exv";
if (Params::instance().verbose_) {
std::cout << "Writing Exif data to " << exvPath << "\n";
}
if (!Params::instance().force_ && Util::fileExists(exvPath)) {
std::cout << Params::instance().progname()
<< ": Overwrite `" << exvPath << "'? ";
@ -736,16 +753,23 @@ namespace Action {
std::cin >> s;
if (s[0] != 'y' && s[0] != 'Y') return 0;
}
int rc = exifData.writeExifData(exvPath);
if (rc) {
std::cerr << Exiv2::ExifData::strError(rc, exvPath) << "\n";
}
return rc;
return metacopy(path_, exvPath);
}
catch(const Exiv2::Error& e)
{
std::cerr << "Exif exception in extract action for file " << path
<< ":\n" << e << "\n";
return 1;
} // Extract::run
int Extract::writeThumbnail(const Exiv2::ExifData& exifData) const
int Extract::writeThumbnail() const
{
int rc = 0;
Exiv2::ExifData exifData;
int rc = exifData.read(path_);
if (rc) {
std::cerr << Exiv2::ExifData::strError(rc, path_) << "\n";
return rc;
}
std::string thumb = Util::dirname(path_) + SEPERATOR_STR
+ Util::basename(path_, true) + "-thumb";
std::string thumbExt = exifData.thumbnailExtension();
@ -772,7 +796,7 @@ namespace Action {
}
}
return rc;
}
} // Extract::writeThumbnail
Extract::AutoPtr Extract::clone() const
{
@ -788,20 +812,7 @@ namespace Action {
try {
std::string exvPath = Util::dirname(path) + SEPERATOR_STR
+ Util::basename(path, true) + ".exv";
Exiv2::ExifData exifData;
int rc = exifData.read(exvPath);
if (rc) {
std::cerr << Exiv2::ExifData::strError(rc, exvPath) << "\n";
return rc;
}
if (Params::instance().verbose_) {
std::cout << "Inserting metadata from " << exvPath << "\n";
}
rc = exifData.write(path);
if (rc) {
std::cerr << Exiv2::ExifData::strError(rc, path) << "\n";
}
return rc;
return metacopy(exvPath, path);
}
catch(const Exiv2::Error& e)
{
@ -949,4 +960,69 @@ namespace {
return os.str();
} // time2Str
int metacopy(const std::string& source, const std::string& target)
{
if (!Util::fileExists(source, true)) {
std::cerr << source
<< ": Failed to open the file\n";
return -1;
}
Exiv2::Image* pSource = Exiv2::ImageFactory::instance().open(source);
if (!pSource) {
std::cerr << source
<< ": The file contains data of an unknown image type\n";
return -2;
}
int rc = pSource->readMetadata();
pSource->detach();
if (rc) {
std::cerr << source
<< ": Could not read metadata\n";
return 1;
}
Exiv2::Image* pTarget = Exiv2::ImageFactory::instance().open(target);
if (!pTarget) {
pTarget = Exiv2::ImageFactory::instance().create(Exiv2::Image::exv,
target);
}
if (!pTarget) {
std::cerr << target
<< ": Could not open nor create the file\n";
return 2;
}
if ( Params::instance().target_ & Params::ctExif
&& pSource->sizeExifData() > 0) {
if (Params::instance().verbose_) {
std::cout << "Writing Exif data from " << source
<< " to " << target << "\n";
}
pTarget->setExifData(pSource->exifData(), pSource->sizeExifData());
}
if ( Params::instance().target_ & Params::ctIptc
&& pSource->sizeIptcData() > 0) {
if (Params::instance().verbose_) {
std::cout << "Writing Iptc data from " << source
<< " to " << target << "\n";
}
pTarget->setIptcData(pSource->iptcData(), pSource->sizeIptcData());
}
if ( Params::instance().target_ & Params::ctComment
&& !pSource->comment().empty()) {
if (Params::instance().verbose_) {
std::cout << "Writing Jpeg comment from " << source
<< " to " << target << "\n";
}
pTarget->setComment(pSource->comment());
}
rc = pTarget->writeMetadata();
if (rc) {
std::cerr << target <<
": Could not write metadata to file, rc = " << rc << "\n";
}
delete pSource;
delete pTarget;
return rc;
} // metacopy
}

@ -22,7 +22,7 @@
@file actions.hpp
@brief Implements base class Task, TaskFactory and the various supported
actions (derived from Task).
@version $Name: $ $Revision: 1.11 $
@version $Name: $ $Revision: 1.12 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Dec-03, ahu: created
@ -149,6 +149,8 @@ namespace Action {
typedef std::auto_ptr<Print> AutoPtr;
AutoPtr clone() const;
//! Print the Jpeg comment
int printComment();
//! Print uninterpreted Iptc information
int printIptc();
//! Print Exif summary information
@ -248,12 +250,7 @@ namespace Action {
"-thumb" and the appropriate suffix (".jpg" or ".tif"), depending
on the format of the Exif thumbnail image.
*/
int writeThumbnail(const Exiv2::ExifData& exifData) const;
/*!
@brief Write the Exif data to a file. The filename is composed by
replacing the suffix of the image filename with ".exf".
*/
int writeExifData(Exiv2::ExifData& exifData) const;
int writeThumbnail() const;
private:
virtual Extract* clone_() const;

@ -22,13 +22,13 @@
Abstract: Command line program to display and manipulate image %Exif data
File: exiv2.cpp
Version: $Name: $ $Revision: 1.14 $
Version: $Name: $ $Revision: 1.15 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 10-Dec-03, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.14 $ $RCSfile: exiv2.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.15 $ $RCSfile: exiv2.cpp,v $");
// *****************************************************************************
// included header files
@ -57,6 +57,15 @@ namespace {
// Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value
// in seconds if successful, else returns false.
bool parseTime(const std::string& ts, long& time);
/*!
@brief Parse the oparg string into a bitmap of common targets.
@param optarg Option arguments
@param action Action being processed
@return A bitmap of common targets or -1 in case of a parse error
*/
int parseCommonTargets(const std::string& optarg,
const std::string& action);
}
// *****************************************************************************
@ -131,12 +140,12 @@ void Params::help(std::ostream& os) const
{
usage(os);
os << "\nActions:\n"
<< " ad | adjust Adjust the metadata timestamp by the given time. This\n"
<< " ad | adjust Adjust Exif timestamps by the given time. This\n"
<< " action requires the option -a time.\n"
<< " pr | print Print the Exif (or other) image metadata.\n"
<< " pr | print Print Exif or Iptc image metadata.\n"
<< " rm | delete Delete the Exif section or thumbnail from the files.\n"
<< " ex | extract Extract the Exif data or Exif thumbnail to files.\n"
<< " in | insert Insert the Exif data from corresponding *.exv files.\n"
<< " in | insert Insert metadata from corresponding *.exv files.\n"
<< " ex | extract Extract metadata to *.exv and thumbnail image files.\n"
<< " mv | rename Rename files according to the Exif create timestamp.\n"
<< " The filename format can be set with -r format.\n"
<< "\nOptions:\n"
@ -146,16 +155,24 @@ void Params::help(std::ostream& os) const
<< " -f Do not prompt before overwriting existing files (force).\n"
<< " -a time Time adjustment in the format [-]HH[:MM[:SS]]. This option\n"
<< " is only used with the `adjust' action.\n"
<< " -p mode Print mode for the `print' action. Possible modes are `s'\n"
<< " for a summary (the default), `i' for interpreted Exif data,\n"
<< " `v' for plain Exif data values, `h' for a hexdump of the\n"
<< " Exif data and `I' for Iptc data values.\n"
<< " -p mode Print mode for the `print' action. Possible modes are:\n"
<< " s : print a summary of the Exif metadata (the default)\n"
<< " t : interpreted (translated) Exif data\n"
<< " v : plain Exif data values\n"
<< " 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 for the `insert' action. Possible targets are:\n"
<< " a : all supported metadata (default)\n"
<< " e : Exif data\n"
<< " i : Iptc data\n"
<< " c : Jpeg comment\n"
<< " -e tgt Extract target for the `extract' action. Possible targets\n"
<< " are `e' to extract the Exif data to a binary file (the\n"
<< " default) and `t' to extract only the Exif thumbnail.\n"
<< " are the same as those for the -i option plus:\n"
<< " t : extract the Exif thumbnail to an image file\n"
<< " -r fmt Filename format for the `rename' action. The format string\n"
<< " follows strftime(3). Default filename format is "
<< format_ << ".\n\n";
@ -213,11 +230,12 @@ int Params::option(int opt, const std::string& optarg, int optopt)
case Action::none:
action_ = Action::print;
switch (optarg[0]) {
case 's': printMode_ = summary; break;
case 'i': printMode_ = interpreted; break;
case 'v': printMode_ = values; break;
case 'h': printMode_ = hexdump; break;
case 'I': printMode_ = iptc; break;
case 's': printMode_ = pmSummary; break;
case 't': printMode_ = pmInterpreted; break;
case 'v': printMode_ = pmValues; break;
case 'h': printMode_ = pmHexdump; break;
case 'i': printMode_ = pmIptc; break;
case 'c': printMode_ = pmComment; break;
default:
std::cerr << progname() << ": Unrecognized print mode `"
<< optarg << "'\n";
@ -241,8 +259,8 @@ int Params::option(int opt, const std::string& optarg, int optopt)
case Action::none:
action_ = Action::erase;
switch (optarg[0]) {
case 'e': delTarget_ = delExif; break;
case 't': delTarget_ = delThumb; break;
case 'e': target_ = ctExif; break;
case 't': target_ = ctThumb; break;
default:
std::cerr << progname() << ": Unrecognized delete target `"
<< optarg << "'\n";
@ -265,23 +283,44 @@ int Params::option(int opt, const std::string& optarg, int optopt)
switch (action_) {
case Action::none:
action_ = Action::extract;
switch (optarg[0]) {
case 'e': extractTarget_ = extExif; break;
case 't': extractTarget_ = extThumb; break;
default:
std::cerr << progname() << ": Unrecognized extract target `"
<< optarg << "'\n";
target_ = 0;
// fallthrough
case Action::extract:
rc = parseCommonTargets(optarg, "extract");
if (rc > 0) {
target_ |= rc;
rc = 0;
}
else {
rc = 1;
break;
}
break;
case Action::extract:
default:
std::cerr << progname()
<< ": Ignoring surplus option -e" << optarg << "\n";
<< ": Option -e is not compatible with a previous option\n";
rc = 1;
break;
}
break;
case 'i':
switch (action_) {
case Action::none:
action_ = Action::insert;
target_ = 0;
// fallthrough
case Action::insert:
rc = parseCommonTargets(optarg, "insert");
if (rc > 0) {
target_ |= rc;
rc = 0;
}
else {
rc = 1;
}
break;
default:
std::cerr << progname()
<< ": Option -e is not compatible with a previous option\n";
<< ": Option -i is not compatible with a previous option\n";
rc = 1;
break;
}
@ -444,4 +483,28 @@ namespace {
return true;
} // parseTime
int parseCommonTargets(const std::string& optarg,
const std::string& action)
{
int rc = 0;
int target = 0;
for (size_t i = 0; i < optarg.size(); ++i) {
switch (optarg[i]) {
case 'e': target |= Params::ctExif; break;
case 'i': target |= Params::ctIptc; break;
case 'c': target |= Params::ctComment; break;
case 't': target |= Params::ctThumb; break;
case 'a': target |= Params::ctExif
| Params::ctIptc
| Params::ctComment; break;
default:
std::cerr << Params::instance().progname() << ": Unrecognized "
<< action << " target `" << optarg << "'\n";
rc = -1;
break;
}
}
return rc ? rc : target;
} // parseCommonTargets
}

@ -21,7 +21,7 @@
/*!
@file exiv2.hpp
@brief Defines class Params, used for the command line handling of exiv2
@version $Name: $ $Revision: 1.4 $
@version $Name: $ $Revision: 1.5 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 08-Dec-03, ahu: created
@ -86,11 +86,10 @@ public:
static Params& instance();
//! Enumerates print modes
enum PrintMode { summary, interpreted, values, hexdump, iptc };
//! Enumerates delete targets
enum DelTarget { delExif, delThumb };
//! Enumerates extract targets
enum ExtractTarget { extExif, extThumb };
enum PrintMode { pmSummary, pmInterpreted, pmValues, pmHexdump, pmIptc,
pmComment };
//! Enumerates common targets, bitmap
enum commonTarget { ctExif = 1, ctIptc = 2, ctComment = 4, ctThumb = 8 };
bool help_; //!< Help option flag.
bool version_; //!< Version option flag.
@ -98,10 +97,9 @@ public:
bool force_; //!< Force overwrites flag.
bool adjust_; //!< Adjustment flag.
PrintMode printMode_; //!< Print mode.
DelTarget delTarget_; //!< What to delete.
ExtractTarget extractTarget_; //!< What to extract.
//! %Action (integer rather than TaskType to avoid dependency).
int action_;
int target_; //!< What common target to process.
long adjustment_; //!< Adjustment in seconds.
std::string format_; //!< Filename format (-r option arg).
@ -114,18 +112,17 @@ public:
private:
/*!
@brief Default constructor. Note that optstring_ is initialized here.
Private to force instantiation through instance().
The c'tor is private to force instantiation through instance().
*/
Params() : optstring_(":hVvfa:r:p:d:e:"),
Params() : optstring_(":hVvfa:r:p:d:e:i:"),
help_(false),
version_(false),
verbose_(false),
force_(false),
adjust_(false),
printMode_(summary),
delTarget_(delExif),
extractTarget_(extExif),
printMode_(pmSummary),
action_(0),
target_(ctExif|ctIptc|ctComment),
adjustment_(0),
format_("%Y%m%d_%H%M%S"),
first_(true) {}

Loading…
Cancel
Save