From 9beec8880d80d12ba8b28bf97762d9bbfe324f8b Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Sat, 22 Sep 2007 15:28:49 +0000 Subject: [PATCH] Added XMP sample (incomplete), bugfixes. --- src/Makefile | 3 +- src/error.cpp | 1 - src/value.cpp | 4 +-- src/value.hpp | 5 ++- src/xmp.cpp | 16 +++++++-- src/xmpsample.cpp | 67 ++++++++++++++++++++++++++++++++++++ test/data/xmpparser-test.out | 8 ++--- 7 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 src/xmpsample.cpp diff --git a/src/Makefile b/src/Makefile index 6fcd802a..c522bd44 100644 --- a/src/Makefile +++ b/src/Makefile @@ -122,7 +122,8 @@ BINSRC = addmoddel.cpp \ tiffparse.cpp ifdef ENABLE_XMP BINSRC += xmpparse.cpp \ - xmpparser-test.cpp + xmpparser-test.cpp \ + xmpsample.cpp endif # Main source file of the Exiv2 application diff --git a/src/error.cpp b/src/error.cpp index 924c970a..a6b701cc 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -90,7 +90,6 @@ namespace Exiv2 { ErrMsg( 45, N_("Schema namespace %1 is not registered with the XMP Toolkit")), // %1=namespace ErrMsg( 46, N_("No namespace registered for prefix `%1'")), // %1=prefix ErrMsg( 47, N_("No prefix registered for namespace `%1'")), // %1=namespace - ErrMsg( 48, N_("Invalid type `%1' to create an XmpArrayValue")), // %1=typeName // Last error message (message is not used) ErrMsg( -2, N_("(Unknown Error)")) diff --git a/src/value.cpp b/src/value.cpp index 44995a34..bcc99e76 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -447,9 +447,7 @@ namespace Exiv2 { case xmpAlt: xa = xaAlt; break; case xmpBag: xa = xaBag; break; case xmpSeq: xa = xaSeq; break; - default: - throw Error(48, TypeInfo::typeName(typeId)); - break; + default: break; } return xa; } diff --git a/src/value.hpp b/src/value.hpp index f5f59569..e4db4aa4 100644 --- a/src/value.hpp +++ b/src/value.hpp @@ -673,7 +673,10 @@ namespace Exiv2 { virtual int read(const std::string& buf) =0; //@} - //! Return XMP array type for an array Value TypeId + /*! + @brief Return XMP array type for an array Value TypeId, xaNone if + \em typeId is not an XMP array value type. + */ static XmpArrayType xmpArrayType(TypeId typeId); protected: diff --git a/src/xmp.cpp b/src/xmp.cpp index 7eac7908..bfa7dfc9 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -565,12 +565,22 @@ namespace Exiv2 { const LangAltValue* la = dynamic_cast(&i->value()); if (la == 0) throw Error(43, i->key()); int idx = 1; - for (LangAltValue::ValueType::const_iterator k = la->value_.begin(); - k != la->value_.end(); ++k) { + // write the default first + LangAltValue::ValueType::const_iterator k = la->value_.find("x-default"); + if (k != la->value_.end()) { #ifdef DEBUG printNode(ns, i->tagName(), k->second, 0); #endif - meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAltText, k->second.c_str()); + meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); + const std::string item = i->tagName() + "[" + toString(idx++) + "]"; + meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); + } + for (k = la->value_.begin(); k != la->value_.end(); ++k) { + if (k->first == "x-default") continue; +#ifdef DEBUG + printNode(ns, i->tagName(), k->second, 0); +#endif + meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); const std::string item = i->tagName() + "[" + toString(idx++) + "]"; meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); } diff --git a/src/xmpsample.cpp b/src/xmpsample.cpp new file mode 100644 index 00000000..4dc1adfc --- /dev/null +++ b/src/xmpsample.cpp @@ -0,0 +1,67 @@ +// ***************************************************************** -*- C++ -*- +// xmpsample.cpp, $Rev$ +// Sample/test for high level XMP classes + +#include "value.hpp" +#include "xmp.hpp" +#include "error.hpp" + +#include +#include +#include + +using namespace Exiv2; + +int main() +try { + // The XMP property container + Exiv2::XmpData xmpData; + + // Add a simple XMP property in a known namespace + Exiv2::Value::AutoPtr v = Exiv2::Value::create(xmpText); + v->read("image/jpeg"); + xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get()); + + // Add an ordered array of text values + v = Exiv2::Value::create(xmpSeq); + v->read("1) The first creator"); // the sequence in which the array elements + v->read("2) The second creator"); // are added is relevant + v->read("3) And another one"); + xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get()); + + // Add a language alternative property + v = Exiv2::Value::create(langAlt); + v->read("lang=de-DE Hallo, Welt"); // the default doesn't need a qualifier + v->read("Hello, World"); // and it will become the first element + xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get()); + + // Output XMP properties + for (Exiv2::XmpData::const_iterator md = xmpData.begin(); + md != xmpData.end(); ++md) { + std::cout << std::setfill(' ') << std::left + << std::setw(44) + << md->key() << " " + << std::setw(9) << std::setfill(' ') << std::left + << md->typeName() << " " + << std::dec << std::setw(3) + << std::setfill(' ') << std::right + << md->count() << " " + << std::dec << md->value() + << std::endl; + } + + // Serialize the XMP data and output the XMP packet + std::string xmpPacket; + if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) { + throw Exiv2::Error(1, "Failed to serialize XMP data"); + } + std::cout << xmpPacket << "\n"; + + // Cleanup + Exiv2::XmpParser::terminate(); + return 0; +} +catch (Exiv2::AnyError& e) { + std::cout << "Caught Exiv2 exception '" << e << "'\n"; + return -1; +} diff --git a/test/data/xmpparser-test.out b/test/data/xmpparser-test.out index 56bf373b..330b9a01 100644 --- a/test/data/xmpparser-test.out +++ b/test/data/xmpparser-test.out @@ -22,7 +22,7 @@ Xmp.tiff.ImageWidth XmpText 3 360 Xmp.tiff.ImageLength XmpText 3 216 Xmp.tiff.NativeDigest XmpText 134 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;D0485928256FC8D17D036C26919E106D Xmp.tiff.Make XmpText 5 Nikon -Xmp.tiff.BitsPerSample XmpBag 3 8, 8, 8 +Xmp.tiff.BitsPerSample XmpSeq 3 8, 8, 8 Xmp.exif.PixelXDimension XmpText 3 360 Xmp.exif.PixelYDimension XmpText 3 216 Xmp.exif.ColorSpace XmpText 1 1 @@ -34,7 +34,7 @@ Xmp.exif.NativeDigest XmpText 414 36864,40960,40961,37 > 35d34 < Blue Square Test File - .jpg -36a36 +37a37 > Blue Square Test File - .jpg -----> Decoding XMP data read from StaffPhotographer-Example.xmp <----- Xmp.iptc.IntellectualGenre XmpText 7 Profile @@ -75,7 +75,7 @@ Xmp.tiff.Orientation XmpText 1 1 Xmp.tiff.ImageWidth XmpText 3 432 Xmp.tiff.ImageLength XmpText 3 293 Xmp.tiff.NativeDigest XmpText 134 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;24B61B075FA9960B09291337508795BF -Xmp.tiff.BitsPerSample XmpBag 3 8, 8, 8 +Xmp.tiff.BitsPerSample XmpSeq 3 8, 8, 8 Xmp.xmp.CreateDate XmpText 25 2005-03-13T02:01:44-06:00 Xmp.xmp.ModifyDate XmpText 25 2005-03-13T02:01:44-06:00 Xmp.xmp.MetadataDate XmpText 25 2007-01-08T13:25:45+01:00 @@ -93,7 +93,7 @@ Xmp.dc.format XmpText 10 image/jpeg Xmp.dc.description LangAlt 1 lang="x-default" After digging the furrows another ten yards with the tractor, Jim Moore hops off to hand-set more leeks and onions. Xmp.dc.title LangAlt 1 lang="x-default" 01661gdx Xmp.dc.rights LangAlt 1 lang="x-default" ©2003 Big Newspaper, all rights reserved -Xmp.dc.creator XmpBag 1 John Doe +Xmp.dc.creator XmpSeq 1 John Doe Xmp.dc.subject XmpBag 22 agriculture, farm laborer, farmer, field hand, field worker, humans, occupation, people, agricultural, agronomy, crops, onions, vegetable crops, plants, vegetables, outdoors, outside, agricultural equipment, tractor, gender, male, men Xmp.wine.Recommend XmpText 5 False -----> Encoding XMP data to write to StaffPhotographer-Example.xmp-new <-----