Added Key, ExifKey and IptcKey class hierarchy

Changed Exif keys to 'Exif.ifdItem.tagName'
v0.27.3
Andreas Huggel 21 years ago
parent 84a121bbe2
commit 0147a77c7b

@ -20,13 +20,13 @@
*/ */
/* /*
File: actions.cpp File: actions.cpp
Version: $Name: $ $Revision: 1.32 $ Version: $Name: $ $Revision: 1.33 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 08-Dec-03, ahu: created History: 08-Dec-03, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.32 $ $RCSfile: actions.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.33 $ $RCSfile: actions.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -163,25 +163,26 @@ namespace Action {
} }
// Camera make // Camera make
printTag(exifData, "Image.OtherTags.Make", "Camera make"); printTag(exifData, "Exif.Image.Make", "Camera make");
// Camera model // Camera model
printTag(exifData, "Image.OtherTags.Model", "Camera model"); printTag(exifData, "Exif.Image.Model", "Camera model");
// Image Timestamp // Image Timestamp
printTag(exifData, "Image.DateTime.DateTimeOriginal", "Image timestamp"); printTag(exifData, "Exif.Photo.DateTimeOriginal", "Image timestamp");
// Image number // Image number
// Todo: Image number for cameras other than Canon // Todo: Image number for cameras other than Canon
printTag(exifData, "Makernote.Canon.ImageNumber", "Image number"); printTag(exifData, "Exif.Canon.ImageNumber", "Image number");
// Exposure time // Exposure time
// From ExposureTime, failing that, try ShutterSpeedValue // From ExposureTime, failing that, try ShutterSpeedValue
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Exposure time" << ": "; << "Exposure time" << ": ";
Exiv2::ExifData::const_iterator md; Exiv2::ExifData::const_iterator md;
if (0 == printTag(exifData, "Image.CaptureConditions.ExposureTime")) { if (0 == printTag(exifData, "Exif.Photo.ExposureTime")) {
md = exifData.findKey("Image.CaptureConditions.ShutterSpeedValue"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Photo.ShutterSpeedValue"));
if (md != exifData.end()) { if (md != exifData.end()) {
double tmp = exp(log(2.0) * md->toFloat()) + 0.5; double tmp = exp(log(2.0) * md->toFloat()) + 0.5;
if (tmp > 1) { if (tmp > 1) {
@ -198,8 +199,9 @@ namespace Action {
// Get if from FNumber and, failing that, try ApertureValue // Get if from FNumber and, failing that, try ApertureValue
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Aperture" << ": "; << "Aperture" << ": ";
if (0 == printTag(exifData, "Image.CaptureConditions.FNumber")) { if (0 == printTag(exifData, "Exif.Photo.FNumber")) {
md = exifData.findKey("Image.CaptureConditions.ApertureValue"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Photo.ApertureValue"));
if (md != exifData.end()) { if (md != exifData.end()) {
std::cout << std::fixed << std::setprecision(1) std::cout << std::fixed << std::setprecision(1)
<< "F" << exp(log(2.0) * md->toFloat() / 2); << "F" << exp(log(2.0) * md->toFloat() / 2);
@ -208,16 +210,16 @@ namespace Action {
std::cout << "\n"; std::cout << "\n";
// Exposure bias // Exposure bias
printTag(exifData, "Image.CaptureConditions.ExposureBiasValue", "Exposure bias"); printTag(exifData, "Exif.Photo.ExposureBiasValue", "Exposure bias");
// Flash // Flash
printTag(exifData, "Image.CaptureConditions.Flash", "Flash"); printTag(exifData, "Exif.Photo.Flash", "Flash");
// Todo: Flash bias, flash energy // Todo: Flash bias, flash energy
// Todo: Implement this for other cameras // Todo: Implement this for other cameras
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Flash bias" << ": "; << "Flash bias" << ": ";
md = exifData.findKey("Makernote.Canon.CameraSettings2"); md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings2"));
if (md != exifData.end() && md->count() >= 15) { if (md != exifData.end() && md->count() >= 15) {
Exiv2::CanonMakerNote::print0x0004_15(std::cout, md->toLong(15)); Exiv2::CanonMakerNote::print0x0004_15(std::cout, md->toLong(15));
} }
@ -227,8 +229,9 @@ namespace Action {
// Todo: Calculate 35 mm equivalent a la jhead // Todo: Calculate 35 mm equivalent a la jhead
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Focal length" << ": "; << "Focal length" << ": ";
if (1 == printTag(exifData, "Image.CaptureConditions.FocalLength")) { if (1 == printTag(exifData, "Exif.Photo.FocalLength")) {
md = exifData.findKey("Image.CaptureConditions.FocalLengthIn35mmFilm"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Photo.FocalLengthIn35mmFilm"));
if (md != exifData.end()) { if (md != exifData.end()) {
std::cout << " (35 mm equivalent: " << *md << ")"; std::cout << " (35 mm equivalent: " << *md << ")";
} }
@ -238,8 +241,9 @@ namespace Action {
// Subject distance // Subject distance
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Subject distance" << ": "; << "Subject distance" << ": ";
if (0 == printTag(exifData, "Image.CaptureConditions.SubjectDistance")) { if (0 == printTag(exifData, "Exif.Photo.SubjectDistance")) {
md = exifData.findKey("Makernote.Canon.CameraSettings2"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Canon.CameraSettings2"));
if (md != exifData.end() && md->count() >= 19) { if (md != exifData.end() && md->count() >= 19) {
Exiv2::CanonMakerNote::print0x0004_19(std::cout, md->toLong(19)); Exiv2::CanonMakerNote::print0x0004_19(std::cout, md->toLong(19));
} }
@ -251,20 +255,21 @@ namespace Action {
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "ISO speed" << ": "; << "ISO speed" << ": ";
bool done = false; bool done = false;
if (0 == printTag(exifData, "Image.CaptureConditions.ISOSpeedRatings")) { if (0 == printTag(exifData, "Exif.Photo.ISOSpeedRatings")) {
md = exifData.findKey("Makernote.Canon.CameraSettings1"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Canon.CameraSettings1"));
if (md != exifData.end() && md->count() >= 16) { if (md != exifData.end() && md->count() >= 16) {
Exiv2::CanonMakerNote::print0x0001_16(std::cout, md->toLong(16)); Exiv2::CanonMakerNote::print0x0001_16(std::cout, md->toLong(16));
done = true; done = true;
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon1.ISOSpeed"); done = printTag(exifData, "Exif.Nikon1.ISOSpeed");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon2.ISOSpeed"); done = printTag(exifData, "Exif.Nikon2.ISOSpeed");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon3.ISOSpeed"); done = printTag(exifData, "Exif.Nikon3.ISOSpeed");
} }
} }
std::cout << "\n"; std::cout << "\n";
@ -273,8 +278,9 @@ namespace Action {
// From ExposureProgram or Canon Makernote // From ExposureProgram or Canon Makernote
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Exposure mode" << ": "; << "Exposure mode" << ": ";
if (0 == printTag(exifData, "Image.CaptureConditions.ExposureProgram")) { if (0 == printTag(exifData, "Exif.Photo.ExposureProgram")) {
md = exifData.findKey("Makernote.Canon.CameraSettings1"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Canon.CameraSettings1"));
if (md != exifData.end() && md->count() >= 20) { if (md != exifData.end() && md->count() >= 20) {
Exiv2::CanonMakerNote::print0x0001_20(std::cout, md->toLong(20)); Exiv2::CanonMakerNote::print0x0001_20(std::cout, md->toLong(20));
} }
@ -282,20 +288,21 @@ namespace Action {
std::cout << "\n"; std::cout << "\n";
// Metering mode // Metering mode
printTag(exifData, "Image.CaptureConditions.MeteringMode", "Metering mode"); printTag(exifData, "Exif.Photo.MeteringMode", "Metering mode");
// Macro mode // Macro mode
// Todo: Implement this for other cameras // Todo: Implement this for other cameras
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Macro mode" << ": "; << "Macro mode" << ": ";
done = false; done = false;
md = exifData.findKey("Makernote.Canon.CameraSettings1"); md = exifData.findKey(
Exiv2::ExifKey("Exif.Canon.CameraSettings1"));
if (md != exifData.end() && md->count() >= 1) { if (md != exifData.end() && md->count() >= 1) {
Exiv2::CanonMakerNote::print0x0001_01(std::cout, md->toLong(1)); Exiv2::CanonMakerNote::print0x0001_01(std::cout, md->toLong(1));
done = true; done = true;
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Fujifilm.Macro"); done = printTag(exifData, "Exif.Fujifilm.Macro");
} }
std::cout << "\n"; std::cout << "\n";
@ -304,25 +311,25 @@ namespace Action {
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "Image quality" << ": "; << "Image quality" << ": ";
done = false; done = false;
md = exifData.findKey("Makernote.Canon.CameraSettings1"); md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings1"));
if (md != exifData.end() && md->count() >= 3) { if (md != exifData.end() && md->count() >= 3) {
Exiv2::CanonMakerNote::print0x0001_03(std::cout, md->toLong(3)); Exiv2::CanonMakerNote::print0x0001_03(std::cout, md->toLong(3));
done = true; done = true;
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Fujifilm.Quality"); done = printTag(exifData, "Exif.Fujifilm.Quality");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Sigma.Quality"); done = printTag(exifData, "Exif.Sigma.Quality");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon1.Quality"); done = printTag(exifData, "Exif.Nikon1.Quality");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon2.Quality"); done = printTag(exifData, "Exif.Nikon2.Quality");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon3.Quality"); done = printTag(exifData, "Exif.Nikon3.Quality");
} }
std::cout << "\n"; std::cout << "\n";
@ -331,9 +338,9 @@ namespace Action {
<< "Exif Resolution" << ": "; << "Exif Resolution" << ": ";
long xdim = 0; long xdim = 0;
long ydim = 0; long ydim = 0;
md = exifData.findKey("Image.ImageConfig.PixelXDimension"); md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension"));
if (md != exifData.end()) xdim = md->toLong(); if (md != exifData.end()) xdim = md->toLong();
md = exifData.findKey("Image.ImageConfig.PixelYDimension"); md = exifData.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension"));
if (md != exifData.end()) ydim = md->toLong(); if (md != exifData.end()) ydim = md->toLong();
if (xdim != 0 && ydim != 0) { if (xdim != 0 && ydim != 0) {
std::cout << xdim << " x " << ydim; std::cout << xdim << " x " << ydim;
@ -345,25 +352,25 @@ namespace Action {
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< "White balance" << ": "; << "White balance" << ": ";
done = false; done = false;
md = exifData.findKey("Makernote.Canon.CameraSettings2"); md = exifData.findKey(Exiv2::ExifKey("Exif.Canon.CameraSettings2"));
if (md != exifData.end() && md->count() >= 7) { if (md != exifData.end() && md->count() >= 7) {
Exiv2::CanonMakerNote::print0x0004_07(std::cout, md->toLong(7)); Exiv2::CanonMakerNote::print0x0004_07(std::cout, md->toLong(7));
done = true; done = true;
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Fujifilm.WhiteBalance"); done = printTag(exifData, "Exif.Fujifilm.WhiteBalance");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Sigma.WhiteBalance"); done = printTag(exifData, "Exif.Sigma.WhiteBalance");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon1.WhiteBalance"); done = printTag(exifData, "Exif.Nikon1.WhiteBalance");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon2.WhiteBalance"); done = printTag(exifData, "Exif.Nikon2.WhiteBalance");
} }
if (!done) { if (!done) {
done = printTag(exifData, "Makernote.Nikon3.WhiteBalance"); done = printTag(exifData, "Exif.Nikon3.WhiteBalance");
} }
std::cout << "\n"; std::cout << "\n";
@ -381,10 +388,10 @@ namespace Action {
std::cout << "\n"; std::cout << "\n";
// Copyright // Copyright
printTag(exifData, "Image.OtherTags.Copyright", "Copyright"); printTag(exifData, "Exif.Image.Copyright", "Copyright");
// Exif Comment // Exif Comment
printTag(exifData, "Image.UserInfo.UserComment", "Exif comment"); printTag(exifData, "Exif.Photo.UserComment", "Exif comment");
std::cout << std::endl; std::cout << std::endl;
} // Print::printSummary } // Print::printSummary
@ -399,7 +406,8 @@ namespace Action {
std::cout << std::setw(align_) << std::setfill(' ') << std::left std::cout << std::setw(align_) << std::setfill(' ') << std::left
<< label << ": "; << label << ": ";
} }
Exiv2::ExifData::const_iterator md = exifData.findKey(key); Exiv2::ExifKey ek(key);
Exiv2::ExifData::const_iterator md = exifData.findKey(ek);
if (md != exifData.end()) { if (md != exifData.end()) {
std::cout << *md; std::cout << *md;
rc = 1; rc = 1;
@ -484,7 +492,7 @@ namespace Action {
std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; std::cerr << Exiv2::ExifData::strError(rc, path) << "\n";
return rc; return rc;
} }
std::string key = "Image.DateTime.DateTimeOriginal"; Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
Exiv2::ExifData::iterator md = exifData.findKey(key); Exiv2::ExifData::iterator md = exifData.findKey(key);
if (md == exifData.end()) { if (md == exifData.end()) {
std::cerr << "Metadatum with key `" << key << "' " std::cerr << "Metadatum with key `" << key << "' "
@ -753,9 +761,9 @@ namespace Action {
std::cerr << Exiv2::ExifData::strError(rc, path) << "\n"; std::cerr << Exiv2::ExifData::strError(rc, path) << "\n";
return rc; return rc;
} }
rc = adjustDateTime(exifData, "Image.OtherTags.DateTime", path); rc = adjustDateTime(exifData, "Exif.Image.DateTime", path);
rc += adjustDateTime(exifData, "Image.DateTime.DateTimeOriginal", path); rc += adjustDateTime(exifData, "Exif.Photo.DateTimeOriginal", path);
rc += adjustDateTime(exifData, "Image.DateTime.DateTimeDigitized", path); rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path);
if (rc) return 1; if (rc) return 1;
rc = exifData.write(path); rc = exifData.write(path);
if (rc) { if (rc) {
@ -784,7 +792,8 @@ namespace Action {
const std::string& key, const std::string& key,
const std::string& path) const const std::string& path) const
{ {
Exiv2::ExifData::iterator md = exifData.findKey(key); Exiv2::ExifKey ek(key);
Exiv2::ExifData::iterator md = exifData.findKey(ek);
if (md == exifData.end()) { if (md == exifData.end()) {
// Key not found. That's ok, we do nothing. // Key not found. That's ok, we do nothing.
return 0; return 0;
@ -792,7 +801,7 @@ namespace Action {
std::string timeStr = md->toString(); std::string timeStr = md->toString();
if (timeStr == "" || timeStr[0] == ' ') { if (timeStr == "" || timeStr[0] == ' ') {
std::cerr << path << ": Timestamp of metadatum with key `" std::cerr << path << ": Timestamp of metadatum with key `"
<< key << "' not set\n"; << ek << "' not set\n";
return 1; return 1;
} }
time_t time = str2Time(timeStr); time_t time = str2Time(timeStr);
@ -802,7 +811,7 @@ namespace Action {
return 1; return 1;
} }
if (Params::instance().verbose_) { if (Params::instance().verbose_) {
std::cout << "Adjusting `" << key << "' by" std::cout << "Adjusting `" << ek << "' by"
<< (adjustment_ < 0 ? " " : " +") << (adjustment_ < 0 ? " " : " +")
<< adjustment_ << " s to "; << adjustment_ << " s to ";
} }

@ -3,7 +3,7 @@
Abstract: Sample program showing how to add, modify and delete Exif metadata. Abstract: Sample program showing how to add, modify and delete Exif metadata.
File: addmoddel.cpp File: addmoddel.cpp
Version: $Name: $ $Revision: 1.3 $ Version: $Name: $ $Revision: 1.4 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created History: 26-Jan-04, ahu: created
*/ */
@ -28,7 +28,7 @@ try {
// Set the value to a string // Set the value to a string
v->read("1999:12:31 23:59:59"); v->read("1999:12:31 23:59:59");
// Add the value together with its key to the Exif data container // Add the value together with its key to the Exif data container
std::string key = "Image.DateTime.DateTimeOriginal"; Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
exifData.add(key, v); exifData.add(key, v);
std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n"; std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n";
@ -43,7 +43,7 @@ try {
rv->value_.push_back(std::make_pair(2,3)); rv->value_.push_back(std::make_pair(2,3));
rv->value_.push_back(std::make_pair(3,4)); rv->value_.push_back(std::make_pair(3,4));
// Add the key and value pair to the Exif data // Add the key and value pair to the Exif data
key = "Image.ImageCharacteristics.PrimaryChromaticities"; key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
exifData.add(key, rv); exifData.add(key, rv);
std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n"; std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n";
@ -54,7 +54,7 @@ try {
// Modify Exif data // Modify Exif data
// Find the timestamp metadatum by its key // Find the timestamp metadatum by its key
key = "Image.DateTime.DateTimeOriginal"; key = Exiv2::ExifKey("Exif.Photo.DateTimeOriginal");
Exiv2::ExifData::iterator pos = exifData.findKey(key); Exiv2::ExifData::iterator pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error("Key not found"); if (pos == exifData.end()) throw Exiv2::Error("Key not found");
// Modify the value // Modify the value
@ -65,7 +65,7 @@ try {
<< "\", new value \"" << pos->value() << "\"\n"; << "\", new value \"" << pos->value() << "\"\n";
// Find the other key // Find the other key
key = "Image.ImageCharacteristics.PrimaryChromaticities"; key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
pos = exifData.findKey(key); pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error("Key not found"); if (pos == exifData.end()) throw Exiv2::Error("Key not found");
// Get a pointer to a copy of the value // Get a pointer to a copy of the value
@ -86,7 +86,7 @@ try {
// Delete metadata from the Exif data container // Delete metadata from the Exif data container
// Delete the metadatum at iterator position pos // Delete the metadatum at iterator position pos
key = "Image.ImageCharacteristics.PrimaryChromaticities"; key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
pos = exifData.findKey(key); pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error("Key not found"); if (pos == exifData.end()) throw Exiv2::Error("Key not found");
exifData.erase(pos); exifData.erase(pos);

@ -20,7 +20,7 @@
*/ */
/* /*
File: canonmn.cpp File: canonmn.cpp
Version: $Name: $ $Revision: 1.12 $ Version: $Name: $ $Revision: 1.13 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 18-Feb-04, ahu: created History: 18-Feb-04, ahu: created
07-Mar-04, ahu: isolated as a separate component 07-Mar-04, ahu: isolated as a separate component
@ -30,7 +30,7 @@
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.12 $ $RCSfile: canonmn.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.13 $ $RCSfile: canonmn.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -68,7 +68,7 @@ namespace Exiv2 {
}; };
CanonMakerNote::CanonMakerNote(bool alloc) CanonMakerNote::CanonMakerNote(bool alloc)
: IfdMakerNote(canonMnTagInfo, alloc), sectionName_("Canon") : IfdMakerNote(canonMnTagInfo, alloc), ifdItem_("Canon")
{ {
} }

@ -23,7 +23,7 @@
@brief Canon MakerNote implemented according to the specification @brief Canon MakerNote implemented according to the specification
<a href="http://www.burren.cx/david/canon.html"> <a href="http://www.burren.cx/david/canon.html">
EXIF MakerNote of Canon</a> by David Burren EXIF MakerNote of Canon</a> by David Burren
@version $Name: $ $Revision: 1.9 $ @version $Name: $ $Revision: 1.10 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 18-Feb-04, ahu: created<BR> @date 18-Feb-04, ahu: created<BR>
@ -98,8 +98,8 @@ namespace Exiv2 {
//! @name Accessors //! @name Accessors
//@{ //@{
CanonMakerNote* clone(bool alloc =true) const; CanonMakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Canon") //! Return the name of the makernote item ("Canon")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -193,8 +193,8 @@ namespace Exiv2 {
*/ */
static const RegisterMakerNote register_; static const RegisterMakerNote register_;
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class CanonMakerNote }; // class CanonMakerNote

@ -20,13 +20,13 @@
*/ */
/* /*
File: datasets.cpp File: datasets.cpp
Version: $Name: $ $Revision: 1.3 $ Version: $Name: $ $Revision: 1.4 $
Author(s): Brad Schick (brad) <schick@robotbattle.com> Author(s): Brad Schick (brad) <schick@robotbattle.com>
History: 24-Jul-04, brad: created History: 24-Jul-04, brad: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.3 $ $RCSfile: datasets.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.4 $ $RCSfile: datasets.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -162,6 +162,8 @@ namespace Exiv2 {
0 0
}; };
const char* IptcDataSets::familyName_ = "Iptc";
int IptcDataSets::dataSetIdx(uint16 number, uint16 recordId) int IptcDataSets::dataSetIdx(uint16 number, uint16 recordId)
{ {
if( recordId != envelope && recordId != application2 ) return -1; if( recordId != envelope && recordId != application2 ) return -1;
@ -248,13 +250,15 @@ namespace Exiv2 {
std::string IptcDataSets::makeKey(const DataSet& dataSet) std::string IptcDataSets::makeKey(const DataSet& dataSet)
{ {
return "Iptc." + std::string(recordName(dataSet.recordId_)) return std::string(familyName())
+ "." + std::string(recordName(dataSet.recordId_))
+ "." + dataSet.name_; + "." + dataSet.name_;
} }
std::string IptcDataSets::makeKey(uint16 number, uint16 recordId) std::string IptcDataSets::makeKey(uint16 number, uint16 recordId)
{ {
return "Iptc." + std::string(recordName(recordId)) return std::string(familyName())
+ "." + std::string(recordName(recordId))
+ "." + std::string(dataSetName(number, recordId)); + "." + std::string(dataSetName(number, recordId));
} }

@ -21,7 +21,7 @@
/*! /*!
@file datasets.hpp @file datasets.hpp
@brief Iptc dataSet and type information @brief Iptc dataSet and type information
@version $Name: $ $Revision: 1.2 $ @version $Name: $ $Revision: 1.3 $
@author Brad Schick (brad) <schick@robotbattle.com> @author Brad Schick (brad) <schick@robotbattle.com>
@date 24-Jul-04, brad: created @date 24-Jul-04, brad: created
*/ */
@ -171,7 +171,10 @@ namespace Exiv2 {
static const uint16 PreviewVersion = 201; static const uint16 PreviewVersion = 201;
static const uint16 Preview = 202; static const uint16 Preview = 202;
//@} //@}
private:
static const char* familyName_;
private: private:
//! Prevent construction: not implemented. //! Prevent construction: not implemented.
IptcDataSets() {} IptcDataSets() {}
@ -181,6 +184,8 @@ namespace Exiv2 {
IptcDataSets& operator=(const IptcDataSets& rhs); IptcDataSets& operator=(const IptcDataSets& rhs);
public: public:
//! Return an identifier for Iptc datasets
static const char* familyName() { return familyName_; }
/*! /*!
@brief Return the name of the dataset. @brief Return the name of the dataset.
@param number The dataset number @param number The dataset number
@ -240,12 +245,12 @@ namespace Exiv2 {
static uint16 recordId(const std::string& recordName); static uint16 recordId(const std::string& recordName);
/*! /*!
@brief Return the key for the dataSet number and record id. The key is @brief Return the key for the dataSet number and record id. The key is
of the form 'recordName.dataSetName'. of the form '<b>Iptc</b>.recordName.dataSetName'.
*/ */
static std::string makeKey(uint16 number, uint16 recordId); static std::string makeKey(uint16 number, uint16 recordId);
/*! /*!
@brief Return the key for the dataSet. The key is of the form @brief Return the key for the dataSet. The key is of the form
'recordName.dataSetName'. '<b>Iptc</b>.recordName.dataSetName'.
*/ */
static std::string makeKey(const DataSet& dataSet); static std::string makeKey(const DataSet& dataSet);
/*! /*!

@ -20,14 +20,14 @@
*/ */
/* /*
File: exif.cpp File: exif.cpp
Version: $Name: $ $Revision: 1.53 $ Version: $Name: $ $Revision: 1.54 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created History: 26-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component 11-Feb-04, ahu: isolated as a component
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.53 $ $RCSfile: exif.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.54 $ $RCSfile: exif.cpp,v $");
// Define DEBUG_MAKERNOTE to output debug information to std::cerr // Define DEBUG_MAKERNOTE to output debug information to std::cerr
#undef DEBUG_MAKERNOTE #undef DEBUG_MAKERNOTE
@ -73,37 +73,127 @@ namespace {
// class member definitions // class member definitions
namespace Exiv2 { namespace Exiv2 {
Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder) ExifKey::ExifKey(const std::string& key)
: idx_(0), pMakerNote_(0), key_(key)
{
decomposeKey();
}
ExifKey::ExifKey(const Entry& e)
: tag_(e.tag()), ifdId_(e.ifdId()), idx_(e.idx()), : tag_(e.tag()), ifdId_(e.ifdId()), idx_(e.idx()),
pMakerNote_(e.makerNote()), pValue_(0), key_(makeKey(e)) pMakerNote_(e.makerNote()), key_(makeKey(e))
{ {
pValue_ = Value::create(TypeId(e.type()));
pValue_->read(e.data(), e.count() * e.typeSize(), byteOrder);
} }
Exifdatum::Exifdatum(const std::string& key, ExifKey::ExifKey(const ExifKey& rhs)
const Value* value, : tag_(rhs.tag_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
MakerNote* makerNote) pMakerNote_(rhs.pMakerNote_), key_(rhs.key_)
: idx_(0), pMakerNote_(makerNote), pValue_(0), key_(key) {
}
ExifKey& ExifKey::operator=(const ExifKey& rhs)
{
if (this == &rhs) return *this;
Key::operator=(rhs);
tag_ = rhs.tag_;
ifdId_ = rhs.ifdId_;
idx_ = rhs.idx_;
pMakerNote_ = rhs.pMakerNote_;
key_ = rhs.key_;
return *this;
}
void ExifKey::setMakerNote(MakerNote* pMakerNote)
{
if (ifdId_ == makerIfd && pMakerNote_ != pMakerNote) {
pMakerNote_ = pMakerNote;
decomposeKey();
}
}
std::string ExifKey::tagName() const
{
if (ifdId_ == makerIfd && pMakerNote_ != 0) {
return pMakerNote_->tagName(tag_);
}
return ExifTags::tagName(tag(), ifdId());
}
uint16 ExifKey::tag() const
{
if (tag_ == 0xffff) throw Error("Invalid key");
return tag_;
}
IfdId ExifKey::ifdId() const
{
if (ifdId_ == ifdIdNotSet) throw Error("Invalid key");
return ifdId_;
}
ExifKey* ExifKey::clone() const
{
return new ExifKey(*this);
}
std::string ExifKey::sectionName() const
{
if (ifdId_ == makerIfd && pMakerNote_ != 0) {
return pMakerNote_->ifdItem();
}
return ExifTags::sectionName(tag(), ifdId());
}
void ExifKey::decomposeKey()
{ {
if (value) pValue_ = value->clone(); std::pair<uint16, IfdId> p;
std::pair<uint16, IfdId> p = decomposeKey(key, makerNote); if (ifdId_ == makerIfd && pMakerNote_ != 0) {
if (p.first == 0xffff) throw Error("Invalid key"); p.first = pMakerNote_->decomposeKey(key_);
if (p.first == 0xffff) throw Error("Invalid key");
p.second = makerIfd;
}
else {
p = ExifTags::decomposeKey(key_);
// If it's couldn't be parsed, we assume it is an incomplete
// makernote key (pMakerNote_ not set)
if (p.second == ifdIdNotSet) p.second = makerIfd;
// No checks as this could still be an incomplete makernote key
}
tag_ = p.first; tag_ = p.first;
if (p.second == ifdIdNotSet) throw Error("Invalid key");
ifdId_ = p.second; ifdId_ = p.second;
} }
std::ostream& ExifKey::printTag(std::ostream& os, const Value& value) const
{
if (ifdId_ == makerIfd && pMakerNote_ != 0) {
return pMakerNote_->printTag(os, tag(), value);
}
return ExifTags::printTag(os, tag(), ifdId(), value);
}
Exifdatum::Exifdatum(const Entry& e, ByteOrder byteOrder)
: pKey_(new ExifKey(e)), pValue_(0)
{
pValue_ = Value::create(TypeId(e.type()));
pValue_->read(e.data(), e.count() * e.typeSize(), byteOrder);
}
Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue)
: pKey_(key.clone()), pValue_(0)
{
if (pValue) pValue_ = pValue->clone();
}
Exifdatum::~Exifdatum() Exifdatum::~Exifdatum()
{ {
delete pKey_;
delete pValue_; delete pValue_;
// do *not* delete the MakerNote
} }
Exifdatum::Exifdatum(const Exifdatum& rhs) Exifdatum::Exifdatum(const Exifdatum& rhs)
: Metadatum(rhs), tag_(rhs.tag_), ifdId_(rhs.ifdId_), idx_(rhs.idx_), : Metadatum(rhs), pKey_(0), pValue_(0)
pMakerNote_(rhs.pMakerNote_), pValue_(0), key_(rhs.key_)
{ {
if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy
if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy
} }
@ -111,14 +201,15 @@ namespace Exiv2 {
{ {
if (this == &rhs) return *this; if (this == &rhs) return *this;
Metadatum::operator=(rhs); Metadatum::operator=(rhs);
tag_ = rhs.tag_;
ifdId_ = rhs.ifdId_; delete pKey_;
idx_ = rhs.idx_; pKey_ = 0;
pMakerNote_ = rhs.pMakerNote_; if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy
delete pValue_; delete pValue_;
pValue_ = 0; pValue_ = 0;
if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy
key_ = rhs.key_;
return *this; return *this;
} // Exifdatum::operator= } // Exifdatum::operator=
@ -141,22 +232,6 @@ namespace Exiv2 {
pValue_->read(buf); pValue_->read(buf);
} }
std::string Exifdatum::tagName() const
{
if (ifdId_ == makerIfd && pMakerNote_ != 0) {
return pMakerNote_->tagName(tag_);
}
return ExifTags::tagName(tag_, ifdId_);
}
std::string Exifdatum::sectionName() const
{
if (ifdId_ == makerIfd && pMakerNote_ != 0) {
return pMakerNote_->sectionName(tag_);
}
return ExifTags::sectionName(tag_, ifdId_);
}
TiffThumbnail::TiffThumbnail() TiffThumbnail::TiffThumbnail()
: offset_(0), size_(0), pImage_(0), ifd_(ifd1, 0, false) : offset_(0), size_(0), pImage_(0), ifd_(ifd1, 0, false)
{ {
@ -229,17 +304,16 @@ namespace Exiv2 {
buflen += ifd1.size() + ifd1.dataSize(); buflen += ifd1.size() + ifd1.dataSize();
if (len < buflen) rc = 1; if (len < buflen) rc = 1;
} }
std::string key;
ExifData::const_iterator offsets; ExifData::const_iterator offsets;
ExifData::const_iterator sizes; ExifData::const_iterator sizes;
if (rc == 0) { if (rc == 0) {
// Copy thumbnail image data, remember the offsets used // Copy thumbnail image data, remember the offsets used
key = "Thumbnail.RecordingOffset.StripOffsets"; ExifKey key("Exif.Thumbnail.StripOffsets");
offsets = exifData.findKey(key); offsets = exifData.findKey(key);
if (offsets == exifData.end()) rc = 2; if (offsets == exifData.end()) rc = 2;
} }
if (rc == 0) { if (rc == 0) {
key = "Thumbnail.RecordingOffset.StripByteCounts"; ExifKey key("Exif.Thumbnail.StripByteCounts");
sizes = exifData.findKey(key); sizes = exifData.findKey(key);
if (sizes == exifData.end()) rc = 2; if (sizes == exifData.end()) rc = 2;
} }
@ -426,12 +500,12 @@ namespace Exiv2 {
const ExifData& exifData, const ExifData& exifData,
ByteOrder byteOrder) ByteOrder byteOrder)
{ {
std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat"; ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");
ExifData::const_iterator pos = exifData.findKey(key); ExifData::const_iterator pos = exifData.findKey(key);
if (pos == exifData.end()) return 2; if (pos == exifData.end()) return 2;
long offset = pos->toLong(); long offset = pos->toLong();
key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength"; ExifKey key2("Exif.Thumbnail.JPEGInterchangeFormatLength");
pos = exifData.findKey(key); pos = exifData.findKey(key2);
if (pos == exifData.end()) return 2; if (pos == exifData.end()) return 2;
long size = pos->toLong(); long size = pos->toLong();
if (len < offset + size) return 1; if (len < offset + size) return 1;
@ -466,7 +540,7 @@ namespace Exiv2 {
void JpegThumbnail::update(ExifData& exifData) const void JpegThumbnail::update(ExifData& exifData) const
{ {
std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat"; ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");
ExifData::iterator pos = exifData.findKey(key); ExifData::iterator pos = exifData.findKey(key);
if (pos == exifData.end()) { if (pos == exifData.end()) {
Value* value = Value::create(unsignedLong); Value* value = Value::create(unsignedLong);
@ -476,13 +550,13 @@ namespace Exiv2 {
} }
pos->setValue(toString(offset_)); pos->setValue(toString(offset_));
key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength"; ExifKey key2("Exif.Thumbnail.JPEGInterchangeFormatLength");
pos = exifData.findKey(key); pos = exifData.findKey(key2);
if (pos == exifData.end()) { if (pos == exifData.end()) {
Value *value = Value::create(unsignedLong); Value *value = Value::create(unsignedLong);
exifData.add(key, value); exifData.add(key2, value);
delete value; delete value;
pos = exifData.findKey(key); pos = exifData.findKey(key2);
} }
pos->setValue(toString(size_)); pos->setValue(toString(size_));
@ -600,7 +674,7 @@ namespace Exiv2 {
if (rc) { if (rc) {
// Todo: How to handle debug output like this // Todo: How to handle debug output like this
std::cerr << "Warning: Failed to read " std::cerr << "Warning: Failed to read "
<< pMakerNote_->sectionName(0) << pMakerNote_->ifdItem()
<< " Makernote, rc = " << rc << "\n"; << " Makernote, rc = " << rc << "\n";
delete pMakerNote_; delete pMakerNote_;
@ -896,9 +970,12 @@ namespace Exiv2 {
} }
} }
void ExifData::add(const std::string& key, Value* value) void ExifData::add(const ExifKey& key, Value* pValue)
{ {
add(Exifdatum(key, value)); // Todo: Implement a more suitable ExifKey c'tor
ExifKey k(key);
k.setMakerNote(pMakerNote_);
add(Exifdatum(k, pValue));
} }
void ExifData::add(const Exifdatum& exifdatum) void ExifData::add(const Exifdatum& exifdatum)
@ -907,16 +984,16 @@ namespace Exiv2 {
exifMetadata_.push_back(exifdatum); exifMetadata_.push_back(exifdatum);
} }
ExifData::const_iterator ExifData::findKey(const std::string& key) const ExifData::const_iterator ExifData::findKey(const ExifKey& key) const
{ {
return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
FindMetadatumByKey(key)); FindMetadatumByKey(key.key()));
} }
ExifData::iterator ExifData::findKey(const std::string& key) ExifData::iterator ExifData::findKey(const ExifKey& key)
{ {
return std::find_if(exifMetadata_.begin(), exifMetadata_.end(), return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
FindMetadatumByKey(key)); FindMetadatumByKey(key.key()));
} }
ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const
@ -1019,7 +1096,8 @@ namespace Exiv2 {
delete pThumbnail_; delete pThumbnail_;
pThumbnail_ = 0; pThumbnail_ = 0;
int rc = -1; int rc = -1;
const_iterator pos = findKey("Thumbnail.ImageStructure.Compression"); const_iterator pos
= findKey(ExifKey("Exif.Thumbnail.Compression"));
if (pos != end()) { if (pos != end()) {
long compression = pos->toLong(); long compression = pos->toLong();
if (compression == 6) { if (compression == 6) {
@ -1200,7 +1278,7 @@ namespace Exiv2 {
error += "Exif data contains a broken IFD"; error += "Exif data contains a broken IFD";
break; break;
case 7: case 7:
error += "Unsupported Exif or GPS data found in IFD 1"; error += "Unsupported Exif or GPS data found in IFD1";
break; break;
default: default:
@ -1272,13 +1350,9 @@ namespace Exiv2 {
makerNote->add(e); makerNote->add(e);
} // addToMakerNote } // addToMakerNote
std::ostream& operator<<(std::ostream& os, const Exifdatum& md) std::ostream& operator<<(std::ostream& os, const Exifdatum& md)
{ {
if (md.ifdId() == makerIfd && md.makerNote() != 0) { return md.pKey_->printTag(os, md.value());
return md.makerNote()->printTag(os, md.tag(), md.value());
}
return ExifTags::printTag(os, md.tag(), md.ifdId(), md.value());
} }
std::string makeKey(const Entry& entry) std::string makeKey(const Entry& entry)

@ -21,7 +21,7 @@
/*! /*!
@file exif.hpp @file exif.hpp
@brief Encoding and decoding of Exif data @brief Encoding and decoding of Exif data
@version $Name: $ $Revision: 1.49 $ @version $Name: $ $Revision: 1.50 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created @date 09-Jan-04, ahu: created
@ -60,30 +60,117 @@ namespace Exiv2 {
// ***************************************************************************** // *****************************************************************************
// class definitions // class definitions
//! Concrete keys for Exif metadata.
class ExifKey : public Key {
public:
//! @name Creators
//@{
/*!
@brief Constructor to create an Exif key from a key string.
@param key The key string.
@throw Error ("Invalid key") if the key cannot be parsed into three
parts or the first part of the key is not '<b>Exif</b>'.
*/
explicit ExifKey(const std::string& key);
//! Constructor to build an ExifKey from an IFD entry.
explicit ExifKey(const Entry& e);
//! Copy constructor
ExifKey(const ExifKey& rhs);
// A destructor is not needed, as we do *not* delete the makernote
//@}
//! @name Manipulators
//@{
/*!
@brief Assignment operator.
*/
ExifKey& operator=(const ExifKey& rhs);
//! Set the makernote pointer.
void setMakerNote(MakerNote* pMakerNote);
//@}
//! @name Accessors
//@{
virtual std::string key() const { return key_; }
virtual const char* familyName() const { return ExifTags::familyName(); }
/*!
@brief Return the name of the group (the second part of the key).
For Exif keys, the group name is the IFD name.
*/
virtual std::string groupName() const { return ifdName(); }
virtual std::string tagName() const;
/*!
@brief Return the tag.
@throw Error ("Invalid key") if the tag is not set.
*/
virtual uint16 tag() const;
virtual ExifKey* clone() const;
//! Interpret and print the value of an Exif tag
std::ostream& printTag(std::ostream& os, const Value& value) const;
/*!
@brief Return the IFD id
@throw Error ("Invalid key") if the IFD id is not set.
*/
IfdId ifdId() const;
//! Return the name of the IFD
const char* ifdName() const { return ExifTags::ifdName(ifdId()); }
//! Return the related image item
const char* ifdItem() const { return ExifTags::ifdItem(ifdId()); }
//! Return the name of the Exif section (deprecated)
std::string sectionName() const;
//! Return the index (unique id of this key within the original IFD)
int idx() const { return idx_; }
//! Return the pointer to the associated MakerNote
MakerNote* makerNote() const { return pMakerNote_; }
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Parse and convert the key string into tag, and IFD Id.
Forwards the request to MakerNote::decomposeKey if necessary.
Updates key_ and ifdId_ if the string can be decomposed,
or throws Error ("Invalid key").
@throw Error ("Invalid key") if pMakerNote_ is ot 0 and the key
cannot be parsed into family name, group name and tag name
parts.
*/
void decomposeKey();
//@}
private:
// DATA
uint16 tag_; //!< Tag value
IfdId ifdId_; //!< The IFD associated with this tag
int idx_; //!< Unique id of an entry within one IFD
MakerNote* pMakerNote_; //!< Pointer to the associated MakerNote
std::string key_; //!< Key
}; // class ExifKey
/*! /*!
@brief Information related to one Exif tag. @brief Information related to one Exif tag.
*/ */
class Exifdatum : public Metadatum { class Exifdatum : public Metadatum {
friend std::ostream& operator<<(std::ostream&, const Exifdatum&);
public: public:
//! @name Creators //! @name Creators
//@{ //@{
/*! /*!
@brief Constructor for new tags created by an application. The @brief Constructor for new tags created by an application. The
Exifdatum is created from a key / value pair. %Exifdatum copies %Exifdatum is created from a key / value pair. %Exifdatum copies
(clones) the value if one is provided. Alternatively, a program (clones) the key and value if one is provided. Alternatively,
can create an 'empty' Exifdatum with only a key and set the a program can create an 'empty' %Exifdatum with only a key
value using setValue(). and set the value using setValue().
@param key The key of the Exifdatum. @param key ExifKey.
@param value Pointer to a Exifdatum value. @param pValue Pointer to a Exifdatum value.
@param makerNote Pointer to the associated MakerNote (only needed for @throw Error ("Invalid key") if the key cannot be parsed and converted.
MakerNote tags). */
@throw Error ("Invalid key") if the key cannot be parsed and converted explicit Exifdatum(const ExifKey& key, const Value* pValue =0);
to a tag number and an IFD id or the section name does not match.
*/
explicit Exifdatum(const std::string& key,
const Value* value =0,
MakerNote* makerNote =0);
//! Constructor to build a Exifdatum from an IFD entry. //! Constructor to build a Exifdatum from an IFD entry.
Exifdatum(const Entry& e, ByteOrder byteOrder); Exifdatum(const Entry& e, ByteOrder byteOrder);
//! Copy constructor //! Copy constructor
@ -115,6 +202,30 @@ namespace Exiv2 {
//! @name Accessors //! @name Accessors
//@{ //@{
//! Return the key of the %Exifdatum.
std::string key() const
{ return pKey_ == 0 ? "" : pKey_->key(); }
//! Return the name of the group (the second part of the key)
std::string groupName() const
{ return pKey_ == 0 ? "" : pKey_->groupName(); }
//! Return the name of the tag (which is also the third part of the key)
std::string tagName() const
{ return pKey_ == 0 ? "" : pKey_->tagName(); }
//! Return the tag
uint16 tag() const
{ return pKey_ == 0 ? 0xffff : pKey_->tag(); }
//! Return the IFD id
IfdId ifdId() const
{ return pKey_ == 0 ? ifdIdNotSet : pKey_->ifdId(); }
//! Return the name of the IFD
const char* ifdName() const
{ return pKey_ == 0 ? "" : pKey_->ifdName(); }
//! Return the related image item (deprecated)
const char* ifdItem() const
{ return pKey_ == 0 ? "" : pKey_->ifdItem(); }
//! Return the index (unique id of this key within the original IFD)
int idx() const
{ return pKey_ == 0 ? 0 : pKey_->idx(); }
/*! /*!
@brief Write value to a data buffer and return the number @brief Write value to a data buffer and return the number
of bytes written. of bytes written.
@ -128,40 +239,21 @@ namespace Exiv2 {
*/ */
long copy(byte* buf, ByteOrder byteOrder) const long copy(byte* buf, ByteOrder byteOrder) const
{ return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); } { return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); }
/*!
@brief Return the key of the Exifdatum. The key is of the form
'ifdItem.sectionName.tagName'. Note however that the key
is not necessarily unique, i.e., an ExifData may contain
multiple metadata with the same key.
*/
std::string key() const { return key_; }
//! Return the related image item (the first part of the key)
const char* ifdItem() const { return ExifTags::ifdItem(ifdId_); }
//! Return the name of the section (the second part of the key)
std::string sectionName() const;
//! Return the name of the tag (which is also the third part of the key)
std::string tagName() const;
//! Return the tag
uint16 tag() const { return tag_; }
//! Return the type id of the value //! Return the type id of the value
TypeId typeId() const TypeId typeId() const
{ return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); } { return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); }
//! Return the name of the type //! Return the name of the type
const char* typeName() const { return TypeInfo::typeName(typeId()); } const char* typeName() const
{ return TypeInfo::typeName(typeId()); }
//! Return the size in bytes of one component of this type //! Return the size in bytes of one component of this type
long typeSize() const { return TypeInfo::typeSize(typeId()); } long typeSize() const
{ return TypeInfo::typeSize(typeId()); }
//! Return the number of components in the value //! Return the number of components in the value
long count() const { return pValue_ == 0 ? 0 : pValue_->count(); } long count() const
{ return pValue_ == 0 ? 0 : pValue_->count(); }
//! Return the size of the value in bytes //! Return the size of the value in bytes
long size() const { return pValue_ == 0 ? 0 : pValue_->size(); } long size() const
//! Return the IFD id { return pValue_ == 0 ? 0 : pValue_->size(); }
IfdId ifdId() const { return ifdId_; }
//! Return the name of the IFD
const char* ifdName() const { return ExifTags::ifdName(ifdId_); }
//! Return the index (unique id of this Exifdatum within the original IFD)
int idx() const { return idx_; }
//! Return the pointer to the associated MakerNote
MakerNote* makerNote() const { return pMakerNote_; }
//! Return the value as a string. //! Return the value as a string.
std::string toString() const std::string toString() const
{ return pValue_ == 0 ? "" : pValue_->toString(); } { return pValue_ == 0 ? "" : pValue_->toString(); }
@ -201,7 +293,8 @@ namespace Exiv2 {
@return A pointer to a copy (clone) of the value, 0 if the value is @return A pointer to a copy (clone) of the value, 0 if the value is
not set. not set.
*/ */
Value* getValue() const { return pValue_ == 0 ? 0 : pValue_->clone(); } Value* getValue() const
{ return pValue_ == 0 ? 0 : pValue_->clone(); }
/*! /*!
@brief Return a constant reference to the value. @brief Return a constant reference to the value.
@ -227,17 +320,13 @@ namespace Exiv2 {
private: private:
// DATA // DATA
uint16 tag_; //!< Tag value ExifKey* pKey_; //!< Key
IfdId ifdId_; //!< The IFD associated with this tag
int idx_; //!< Unique id of an entry within one IFD
MakerNote* pMakerNote_; //!< Pointer to the associated MakerNote
Value* pValue_; //!< Pointer to the value Value* pValue_; //!< Pointer to the value
std::string key_; //!< Key
}; // class Exifdatum }; // class Exifdatum
/*! /*!
@brief Output operator for Exifdatum types, printing the interpreted @brief Output operator for Exifdatum types, prints the interpreted
tag value. tag value.
*/ */
std::ostream& operator<<(std::ostream& os, const Exifdatum& md); std::ostream& operator<<(std::ostream& os, const Exifdatum& md);
@ -579,11 +668,12 @@ namespace Exiv2 {
ByteOrder byteOrder); ByteOrder byteOrder);
/*! /*!
@brief Add a Exifdatum from the supplied key and value pair. This @brief Add a Exifdatum from the supplied key and value pair. This
method copies (clones) the value. No duplicate checks are method copies (clones) key and value and adds a pointer to
the MakerNote to the cloned key. No duplicate checks are
performed, i.e., it is possible to add multiple metadata with performed, i.e., it is possible to add multiple metadata with
the same key. the same key.
*/ */
void add(const std::string& key, Value* value); void add(const ExifKey& key, Value* pValue);
/*! /*!
@brief Add a copy of the Exifdatum to the Exif metadata. No @brief Add a copy of the Exifdatum to the Exif metadata. No
duplicate checks are performed, i.e., it is possible to add duplicate checks are performed, i.e., it is possible to add
@ -610,7 +700,7 @@ namespace Exiv2 {
If multiple metadata with the same key exist, it is undefined If multiple metadata with the same key exist, it is undefined
which of the matching metadata is found. which of the matching metadata is found.
*/ */
iterator findKey(const std::string& key); iterator findKey(const ExifKey& key);
/*! /*!
@brief Find the Exifdatum with the given ifd id and idx, return an @brief Find the Exifdatum with the given ifd id and idx, return an
iterator to it. iterator to it.
@ -659,7 +749,7 @@ namespace Exiv2 {
it. If multiple metadata with the same key exist, it is it. If multiple metadata with the same key exist, it is
undefined which of the matching metadata is found. undefined which of the matching metadata is found.
*/ */
const_iterator findKey(const std::string& key) const; const_iterator findKey(const ExifKey& key) const;
/*! /*!
@brief Find the Exifdatum with the given ifd id and idx, return an @brief Find the Exifdatum with the given ifd id and idx, return an
iterator to it. iterator to it.
@ -863,7 +953,7 @@ namespace Exiv2 {
ByteOrder byteOrder); ByteOrder byteOrder);
/*! /*!
@brief Return a key for the entry. The key is of the form @brief Return a key for the entry. The key is of the form
'ifdItem.sectionName.tagName'. This function knows about '<b>Exif</b>.ifdItem.tagName'. This function knows about
MakerNotes, i.e., it will invoke MakerNote::makeKey if necessary. MakerNotes, i.e., it will invoke MakerNote::makeKey if necessary.
*/ */
std::string makeKey(const Entry& entry); std::string makeKey(const Entry& entry);

@ -3,7 +3,7 @@
Abstract : Sample program showing how to set the Exif comment of an image Abstract : Sample program showing how to set the Exif comment of an image
File: exifcomment.cpp File: exifcomment.cpp
Version : $Name: $ $Revision: 1.3 $ Version : $Name: $ $Revision: 1.4 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History : 10-May-04, ahu: created History : 10-May-04, ahu: created
*/ */
@ -33,7 +33,7 @@ try {
/* /*
There are two pitfalls that we need to consider when setting the Exif user There are two pitfalls that we need to consider when setting the Exif user
comment (Image.UserInfo.UserComment) of an image: comment (Exif.Photo.UserComment) of an image:
First, the type of the Exif user comment tag is "undefined" (and not First, the type of the Exif user comment tag is "undefined" (and not
ASCII) according to the Exif standard. This means that in Exiv2, we have ASCII) according to the Exif standard. This means that in Exiv2, we have
@ -60,7 +60,7 @@ try {
8 + static_cast<long>(comment.size())); 8 + static_cast<long>(comment.size()));
// Set the Exif comment // Set the Exif comment
std::string key = "Image.UserInfo.UserComment"; Exiv2::ExifKey key("Exif.Photo.UserComment");
Exiv2::ExifData::iterator pos = exifData.findKey(key); Exiv2::ExifData::iterator pos = exifData.findKey(key);
if (pos != exifData.end()) { if (pos != exifData.end()) {
// Use the existing Exif UserComment metadatum if there is one // Use the existing Exif UserComment metadatum if there is one

@ -20,7 +20,7 @@
*/ */
/* /*
File: fujimn.cpp File: fujimn.cpp
Version: $Name: $ $Revision: 1.9 $ Version: $Name: $ $Revision: 1.10 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 18-Feb-04, ahu: created History: 18-Feb-04, ahu: created
07-Mar-04, ahu: isolated as a separate component 07-Mar-04, ahu: isolated as a separate component
@ -31,7 +31,7 @@
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: fujimn.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.10 $ $RCSfile: fujimn.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -78,7 +78,7 @@ namespace Exiv2 {
}; };
FujiMakerNote::FujiMakerNote(bool alloc) FujiMakerNote::FujiMakerNote(bool alloc)
: IfdMakerNote(fujiMnTagInfo, alloc), sectionName_("Fujifilm") : IfdMakerNote(fujiMnTagInfo, alloc), ifdItem_("Fujifilm")
{ {
byteOrder_ = littleEndian; byteOrder_ = littleEndian;
absOffset_ = false; absOffset_ = false;

@ -24,7 +24,7 @@
in Appendix 4: Makernote of Fujifilm of the document in Appendix 4: Makernote of Fujifilm of the document
<a href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html"> <a href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html">
Exif file format</a> by TsuruZoh Tachibanaya Exif file format</a> by TsuruZoh Tachibanaya
@version $Name: $ $Revision: 1.6 $ @version $Name: $ $Revision: 1.7 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Feb-04, ahu: created @date 11-Feb-04, ahu: created
@ -106,8 +106,8 @@ namespace Exiv2 {
//@{ //@{
int checkHeader() const; int checkHeader() const;
FujiMakerNote* clone(bool alloc =true) const; FujiMakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Fujifilm") //! Return the name of the makernote item ("Fujifilm")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -157,8 +157,8 @@ namespace Exiv2 {
*/ */
static const RegisterMakerNote register_; static const RegisterMakerNote register_;
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class FujiMakerNote }; // class FujiMakerNote

@ -20,13 +20,13 @@
*/ */
/* /*
File: iptc.cpp File: iptc.cpp
Version: $Name: $ $Revision: 1.2 $ Version: $Name: $ $Revision: 1.3 $
Author(s): Brad Schick (brad) <schick@robotbattle.com> Author(s): Brad Schick (brad) <schick@robotbattle.com>
History: 31-July-04, brad: created History: 31-July-04, brad: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.2 $ $RCSfile: iptc.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.3 $ $RCSfile: iptc.cpp,v $");
// Define DEBUG_MAKERNOTE to output debug information to std::cerr // Define DEBUG_MAKERNOTE to output debug information to std::cerr
#undef DEBUG_MAKERNOTE #undef DEBUG_MAKERNOTE
@ -48,27 +48,63 @@ EXIV2_RCSID("@(#) $Name: $ $Revision: 1.2 $ $RCSfile: iptc.cpp,v $");
// class member definitions // class member definitions
namespace Exiv2 { namespace Exiv2 {
Iptcdatum::Iptcdatum(const std::string& key, IptcKey::IptcKey(const std::string& key)
const Value* value) : key_(key)
: pValue_(0), key_(key), modified_(false)
{ {
if (value) pValue_ = value->clone(); decomposeKey();
std::pair<uint16, uint16> p = decomposeKey(key); }
IptcKey::IptcKey(uint16 tag, uint16 record)
: tag_(tag), record_(record), key_(IptcDataSets::makeKey(tag, record))
{
}
IptcKey::IptcKey(const IptcKey& rhs)
: tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_)
{
}
IptcKey& IptcKey::operator=(const IptcKey& rhs)
{
if (this == &rhs) return *this;
Key::operator=(rhs);
tag_ = rhs.tag_;
record_ = rhs.record_;
key_ = rhs.key_;
return *this;
}
IptcKey* IptcKey::clone() const
{
return new IptcKey(*this);
}
void IptcKey::decomposeKey()
{
std::pair<uint16, uint16> p = IptcDataSets::decomposeKey(key_);
if (p.first == 0xffff) throw Error("Invalid key"); if (p.first == 0xffff) throw Error("Invalid key");
tag_ = p.first;
if (p.second == IptcDataSets::invalidRecord) throw Error("Invalid key"); if (p.second == IptcDataSets::invalidRecord) throw Error("Invalid key");
tag_ = p.first;
record_ = p.second; record_ = p.second;
} }
Iptcdatum::Iptcdatum(const IptcKey& key,
const Value* value)
: pKey_(key.clone()), pValue_(0), modified_(false)
{
if (value) pValue_ = value->clone();
}
Iptcdatum::Iptcdatum(const Iptcdatum& rhs) Iptcdatum::Iptcdatum(const Iptcdatum& rhs)
: Metadatum(rhs), tag_(rhs.tag_), record_(rhs.record_), : Metadatum(rhs), pKey_(0), pValue_(0), modified_(false)
pValue_(0), key_(rhs.key_), modified_(false)
{ {
if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy
if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy
} }
Iptcdatum::~Iptcdatum() Iptcdatum::~Iptcdatum()
{ {
delete pKey_;
delete pValue_; delete pValue_;
} }
@ -77,12 +113,15 @@ namespace Exiv2 {
if (this == &rhs) return *this; if (this == &rhs) return *this;
Metadatum::operator=(rhs); Metadatum::operator=(rhs);
modified_ = true; modified_ = true;
tag_ = rhs.tag_;
record_ = rhs.record_; delete pKey_;
pKey_ = 0;
if (rhs.pKey_ != 0) pKey_ = rhs.pKey_->clone(); // deep copy
delete pValue_; delete pValue_;
pValue_ = 0; pValue_ = 0;
if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy if (rhs.pValue_ != 0) pValue_ = rhs.pValue_->clone(); // deep copy
key_ = rhs.key_;
return *this; return *this;
} // Iptcdatum::operator= } // Iptcdatum::operator=
@ -100,16 +139,6 @@ namespace Exiv2 {
pValue_->read(buf); pValue_->read(buf);
} }
std::string Iptcdatum::tagName() const
{
return IptcDataSets::dataSetName(tag_, record_);
}
std::string Iptcdatum::recordName() const
{
return IptcDataSets::recordName(record_);
}
const byte IptcData::marker_ = 0x1C; // Dataset marker const byte IptcData::marker_ = 0x1C; // Dataset marker
IptcData::IptcData() IptcData::IptcData()
@ -206,7 +235,7 @@ namespace Exiv2 {
val = Value::create(undefined); val = Value::create(undefined);
val->read(data, sizeData, bigEndian); val->read(data, sizeData, bigEndian);
} }
std::string key = makeKey(dataSet, record); IptcKey key(dataSet, record);
add(key, val); add(key, val);
delete val; delete val;
return 0; return 0;
@ -346,7 +375,7 @@ namespace Exiv2 {
return exvImage.writeMetadata(); return exvImage.writeMetadata();
} // IptcData::writeIptcData } // IptcData::writeIptcData
int IptcData::add(const std::string& key, Value* value) int IptcData::add(const IptcKey& key, Value* value)
{ {
return add(Iptcdatum(key, value)); return add(Iptcdatum(key, value));
} }
@ -364,16 +393,16 @@ namespace Exiv2 {
return 0; return 0;
} }
IptcData::const_iterator IptcData::findKey(const std::string& key) const IptcData::const_iterator IptcData::findKey(const IptcKey& key) const
{ {
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumByKey(key)); FindMetadatumByKey(key.key()));
} }
IptcData::iterator IptcData::findKey(const std::string& key) IptcData::iterator IptcData::findKey(const IptcKey& key)
{ {
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(), return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumByKey(key)); FindMetadatumByKey(key.key()));
} }
IptcData::const_iterator IptcData::findId(uint16 dataset, uint16 record) const IptcData::const_iterator IptcData::findId(uint16 dataset, uint16 record) const
@ -453,14 +482,4 @@ namespace Exiv2 {
return os << md.value(); return os << md.value();
} }
std::string makeKey(uint16 number, uint16 record)
{
return IptcDataSets::makeKey(number, record);
}
std::pair<uint16, uint16> decomposeKey(const std::string& key)
{
return IptcDataSets::decomposeKey(key);
}
} // namespace Exiv2 } // namespace Exiv2

@ -21,7 +21,7 @@
/*! /*!
@file iptc.hpp @file iptc.hpp
@brief Encoding and decoding of Iptc data @brief Encoding and decoding of Iptc data
@version $Name: $ $Revision: 1.3 $ @version $Name: $ $Revision: 1.4 $
@author Brad Schick (brad) @author Brad Schick (brad)
<a href="mailto:schick@robotbattle.com">schick@robotbattle.com</a> <a href="mailto:schick@robotbattle.com">schick@robotbattle.com</a>
@date 31-Jul-04, brad: created @date 31-Jul-04, brad: created
@ -48,6 +48,82 @@ namespace Exiv2 {
// ***************************************************************************** // *****************************************************************************
// class definitions // class definitions
//! Concrete keys for Iptc metadata.
class IptcKey : public Key {
public:
//! @name Creators
//@{
/*!
@brief Constructor to create an Iptc key from a key string.
@param key The key string.
@throw Error ("Invalid key") if the first part of the key is not
'Iptc' or the remaining parts of the key cannot be parsed and
converted to a record name and a dataset name.
*/
explicit IptcKey(const std::string& key);
/*!
@brief Constructor to create an Iptc key from dataset and record ids.
@param tag Dataset id
@param record Record id
*/
IptcKey(uint16 tag, uint16 record);
//! Copy constructor
IptcKey(const IptcKey& rhs);
//@}
//! @name Manipulators
//@{
/*!
@brief Assignment operator.
*/
IptcKey& operator=(const IptcKey& rhs);
//@}
//! @name Accessors
//@{
virtual std::string key() const { return key_; }
virtual const char* familyName() const
{ return IptcDataSets::familyName(); }
/*!
@brief Return the name of the group (the second part of the key).
For Iptc keys, the group name is the record name.
*/
virtual std::string groupName() const { return recordName(); }
virtual std::string tagName() const
{ return IptcDataSets::dataSetName(tag_, record_); }
virtual uint16 tag() const { return tag_; }
virtual IptcKey* clone() const;
//! Return the name of the record
const char* recordName() const
{ return IptcDataSets::recordName(record_); }
//! Return the record id
uint16 record() const { return record_; }
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Parse and convert the key string into dataset and record id.
Updates tag_ and record_ if the string can be decomposed,
or throws Error ("Invalid key").
@throw Error ("Invalid key") if the key cannot be parsed into
family name, group name and tag name parts.
*/
void decomposeKey();
//@}
private:
// DATA
uint16 tag_; //!< Tag value
uint16 record_; //!< Record value
std::string key_; //!< Key
}; // class IptcKey
/*! /*!
@brief Information related to one Iptc dataset. @brief Information related to one Iptc dataset.
*/ */
@ -57,17 +133,17 @@ namespace Exiv2 {
//@{ //@{
/*! /*!
@brief Constructor for new tags created by an application. The @brief Constructor for new tags created by an application. The
Iptcdatum is created from a key / value pair. %Iptcdatum copies %Iptcdatum is created from a key / value pair. %Iptcdatum
(clones) the value if one is provided. Alternatively, a program copies (clones) the value if one is provided. Alternatively, a
can create an 'empty' Iptcdatum with only a key and set the program can create an 'empty' %Iptcdatum with only a key and
value using setValue(). set the value using setValue().
@param key The key of the Iptcdatum. @param key The key of the %Iptcdatum.
@param value Pointer to a Iptcdatum value. @param value Pointer to a %Iptcdatum value.
@throw Error ("Invalid key") if the key cannot be parsed and converted @throw Error ("Invalid key") if the key cannot be parsed and converted
to a tag number and record id. to a tag number and record id.
*/ */
explicit Iptcdatum(const std::string& key, explicit Iptcdatum(const IptcKey& key,
const Value* value =0); const Value* value =0);
//! Copy constructor //! Copy constructor
Iptcdatum(const Iptcdatum& rhs); Iptcdatum(const Iptcdatum& rhs);
@ -109,30 +185,34 @@ namespace Exiv2 {
{ return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); } { return pValue_ == 0 ? 0 : pValue_->copy(buf, byteOrder); }
/*! /*!
@brief Return the key of the Iptcdatum. The key is of the form @brief Return the key of the Iptcdatum. The key is of the form
'Iptc.recordName.datasetName'. Note however that the key '<b>Iptc</b>.recordName.datasetName'. Note however that the key
is not necessarily unique, i.e., an IptcData may contain is not necessarily unique, i.e., an IptcData may contain
multiple metadata with the same key. multiple metadata with the same key.
*/ */
std::string key() const { return key_; } std::string key() const { return pKey_ == 0 ? "" : pKey_->key(); }
/*! /*!
@brief Return the name of the record @brief Return the name of the record
@return record name @return record name
@throw Error("Unknown record"); @throw Error("Unknown record");
*/ */
std::string recordName() const; const char* recordName() const
{ return pKey_ == 0 ? "" : pKey_->recordName(); }
/*! /*!
@brief Return the record id @brief Return the record id
@return record id @return record id
*/ */
uint16 record() const { return record_; } uint16 record() const
{ return pKey_ == 0 ? 0 : pKey_->record(); }
/*! /*!
@brief Return the name of the tag (aka dataset) @brief Return the name of the tag (aka dataset)
@return tag name @return tag name
@throw Error("No dataSet for record Id") if tag is unknown @throw Error("No dataSet for record Id") if tag is unknown
*/ */
std::string tagName() const; std::string tagName() const
{ return pKey_ == 0 ? "" : pKey_->tagName(); }
//! Return the tag (aka dataset) number //! Return the tag (aka dataset) number
uint16 tag() const { return tag_; } uint16 tag() const
{ return pKey_ == 0 ? 0 : pKey_->tag(); }
//! Return the type id of the value //! Return the type id of the value
TypeId typeId() const TypeId typeId() const
{ return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); } { return pValue_ == 0 ? invalidTypeId : pValue_->typeId(); }
@ -217,10 +297,8 @@ namespace Exiv2 {
private: private:
// DATA // DATA
uint16 tag_; //!< Tag value IptcKey* pKey_; //!< Key
uint16 record_; //!< Record value
Value* pValue_; //!< Pointer to the value Value* pValue_; //!< Pointer to the value
std::string key_; //!< Key
bool modified_; //!< Change indicator bool modified_; //!< Change indicator
}; // class Iptcdatum }; // class Iptcdatum
@ -341,13 +419,13 @@ namespace Exiv2 {
*/ */
long copy(byte* buf); long copy(byte* buf);
/*! /*!
@brief Add a Iptcdatum from the supplied key and value pair. This @brief Add an %Iptcdatum from the supplied key and value pair. This
method copies (clones) the value. A check for non-repeatable method copies (clones) the value. A check for non-repeatable
datasets is performed. datasets is performed.
@return 0 if successful;<BR> @return 0 if successful;<BR>
6 if the dataset already exists and is not repeatable;<BR> 6 if the dataset already exists and is not repeatable
*/ */
int add(const std::string& key, Value* value); int add(const IptcKey& key, Value* value);
/*! /*!
@brief Add a copy of the Iptcdatum to the Iptc metadata. A check @brief Add a copy of the Iptcdatum to the Iptc metadata. A check
for non-repeatable datasets is performed. for non-repeatable datasets is performed.
@ -375,7 +453,7 @@ namespace Exiv2 {
If multiple entries with the same key exist, it is undefined If multiple entries with the same key exist, it is undefined
which of the matching metadata is found. which of the matching metadata is found.
*/ */
iterator findKey(const std::string& key); iterator findKey(const IptcKey& key);
/*! /*!
@brief Find a Iptcdatum with the given record and dataset it, @brief Find a Iptcdatum with the given record and dataset it,
return a const iterator to it. If multiple entries with the return a const iterator to it. If multiple entries with the
@ -404,11 +482,11 @@ namespace Exiv2 {
//! End of the metadata //! End of the metadata
const_iterator end() const { return iptcMetadata_.end(); } const_iterator end() const { return iptcMetadata_.end(); }
/*! /*!
@brief Find a Iptcdatum with the given key, return a const iterator to @brief Find an Iptcdatum with the given key, return a const iterator
it. If multiple metadata with the same key exist it is to it. If multiple metadata with the same key exist it is
undefined which of the matching metadata is found. undefined which of the matching metadata is found.
*/ */
const_iterator findKey(const std::string& key) const; const_iterator findKey(const IptcKey& key) const;
/*! /*!
@brief Find a Iptcdatum with the given record and dataset number, @brief Find a Iptcdatum with the given record and dataset number,
return a const iterator to it. If multiple metadata with the return a const iterator to it. If multiple metadata with the
@ -473,24 +551,6 @@ namespace Exiv2 {
mutable bool modified_; mutable bool modified_;
}; // class IptcData }; // class IptcData
// *****************************************************************************
// free functions
/*!
@brief Return a key for the entry. The key is of the form
'Iptc.recordName.datasetName'.
@throw Error ("No dataSet for record Id") if the dataset number or
record Id is unknown
*/
std::string makeKey(uint16 number, uint16 record);
/*!
@brief Return the record and dataset id pair for the key.
@return A pair consisting of the record and dataset id.
@throw Error ("Invalid key") if the key cannot be parsed into
valid record and dataset parts.
*/
std::pair<uint16, uint16> decomposeKey(const std::string& key);
} // namespace Exiv2 } // namespace Exiv2
#endif // #ifndef IPTC_HPP_ #endif // #ifndef IPTC_HPP_

@ -4,7 +4,7 @@
This is not designed to be a robust application. This is not designed to be a robust application.
File : iptctest.cpp File : iptctest.cpp
Version : $Name: $ $Revision: 1.1 $ Version : $Name: $ $Revision: 1.2 $
Author(s): Brad Schick (brad) <schick@robotbattle.com> Author(s): Brad Schick (brad) <schick@robotbattle.com>
History : 01-Aug-04, brad: created History : 01-Aug-04, brad: created
*/ */
@ -118,7 +118,7 @@ void processAdd(const std::string& line, int num)
Value *val = Value::create(type); Value *val = Value::create(type);
val->read(data); val->read(data);
int rc = g_iptcData.add(key, val); int rc = g_iptcData.add(IptcKey(key), val);
if (rc) { if (rc) {
std::string error = IptcData::strError(rc, "Input file"); std::string error = IptcData::strError(rc, "Input file");
throw Error(error); throw Error(error);
@ -180,7 +180,7 @@ void processModify(const std::string& line, int num)
iter->setValue(val); iter->setValue(val);
} }
else { else {
int rc = g_iptcData.add(key, val); int rc = g_iptcData.add(IptcKey(key), val);
if (rc) { if (rc) {
std::string error = IptcData::strError(rc, "Input file"); std::string error = IptcData::strError(rc, "Input file");
throw Error(error); throw Error(error);

@ -20,13 +20,13 @@
*/ */
/* /*
File: makernote.cpp File: makernote.cpp
Version: $Name: $ $Revision: 1.24 $ Version: $Name: $ $Revision: 1.25 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 18-Feb-04, ahu: created History: 18-Feb-04, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.24 $ $RCSfile: makernote.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.25 $ $RCSfile: makernote.cpp,v $");
// Define DEBUG_* to output debug information to std::cerr // Define DEBUG_* to output debug information to std::cerr
#undef DEBUG_MAKERNOTE #undef DEBUG_MAKERNOTE
@ -59,28 +59,29 @@ namespace Exiv2 {
std::string MakerNote::makeKey(uint16 tag) const std::string MakerNote::makeKey(uint16 tag) const
{ {
return std::string(ExifTags::ifdItem(makerIfd)) return std::string(ExifTags::familyName())
+ "." + sectionName(tag) + "." + tagName(tag); + "." + std::string(ifdItem())
+ "." + tagName(tag);
} // MakerNote::makeKey } // MakerNote::makeKey
uint16 MakerNote::decomposeKey(const std::string& key) const uint16 MakerNote::decomposeKey(const std::string& key) const
{ {
// Get the IFD, section name and tag name parts of the key // Get the family, item and tag name parts of the key
std::string::size_type pos1 = key.find('.'); std::string::size_type pos1 = key.find('.');
if (pos1 == std::string::npos) throw Error("Invalid key"); if (pos1 == std::string::npos) throw Error("Invalid key");
std::string ifdItem = key.substr(0, pos1); std::string familyName = key.substr(0, pos1);
std::string::size_type pos0 = pos1 + 1; std::string::size_type pos0 = pos1 + 1;
pos1 = key.find('.', pos0); pos1 = key.find('.', pos0);
if (pos1 == std::string::npos) throw Error("Invalid key"); if (pos1 == std::string::npos) throw Error("Invalid key");
std::string sectionName = key.substr(pos0, pos1 - pos0); std::string ifdItem = key.substr(pos0, pos1 - pos0);
pos0 = pos1 + 1; pos0 = pos1 + 1;
std::string tagName = key.substr(pos0); std::string tagName = key.substr(pos0);
if (tagName == "") throw Error("Invalid key"); if (tagName == "") throw Error("Invalid key");
if (ifdItem != ExifTags::ifdItem(makerIfd)) return 0xffff; if (familyName != ExifTags::familyName()) return 0xffff;
uint16 tag = this->tag(tagName); uint16 tag = this->tag(tagName);
if (tag == 0xffff) return tag; if (tag == 0xffff) return tag;
if (sectionName != this->sectionName(tag)) return 0xffff; if (ifdItem != this->ifdItem()) return 0xffff;
return tag; return tag;
} // MakerNote::decomposeKey } // MakerNote::decomposeKey

@ -22,7 +22,7 @@
@file makernote.hpp @file makernote.hpp
@brief Contains the Exif %MakerNote interface, IFD %MakerNote and a @brief Contains the Exif %MakerNote interface, IFD %MakerNote and a
MakerNote factory MakerNote factory
@version $Name: $ $Revision: 1.21 $ @version $Name: $ $Revision: 1.22 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 18-Feb-04, ahu: created @date 18-Feb-04, ahu: created
@ -222,8 +222,8 @@ namespace Exiv2 {
virtual Entries::const_iterator findIdx(int idx) const =0; virtual Entries::const_iterator findIdx(int idx) const =0;
//! Return the size of the makernote in bytes //! Return the size of the makernote in bytes
virtual long size() const =0; virtual long size() const =0;
//! Return the name of the makernote section //! Return the name of the makernote item
virtual std::string sectionName(uint16 tag) const =0; virtual std::string ifdItem() const =0;
//! Interpret and print the value of a makernote tag //! Interpret and print the value of a makernote tag
virtual std::ostream& printTag(std::ostream& os, virtual std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
@ -327,7 +327,7 @@ namespace Exiv2 {
*/ */
virtual long headerSize() const; virtual long headerSize() const;
virtual IfdMakerNote* clone(bool alloc =true) const =0; virtual IfdMakerNote* clone(bool alloc =true) const =0;
virtual std::string sectionName(uint16 tag) const =0; virtual std::string ifdItem() const =0;
virtual std::ostream& printTag(std::ostream& os, virtual std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const =0; const Value& value) const =0;

@ -20,14 +20,15 @@
*/ */
/*! /*!
@file metadatum.hpp @file metadatum.hpp
@brief Provides class Metadatum @brief Provides abstract base classes Metadatum and Key
@version $Name: $ $Revision: 1.1 $ @version $Name: $ $Revision: 1.2 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@author Brad Schick (brad) @author Brad Schick (brad)
<a href="mailto:schick@robotbattle.com">schick@robotbattle.com</a> <a href="mailto:schick@robotbattle.com">schick@robotbattle.com</a>
@date 09-Jan-04, ahu: created<BR> @date 09-Jan-04, ahu: created<BR>
31-Jul-04, brad: isolated as a component 31-Jul-04, brad: isolated as a component<BR>
23-Aug-04, ahu: added Key
*/ */
#ifndef METADATUM_HPP_ #ifndef METADATUM_HPP_
#define METADATUM_HPP_ #define METADATUM_HPP_
@ -48,10 +49,82 @@ namespace Exiv2 {
// class definitions // class definitions
/*! /*!
@brief Information related to one Exif tag. @brief Abstract base class defining the %Key of a metadatum.
Keys are used to identify and group metadata.
*/
class Key {
public:
//! @name Creators
//@{
//! Destructor
virtual ~Key() {}
//@}
//! @name Accessors
//@{
/*!
@brief Return the key of the metadatum as a string. The key is of the
form 'familyName.groupName.tagName'. Note however that the
key is not necessarily unique, e.g., an ExifData may contain
multiple metadata with the same key.
*/
virtual std::string key() const =0;
//! Return an identifier for the type of metadata (the first part of the key)
virtual const char* familyName() const =0;
//! Return the name of the group (the second part of the key)
virtual std::string groupName() const =0;
//! Return the name of the tag (which is also the third part of the key)
virtual std::string tagName() const =0;
//! Return the tag number
virtual uint16 tag() const =0;
/*!
@brief Return a pointer to a copy of itself (deep copy).
The caller owns this copy and is responsible to delete it!
*/
virtual Key* clone() const =0;
/*!
@brief Write the key to an output stream. You do not usually have
to use this function; it is used for the implementation of
the output operator for %Key,
operator<<(std::ostream &os, const Key &key).
*/
std::ostream& write(std::ostream& os) const { return os << key(); }
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Key& operator=(const Key& rhs) { return *this; }
//@}
}; // class Key
//! Output operator for Key types
inline std::ostream& operator<<(std::ostream& os, const Key& key)
{
return key.write(os);
}
/*!
@brief Abstract base class defining the interface to access information
related to one metadata tag.
*/ */
class Metadatum { class Metadatum {
public: public:
//! @name Creators
//@{
//! Default Constructor
Metadatum() {}
//! Copy constructor
Metadatum(const Metadatum& rhs) {}
//! Destructor
virtual ~Metadatum() {}
//@}
//! @name Manipulators //! @name Manipulators
//@{ //@{
/*! /*!
@ -83,7 +156,7 @@ namespace Exiv2 {
virtual long copy(byte* buf, ByteOrder byteOrder) const =0; virtual long copy(byte* buf, ByteOrder byteOrder) const =0;
/*! /*!
@brief Return the key of the metadatum. The key is of the form @brief Return the key of the metadatum. The key is of the form
'ifdItem.sectionName.tagName'. Note however that the key 'familyName.ifdItem.tagName'. Note however that the key
is not necessarily unique, i.e., an ExifData may contain is not necessarily unique, i.e., an ExifData may contain
multiple metadata with the same key. multiple metadata with the same key.
*/ */
@ -161,19 +234,12 @@ namespace Exiv2 {
//@} //@}
protected: protected:
//! @name Creators
//@{
//! Default Constructor
Metadatum() {}
//! Copy constructor
Metadatum(const Metadatum& rhs) {}
//! Destructor
virtual ~Metadatum() {}
//@}
//! @name Manipulators //! @name Manipulators
//@{ //@{
//! Assignment operator /*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Metadatum& operator=(const Metadatum& rhs) { return *this; } Metadatum& operator=(const Metadatum& rhs) { return *this; }
//@} //@}

@ -20,14 +20,14 @@
*/ */
/* /*
File: nikon1mn.cpp File: nikon1mn.cpp
Version: $Name: $ $Revision: 1.4 $ Version: $Name: $ $Revision: 1.5 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 17-May-04, ahu: created History: 17-May-04, ahu: created
25-May-04, ahu: combined all Nikon formats in one component 25-May-04, ahu: combined all Nikon formats in one component
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.4 $ $RCSfile: nikonmn.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.5 $ $RCSfile: nikonmn.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -73,7 +73,7 @@ namespace Exiv2 {
}; };
Nikon1MakerNote::Nikon1MakerNote(bool alloc) Nikon1MakerNote::Nikon1MakerNote(bool alloc)
: IfdMakerNote(nikon1MnTagInfo, alloc), sectionName_("Nikon1") : IfdMakerNote(nikon1MnTagInfo, alloc), ifdItem_("Nikon1")
{ {
} }
@ -198,7 +198,7 @@ namespace Exiv2 {
}; };
Nikon2MakerNote::Nikon2MakerNote(bool alloc) Nikon2MakerNote::Nikon2MakerNote(bool alloc)
: IfdMakerNote(nikon2MnTagInfo, alloc), sectionName_("Nikon2") : IfdMakerNote(nikon2MnTagInfo, alloc), ifdItem_("Nikon2")
{ {
} }
@ -383,7 +383,7 @@ namespace Exiv2 {
}; };
Nikon3MakerNote::Nikon3MakerNote(bool alloc) Nikon3MakerNote::Nikon3MakerNote(bool alloc)
: IfdMakerNote(nikon3MnTagInfo, alloc), sectionName_("Nikon3") : IfdMakerNote(nikon3MnTagInfo, alloc), ifdItem_("Nikon3")
{ {
absOffset_ = false; absOffset_ = false;
} }

@ -28,7 +28,7 @@
<a href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html"> <a href="http://park2.wakwak.com/%7Etsuruzoh/Computer/Digicams/exif-e.html">
Exif file format</a> by TsuruZoh Tachibanaya.<BR> Exif file format</a> by TsuruZoh Tachibanaya.<BR>
Format 3: "EXIFutils Field Reference Guide". Format 3: "EXIFutils Field Reference Guide".
@version $Name: $ $Revision: 1.3 $ @version $Name: $ $Revision: 1.4 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 17-May-04, ahu: created<BR> @date 17-May-04, ahu: created<BR>
@ -103,8 +103,8 @@ namespace Exiv2 {
//! @name Accessors //! @name Accessors
//@{ //@{
Nikon1MakerNote* clone(bool alloc =true) const; Nikon1MakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Nikon1") //! Return the name of the makernote item ("Nikon1")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -149,8 +149,8 @@ namespace Exiv2 {
*/ */
static const RegisterMakerNote register_; static const RegisterMakerNote register_;
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class Nikon1MakerNote }; // class Nikon1MakerNote
@ -182,8 +182,8 @@ namespace Exiv2 {
//@{ //@{
int checkHeader() const; int checkHeader() const;
Nikon2MakerNote* clone(bool alloc =true) const; Nikon2MakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Nikon2") //! Return the name of the makernote item ("Nikon2")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -206,8 +206,8 @@ namespace Exiv2 {
//@} //@}
private: private:
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class Nikon2MakerNote }; // class Nikon2MakerNote
@ -236,8 +236,8 @@ namespace Exiv2 {
//@{ //@{
int checkHeader() const; int checkHeader() const;
Nikon3MakerNote* clone(bool alloc =true) const; Nikon3MakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Nikon3") //! Return the name of the makernote item ("Nikon3")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -258,8 +258,8 @@ namespace Exiv2 {
//@} //@}
private: private:
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class Nikon3MakerNote }; // class Nikon3MakerNote

@ -20,7 +20,7 @@
*/ */
/* /*
File: sigmamn.cpp File: sigmamn.cpp
Version: $Name: $ $Revision: 1.8 $ Version: $Name: $ $Revision: 1.9 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 02-Apr-04, ahu: created History: 02-Apr-04, ahu: created
Credits: Sigma and Foveon MakerNote implemented according to the specification Credits: Sigma and Foveon MakerNote implemented according to the specification
@ -29,7 +29,7 @@
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.8 $ $RCSfile: sigmamn.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: sigmamn.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -83,7 +83,7 @@ namespace Exiv2 {
}; };
SigmaMakerNote::SigmaMakerNote(bool alloc) SigmaMakerNote::SigmaMakerNote(bool alloc)
: IfdMakerNote(sigmaMnTagInfo, alloc), sectionName_("Sigma") : IfdMakerNote(sigmaMnTagInfo, alloc), ifdItem_("Sigma")
{ {
} }

@ -23,7 +23,7 @@
@brief Sigma and Foveon MakerNote implemented according to the specification @brief Sigma and Foveon MakerNote implemented according to the specification
<a href="http://www.x3f.info/technotes/FileDocs/MakerNoteDoc.html"> <a href="http://www.x3f.info/technotes/FileDocs/MakerNoteDoc.html">
SIGMA and FOVEON EXIF MakerNote Documentation</a> by Foveon. SIGMA and FOVEON EXIF MakerNote Documentation</a> by Foveon.
@version $Name: $ $Revision: 1.6 $ @version $Name: $ $Revision: 1.7 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 02-Apr-04, ahu: created @date 02-Apr-04, ahu: created
@ -105,8 +105,8 @@ namespace Exiv2 {
//@{ //@{
int checkHeader() const; int checkHeader() const;
SigmaMakerNote* clone(bool alloc =true) const; SigmaMakerNote* clone(bool alloc =true) const;
//! Return the name of the makernote section ("Sigma") //! Return the name of the makernote item ("Sigma")
std::string sectionName(uint16 tag) const { return sectionName_; } std::string ifdItem() const { return ifdItem_; }
std::ostream& printTag(std::ostream& os, std::ostream& printTag(std::ostream& os,
uint16 tag, uint16 tag,
const Value& value) const; const Value& value) const;
@ -148,8 +148,8 @@ namespace Exiv2 {
*/ */
static const RegisterMakerNote register_; static const RegisterMakerNote register_;
//! The section name (second part of the key) used for makernote tags //! The item name (second part of the key) used for makernote tags
std::string sectionName_; std::string ifdItem_;
}; // class SigmaMakerNote }; // class SigmaMakerNote

@ -3,13 +3,13 @@
Abstract: Print a simple comma separated list of tags defined in Exiv2 Abstract: Print a simple comma separated list of tags defined in Exiv2
File: taglist.cpp File: taglist.cpp
Version: $Name: $ $Revision: 1.8 $ Version: $Name: $ $Revision: 1.9 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 07-Jan-04, ahu: created History: 07-Jan-04, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.8 $ $RCSfile: taglist.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.9 $ $RCSfile: taglist.cpp,v $");
#include "makernote.hpp" #include "makernote.hpp"
#include "nikonmn.hpp" #include "nikonmn.hpp"
@ -33,28 +33,28 @@ try {
case 2: case 2:
{ {
MakerNote* pMakerNote = 0; MakerNote* pMakerNote = 0;
std::string section(argv[1]); std::string item(argv[1]);
if (section == "Iptc") { if (item == "Iptc") {
IptcDataSets::dataSetList(std::cout); IptcDataSets::dataSetList(std::cout);
break; break;
} }
if (section == "Canon") { if (item == "Canon") {
pMakerNote = new CanonMakerNote; pMakerNote = new CanonMakerNote;
} }
else if (section == "Fuji") { else if (item == "Fujifilm") {
pMakerNote = new FujiMakerNote; pMakerNote = new FujiMakerNote;
} }
else if (section == "Sigma") { else if (item == "Sigma") {
pMakerNote = new SigmaMakerNote; pMakerNote = new SigmaMakerNote;
} }
else if (section == "Nikon1") { else if (item == "Nikon1") {
pMakerNote = new Nikon1MakerNote; pMakerNote = new Nikon1MakerNote;
} }
else if (section == "Nikon2") { else if (item == "Nikon2") {
pMakerNote = new Nikon2MakerNote; pMakerNote = new Nikon2MakerNote;
} }
else if (section == "Nikon3") { else if (item == "Nikon3") {
pMakerNote = new Nikon3MakerNote; pMakerNote = new Nikon3MakerNote;
} }
@ -76,7 +76,8 @@ try {
break; break;
} }
if (rc) { if (rc) {
std::cout << "Usage: " << argv[0] << " [SectionName|Iptc]\n" std::cout << "Usage: " << argv[0]
<< " [Canon|Fujifilm|Nikon1|Nikon2|Nikon3|Sigma|Iptc]\n"
<< "Print Exif tags, MakerNote tags, or Iptc datasets\n"; << "Print Exif tags, MakerNote tags, or Iptc datasets\n";
} }
return rc; return rc;

@ -1,12 +1,12 @@
################################################################################ ################################################################################
# File : tags.awk # File : tags.awk
# Version : $Name: $ $Revision: 1.3 $ # Version : $Name: $ $Revision: 1.4 $
# Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> # Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
# History : 07-Feb-04, ahu: created # History : 07-Feb-04, ahu: created
# #
# Description: # Description:
# Awk script to convert a taglist to XML format used in the documentation. # Awk script to convert a taglist to XML format used in the documentation.
# $ taglist [SectionName] | awk -f tags.awk > tags.xml # $ taglist [itemName] | awk -f tags.awk > tags.xml
################################################################################ ################################################################################
BEGIN { BEGIN {

@ -20,13 +20,13 @@
*/ */
/* /*
File: tags.cpp File: tags.cpp
Version: $Name: $ $Revision: 1.32 $ Version: $Name: $ $Revision: 1.33 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 15-Jan-04, ahu: created History: 15-Jan-04, ahu: created
*/ */
// ***************************************************************************** // *****************************************************************************
#include "rcsid.hpp" #include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.32 $ $RCSfile: tags.cpp,v $"); EXIV2_RCSID("@(#) $Name: $ $Revision: 1.33 $ $RCSfile: tags.cpp,v $");
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -50,15 +50,16 @@ namespace Exiv2 {
{ {
} }
// Important: IFD item must be unique!
const IfdInfo ExifTags::ifdInfo_[] = { const IfdInfo ExifTags::ifdInfo_[] = {
IfdInfo(ifdIdNotSet, "(Unknown IFD)", "(Unknown data area)"), IfdInfo(ifdIdNotSet, "(Unknown IFD)", "(Unknown item)"),
IfdInfo(ifd0, "IFD0", "Image"), IfdInfo(ifd0, "IFD0", "Image"),
IfdInfo(exifIfd, "Exif", "Image"), IfdInfo(exifIfd, "Exif", "Photo"), // just to avoid 'Exif.Exif.*' keys
IfdInfo(gpsIfd, "GPSInfo", "Image"), IfdInfo(gpsIfd, "GPSInfo", "GPSInfo"),
IfdInfo(makerIfd, "Makernote", "Makernote"), IfdInfo(makerIfd, "Makernote", "Makernote"),
IfdInfo(iopIfd, "Iop", "Image"), IfdInfo(iopIfd, "Iop", "Iop"),
IfdInfo(ifd1, "IFD1", "Thumbnail"), IfdInfo(ifd1, "IFD1", "Thumbnail"),
IfdInfo(lastIfdId, "(Last IFD info)", "(Last IFD info)") IfdInfo(lastIfdId, "(Last IFD info)", "(Last IFD item)")
}; };
SectionInfo::SectionInfo( SectionInfo::SectionInfo(
@ -265,6 +266,8 @@ namespace Exiv2 {
0 0
}; };
const char* ExifTags::familyName_ = "Exif";
int ExifTags::tagInfoIdx(uint16 tag, IfdId ifdId) int ExifTags::tagInfoIdx(uint16 tag, IfdId ifdId)
{ {
const TagInfo* tagInfo = tagInfos_[ifdId]; const TagInfo* tagInfo = tagInfos_[ifdId];
@ -276,17 +279,6 @@ namespace Exiv2 {
return idx; return idx;
} }
int ExifTags::tagInfoIdx(const std::string& tagName, IfdId ifdId)
{
const TagInfo* tagInfo = tagInfos_[ifdId];
if (tagInfo == 0) return -1;
int idx;
for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) {
if (tagInfo[idx].name_ == tagName) break;
}
return idx;
}
const char* ExifTags::tagName(uint16 tag, IfdId ifdId) const char* ExifTags::tagName(uint16 tag, IfdId ifdId)
{ {
int idx = tagInfoIdx(tag, ifdId); int idx = tagInfoIdx(tag, ifdId);
@ -317,6 +309,17 @@ namespace Exiv2 {
return sectionInfo_[tagInfo[idx].sectionId_].desc_; return sectionInfo_[tagInfo[idx].sectionId_].desc_;
} }
uint16 ExifTags::tag(const std::string& tagName, IfdId ifdId)
{
const TagInfo* tagInfo = tagInfos_[ifdId];
if (tagInfo == 0) return 0xffff;
int idx;
for (idx = 0; tagInfo[idx].tag_ != 0xffff; ++idx) {
if (tagInfo[idx].name_ == tagName) break;
}
return tagInfo[idx].tag_;
}
const char* ExifTags::ifdName(IfdId ifdId) const char* ExifTags::ifdName(IfdId ifdId)
{ {
return ifdInfo_[ifdId].name_; return ifdInfo_[ifdId].name_;
@ -343,8 +346,8 @@ namespace Exiv2 {
std::string ExifTags::makeKey(uint16 tag, IfdId ifdId) std::string ExifTags::makeKey(uint16 tag, IfdId ifdId)
{ {
return std::string(ifdItem(ifdId)) return std::string(familyName())
+ "." + std::string(sectionName(tag, ifdId)) + "." + std::string(ifdItem(ifdId))
+ "." + std::string(tagName(tag, ifdId)); + "." + std::string(tagName(tag, ifdId));
} }
@ -352,41 +355,31 @@ namespace Exiv2 {
// we find, it doesn't verify whether this is the only match. // we find, it doesn't verify whether this is the only match.
std::pair<uint16, IfdId> ExifTags::decomposeKey(const std::string& key) std::pair<uint16, IfdId> ExifTags::decomposeKey(const std::string& key)
{ {
// Get the IFD, section name and tag name parts of the key // Get the family name, IFD name and tag name parts of the key
std::string::size_type pos1 = key.find('.'); std::string::size_type pos1 = key.find('.');
if (pos1 == std::string::npos) throw Error("Invalid key"); if (pos1 == std::string::npos) throw Error("Invalid key");
std::string ifdItem = key.substr(0, pos1); std::string familyName = key.substr(0, pos1);
if (familyName != std::string(ExifTags::familyName())) {
throw Error("Invalid key");
}
std::string::size_type pos0 = pos1 + 1; std::string::size_type pos0 = pos1 + 1;
pos1 = key.find('.', pos0); pos1 = key.find('.', pos0);
if (pos1 == std::string::npos) throw Error("Invalid key"); if (pos1 == std::string::npos) throw Error("Invalid key");
std::string sectionName = key.substr(pos0, pos1 - pos0); std::string ifdItem = key.substr(pos0, pos1 - pos0);
pos0 = pos1 + 1; pos0 = pos1 + 1;
std::string tagName = key.substr(pos0); std::string tagName = key.substr(pos0);
if (tagName == "") throw Error("Invalid key"); if (tagName == "") throw Error("Invalid key");
// Check if this is a MakerNote key, stop processing if it is // Find IfdId
if (ifdItem == ifdInfo_[makerIfd].item_) { int i;
return std::make_pair(0xffff, makerIfd); for (i = int(lastIfdId) - 1; i > 0; --i) {
if (ifdInfo_[i].item_ == ifdItem) break;
} }
IfdId ifdId = IfdId(i);
// Use the parts of the key to find tag and IFD id if (ifdId == ifdIdNotSet) return std::make_pair(0xffff, ifdId);
IfdId ifdId = ifdIdNotSet;
uint16 tag = 0xffff;
SectionId s = sectionId(sectionName); return std::make_pair(tag(tagName, ifdId), ifdId);
if (s == sectionIdNotSet) return std::make_pair(tag, ifdId);
for (int i = 0; i < lastIfdId; ++i) {
if (ifdInfo_[i].item_ == ifdItem) {
ifdId = ifdInfo_[i].ifdId_;
int k = tagInfoIdx(tagName, ifdId);
if (k != -1 && tagInfos_[ifdId][k].sectionId_ == s) {
tag = tagInfos_[ifdId][k].tag_;
break;
}
}
}
return std::make_pair(tag, ifdId);
} // ExifTags::decomposeKey } // ExifTags::decomposeKey
std::ostream& ExifTags::printTag(std::ostream& os, std::ostream& ExifTags::printTag(std::ostream& os,

@ -21,7 +21,7 @@
/*! /*!
@file tags.hpp @file tags.hpp
@brief Exif tag and type information @brief Exif tag and type information
@version $Name: $ $Revision: 1.24 $ @version $Name: $ $Revision: 1.25 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 15-Jan-04, ahu: created<BR> @date 15-Jan-04, ahu: created<BR>
@ -72,7 +72,8 @@ namespace Exiv2 {
IfdInfo(IfdId ifdId, const char* name, const char* item); IfdInfo(IfdId ifdId, const char* name, const char* item);
IfdId ifdId_; //!< IFD id IfdId ifdId_; //!< IFD id
const char* name_; //!< IFD name const char* name_; //!< IFD name
const char* item_; //!< Related image item //! Related IFD item. This is also an IFD name, unique for each IFD.
const char* item_;
}; };
//! Contains information pertaining to one section //! Contains information pertaining to one section
@ -113,6 +114,9 @@ namespace Exiv2 {
ExifTags& operator=(const ExifTags& rhs); ExifTags& operator=(const ExifTags& rhs);
public: public:
//! Return an identifier for Exif metadata
static const char* familyName() { return familyName_; }
/*! /*!
@brief Return the name of the tag. @brief Return the name of the tag.
@param tag The tag @param tag The tag
@ -167,7 +171,7 @@ namespace Exiv2 {
static SectionId sectionId(const std::string& sectionName); static SectionId sectionId(const std::string& sectionName);
/*! /*!
@brief Return the key for the tag and IFD id. The key is of the form @brief Return the key for the tag and IFD id. The key is of the form
'ifdItem.sectionName.tagName'. '<b>Exif</b>.ifdItem.tagName'.
*/ */
static std::string makeKey(uint16 tag, IfdId ifdId); static std::string makeKey(uint16 tag, IfdId ifdId);
/*! /*!
@ -187,7 +191,8 @@ namespace Exiv2 {
private: private:
static int tagInfoIdx(uint16 tag, IfdId ifdId); static int tagInfoIdx(uint16 tag, IfdId ifdId);
static int tagInfoIdx(const std::string& tagName, IfdId ifdId);
static const char* familyName_;
static const IfdInfo ifdInfo_[]; static const IfdInfo ifdInfo_[];
static const SectionInfo sectionInfo_[]; static const SectionInfo sectionInfo_[];

@ -3,7 +3,7 @@
Abstract : ExifData write unit tests Abstract : ExifData write unit tests
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Version : $Name: $ $Revision: 1.7 $ Version : $Name: $ $Revision: 1.8 $
Test procedure: Test procedure:
$ rm -f test.jpg thumb.jpg iii ttt; $ rm -f test.jpg thumb.jpg iii ttt;
@ -59,77 +59,77 @@ try {
std::cerr << "Case 1: "; std::cerr << "Case 1: ";
std::cerr << "Non-intrusive change to the standard Exif metadata\n"; std::cerr << "Non-intrusive change to the standard Exif metadata\n";
testCase(testFile, "test1.jpg", "thumb1", testCase(testFile, "test1.jpg", "thumb1",
"Image.DateTime.DateTimeOriginal", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22"); "1999:11:22 00:11:22");
break; break;
case 2: case 2:
std::cerr << "Case 2: "; std::cerr << "Case 2: ";
std::cerr << "Non-intrusive change to the makernote metadata\n"; std::cerr << "Non-intrusive change to the makernote metadata\n";
testCase(testFile, "test2.jpg", "thumb2", testCase(testFile, "test2.jpg", "thumb2",
"Makernote.Canon.OwnerName", "Exif.Canon.OwnerName",
"Chan YeeSend"); "Chan YeeSend");
break; break;
case 3: case 3:
std::cerr << "Case 3: "; std::cerr << "Case 3: ";
std::cerr << "Non-intrusive change to the Exif metadata (w/o makernote)\n"; std::cerr << "Non-intrusive change to the Exif metadata (w/o makernote)\n";
testCase(testFile, "test3.jpg", "thumb3", testCase(testFile, "test3.jpg", "thumb3",
"Image.DateTime.DateTimeOriginal", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22"); "1999:11:22 00:11:22");
break; break;
case 4: case 4:
std::cerr << "Case 4: "; std::cerr << "Case 4: ";
std::cerr << "Intrusive change to the standard Exif metadata\n"; std::cerr << "Intrusive change to the standard Exif metadata\n";
testCase(testFile, "test4.jpg", "thumb4", testCase(testFile, "test4.jpg", "thumb4",
"Image.DateTime.DateTimeOriginal", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22 and twenty seconds"); "1999:11:22 00:11:22 and twenty seconds");
break; break;
case 5: case 5:
std::cerr << "Case 5: "; std::cerr << "Case 5: ";
std::cerr << "Intrusive change to the Canon makernote metadata\n"; std::cerr << "Intrusive change to the Canon makernote metadata\n";
testCase(testFile, "test5.jpg", "thumb5", testCase(testFile, "test5.jpg", "thumb5",
"Makernote.Canon.OwnerName", "Exif.Canon.OwnerName",
"Frau Chan YeeSend und Herr Andreas Huggel"); "Frau Chan YeeSend und Herr Andreas Huggel");
break; break;
case 6: case 6:
std::cerr << "Case 6: "; std::cerr << "Case 6: ";
std::cerr << "Intrusive change to the Exif metadata (w/o makernote)\n"; std::cerr << "Intrusive change to the Exif metadata (w/o makernote)\n";
testCase(testFile, "test6.jpg", "thumb6", testCase(testFile, "test6.jpg", "thumb6",
"Image.DateTime.DateTimeOriginal", "Exif.Photo.DateTimeOriginal",
"1999:11:22 00:11:22 and twenty seconds"); "1999:11:22 00:11:22 and twenty seconds");
break; break;
case 7: case 7:
std::cerr << "Case 7: "; std::cerr << "Case 7: ";
std::cerr << "Intrusive change to the Fujifilm makernote metadata\n"; std::cerr << "Intrusive change to the Fujifilm makernote metadata\n";
testCase(testFile, "test7.jpg", "thumb7", testCase(testFile, "test7.jpg", "thumb7",
"Makernote.Fujifilm.Quality", "Exif.Fujifilm.Quality",
"Typical Fujifilm Quality"); "Typical Fujifilm Quality");
break; break;
case 8: case 8:
std::cerr << "Case 8: "; std::cerr << "Case 8: ";
std::cerr << "Intrusive change to the Sigma makernote metadata\n"; std::cerr << "Intrusive change to the Sigma makernote metadata\n";
testCase(testFile, "test8.jpg", "thumb8", testCase(testFile, "test8.jpg", "thumb8",
"Makernote.Sigma.ResolutionMode", "Exif.Sigma.ResolutionMode",
"Sigma HI resolution"); "Sigma HI resolution");
break; break;
case 9: case 9:
std::cerr << "Case 9: "; std::cerr << "Case 9: ";
std::cerr << "Intrusive change to the Nikon1 makernote metadata\n"; std::cerr << "Intrusive change to the Nikon1 makernote metadata\n";
testCase(testFile, "test9.jpg", "thumb9", testCase(testFile, "test9.jpg", "thumb9",
"Makernote.Nikon1.Quality", "Exif.Nikon1.Quality",
"Typical Nikon1 Quality"); "Typical Nikon1 Quality");
break; break;
case 10: case 10:
std::cerr << "Case 10: "; std::cerr << "Case 10: ";
std::cerr << "Intrusive change to the Nikon2 makernote metadata\n"; std::cerr << "Intrusive change to the Nikon2 makernote metadata\n";
testCase(testFile, "test10.jpg", "thumb10", testCase(testFile, "test10.jpg", "thumb10",
"Makernote.Nikon2.0x0002", "Exif.Nikon2.0x0002",
"Nikon2 Version 2"); "Nikon2 Version 2");
break; break;
case 11: case 11:
std::cerr << "Case 11: "; std::cerr << "Case 11: ";
std::cerr << "Intrusive change to the Nikon3 makernote metadata\n"; std::cerr << "Intrusive change to the Nikon3 makernote metadata\n";
testCase(testFile, "test11.jpg", "thumb11", testCase(testFile, "test11.jpg", "thumb11",
"Makernote.Nikon3.Quality", "Exif.Nikon3.Quality",
"Typical Nikon3 Quality"); "Typical Nikon3 Quality");
break; break;
@ -159,6 +159,7 @@ void testCase(const std::string& file1,
const std::string& key, const std::string& key,
const std::string& value) const std::string& value)
{ {
ExifKey ek(key);
ExifData ed1; ExifData ed1;
std::cerr << "---> Reading file " << file1 << "\n"; std::cerr << "---> Reading file " << file1 << "\n";
@ -169,9 +170,9 @@ void testCase(const std::string& file1,
} }
std::cerr << "---> Modifying Exif data\n"; std::cerr << "---> Modifying Exif data\n";
Exiv2::ExifData::iterator pos = ed1.findKey(key); Exiv2::ExifData::iterator pos = ed1.findKey(ek);
if (pos == ed1.end()) { if (pos == ed1.end()) {
throw Error("Metadatum with key = " + key + " not found"); throw Error("Metadatum with key = " + ek.key() + " not found");
} }
pos->setValue(value); pos->setValue(value);

@ -3,7 +3,7 @@
Abstract : ExifData write unit tests for Exif data created from scratch Abstract : ExifData write unit tests for Exif data created from scratch
File : write2-test.cpp File : write2-test.cpp
Version : $Name: $ $Revision: 1.4 $ Version : $Name: $ $Revision: 1.5 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net> Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History : 26-Jun-04, ahu: created History : 26-Jun-04, ahu: created
@ -31,7 +31,7 @@ try {
std::cout <<"----- One IFD0 tag\n"; std::cout <<"----- One IFD0 tag\n";
Exiv2::ExifData ed1; Exiv2::ExifData ed1;
Exiv2::Exifdatum md1(Exiv2::ExifKey("Image.OtherTags.Model")); Exiv2::Exifdatum md1(Exiv2::ExifKey("Exif.Image.Model"));
md1.setValue("Test 1"); md1.setValue("Test 1");
ed1.add(md1); ed1.add(md1);
write(file, ed1); write(file, ed1);
@ -39,7 +39,7 @@ try {
std::cout <<"\n----- One Exif tag\n"; std::cout <<"\n----- One Exif tag\n";
Exiv2::ExifData ed2; Exiv2::ExifData ed2;
Exiv2::Exifdatum md2(Exiv2::ExifKey("Image.DateTime.DateTimeOriginal")); Exiv2::Exifdatum md2(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"));
md2.setValue("Test 2"); md2.setValue("Test 2");
ed2.add(md2); ed2.add(md2);
write(file, ed2); write(file, ed2);
@ -49,7 +49,7 @@ try {
std::cout <<"\n----- One IOP tag\n"; std::cout <<"\n----- One IOP tag\n";
Exiv2::ExifData ed3; Exiv2::ExifData ed3;
Exiv2::Exifdatum md3(Exiv2::ExifKey("Image.Interoperability.InteroperabilityVersion")); Exiv2::Exifdatum md3(Exiv2::ExifKey("Exif.Iop.InteroperabilityVersion"));
md3.setValue("Test 3"); md3.setValue("Test 3");
ed3.add(md3); ed3.add(md3);
write(file, ed3); write(file, ed3);
@ -57,7 +57,7 @@ try {
std::cout <<"\n----- One GPS tag\n"; std::cout <<"\n----- One GPS tag\n";
Exiv2::ExifData ed4; Exiv2::ExifData ed4;
Exiv2::Exifdatum md4(Exiv2::ExifKey("Image.GPS.GPSVersionID")); Exiv2::Exifdatum md4(Exiv2::ExifKey("Exif.GPSInfo.GPSVersionID"));
md4.setValue("Test 4"); md4.setValue("Test 4");
ed4.add(md4); ed4.add(md4);
write(file, ed4); write(file, ed4);
@ -66,11 +66,11 @@ try {
// Todo: Fix this // Todo: Fix this
std::cout <<"\n----- One IFD1 tag\n"; std::cout <<"\n----- One IFD1 tag\n";
Exiv2::ExifData ed5; Exiv2::ExifData ed5;
Exiv2::Exifdatum md5(Exiv2::ExifKey("Thumbnail.OtherTags.Artist")); Exiv2::Exifdatum md5(Exiv2::ExifKey("Exif.Thumbnail.Artist"));
md5.setValue("Test 5"); md5.setValue("Test 5");
ed5.add(md5); ed5.add(md5);
Exiv2::Exifdatum md6(Exiv2::ExifKey("Image.OtherTags.Model")); Exiv2::Exifdatum md6(Exiv2::ExifKey("Exif.Image.Model"));
md6.setValue("Test 5 (Fix me!)"); md6.setValue("Test 5 (Fix me!)");
ed5.add(md6); ed5.add(md6);

Loading…
Cancel
Save