xmpsample.cpp

Sample usage of high-level XMP classes.

00001 // ***************************************************************** -*- C++ -*-
00002 // xmpsample.cpp, $Rev: 1479 $
00003 // Sample/test for high level XMP classes. See also addmoddel.cpp
00004 
00005 #include <exiv2/xmp.hpp>
00006 #include <exiv2/error.hpp>
00007 
00008 #include <string>
00009 #include <iostream>
00010 #include <iomanip>
00011 #include <cassert>
00012 #include <cmath>
00013 
00014 bool isEqual(float a, float b)
00015 {
00016     double d = std::fabs(a - b);
00017     return d < 0.00001;
00018 }
00019 
00020 int main()
00021 try {
00022     // The XMP property container
00023     Exiv2::XmpData xmpData;
00024 
00025     // -------------------------------------------------------------------------
00026     // Teaser: Setting XMP properties doesn't get much easier than this:
00027 
00028     xmpData["Xmp.dc.source"]  = "xmpsample.cpp";    // a simple text value
00029     xmpData["Xmp.dc.subject"] = "Palmtree";         // an array item
00030     xmpData["Xmp.dc.subject"] = "Rubbertree";       // add a 2nd array item
00031     // a language alternative with two entries and without default
00032     xmpData["Xmp.dc.title"]   = "lang=de-DE Sonnenuntergang am Strand";
00033     xmpData["Xmp.dc.title"]   = "lang=en-US Sunset on the beach";
00034 
00035     // -------------------------------------------------------------------------
00036     // Any properties can be set provided the namespace is known. Values of any
00037     // type can be assigned to an Xmpdatum, if they have an output operator. The
00038     // default XMP value type for unknown properties is a simple text value.
00039 
00040     xmpData["Xmp.dc.one"]     = -1;
00041     xmpData["Xmp.dc.two"]     = 3.1415;
00042     xmpData["Xmp.dc.three"]   = Exiv2::Rational(5, 7);
00043     xmpData["Xmp.dc.four"]    = uint16_t(255);
00044     xmpData["Xmp.dc.five"]    = int32_t(256);
00045     xmpData["Xmp.dc.six"]     = false;
00046 
00047     // In addition, there is a dedicated assignment operator for Exiv2::Value
00048     Exiv2::XmpTextValue val("Seven");
00049     xmpData["Xmp.dc.seven"]   = val;
00050     xmpData["Xmp.dc.eight"]   = true;
00051 
00052     // Extracting values
00053     assert(xmpData["Xmp.dc.one"].toLong() == -1);
00054     assert(xmpData["Xmp.dc.one"].value().ok());
00055 
00056     const Exiv2::Value &getv1 = xmpData["Xmp.dc.one"].value();
00057     assert(isEqual(getv1.toFloat(), -1)); 
00058     assert(getv1.ok());
00059     assert(getv1.toRational() == Exiv2::Rational(-1, 1));
00060     assert(getv1.ok());
00061 
00062     const Exiv2::Value &getv2 = xmpData["Xmp.dc.two"].value();
00063     assert(isEqual(getv2.toFloat(), 3.1415f)); 
00064     assert(getv2.ok());
00065     assert(getv2.toLong() == 3);
00066     assert(getv2.ok());
00067     Exiv2::Rational R = getv2.toRational();
00068     assert(getv2.ok());
00069     assert(isEqual(static_cast<float>(R.first) / R.second, 3.1415f ));
00070 
00071     const Exiv2::Value &getv3 = xmpData["Xmp.dc.three"].value();
00072     assert(isEqual(getv3.toFloat(), 5.0f/7.0f)); 
00073     assert(getv3.ok());
00074     assert(getv3.toLong() == 0);  // long(5.0 / 7.0) 
00075     assert(getv3.ok());
00076     assert(getv3.toRational() == Exiv2::Rational(5, 7));
00077     assert(getv3.ok());
00078     
00079     const Exiv2::Value &getv6 = xmpData["Xmp.dc.six"].value();
00080     assert(getv6.toLong() == 0);
00081     assert(getv6.ok());
00082     assert(getv6.toFloat() == 0.0);
00083     assert(getv6.ok());
00084     assert(getv6.toRational() == Exiv2::Rational(0, 1));
00085     assert(getv6.ok());
00086     
00087     const Exiv2::Value &getv7 = xmpData["Xmp.dc.seven"].value();
00088     getv7.toLong(); // this should fail
00089     assert(!getv7.ok()); 
00090 
00091     const Exiv2::Value &getv8 = xmpData["Xmp.dc.eight"].value();
00092     assert(getv8.toLong() == 1);
00093     assert(getv8.ok());
00094     assert(getv8.toFloat() == 1.0);
00095     assert(getv8.ok());
00096     assert(getv8.toRational() == Exiv2::Rational(1, 1));
00097     assert(getv8.ok());
00098 
00099     // Deleting an XMP property
00100     Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.dc.eight"));
00101     if (pos == xmpData.end()) throw Exiv2::Error(1, "Key not found");
00102     xmpData.erase(pos);
00103 
00104     // -------------------------------------------------------------------------
00105     // Exiv2 has specialized values for simple XMP properties, arrays of simple
00106     // properties and language alternatives.
00107 
00108     // Add a simple XMP property in a known namespace    
00109     Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpText);
00110     v->read("image/jpeg");
00111     xmpData.add(Exiv2::XmpKey("Xmp.dc.format"), v.get());
00112 
00113     // Add an ordered array of text values.
00114     v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt.
00115     v->read("1) The first creator");         // The sequence in which the array
00116     v->read("2) The second creator");        // elements are added is their
00117     v->read("3) And another one");           // order in the array.
00118     xmpData.add(Exiv2::XmpKey("Xmp.dc.creator"), v.get());
00119 
00120     // Add a language alternative property
00121     v = Exiv2::Value::create(Exiv2::langAlt);
00122     v->read("lang=de-DE Hallo, Welt");       // The default doesn't need a 
00123     v->read("Hello, World");                 // qualifier
00124     xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get());
00125 
00126     // According to the XMP specification, Xmp.tiff.ImageDescription is an
00127     // alias for Xmp.dc.description. Exiv2 treats an alias just like any
00128     // other property and leaves it to the application to implement specific
00129     // behaviour if desired.
00130     xmpData["Xmp.tiff.ImageDescription"] = "TIFF image description";
00131     xmpData["Xmp.tiff.ImageDescription"] = "lang=de-DE TIFF Bildbeschreibung";
00132 
00133     // -------------------------------------------------------------------------
00134     // Register a namespace which Exiv2 doesn't know yet. This is only needed
00135     // when properties are added manually. If the XMP metadata is read from an
00136     // image, namespaces are decoded and registered at the same time.
00137     Exiv2::XmpProperties::registerNs("myNamespace/", "ns");
00138 
00139     // -------------------------------------------------------------------------
00140     // Add a property in the new custom namespace.
00141     xmpData["Xmp.ns.myProperty"] = "myValue";
00142 
00143     // -------------------------------------------------------------------------
00144     // There are no specialized values for structures, qualifiers and nested
00145     // types. However, these can be added by using an XmpTextValue and a path as
00146     // the key.
00147 
00148     // Add a structure
00149     Exiv2::XmpTextValue tv("16");
00150     xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv);
00151     tv.read("9");
00152     xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv);
00153     tv.read("inch");
00154     xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv);
00155 
00156     // Add an element with a qualifier (using the namespace registered above)
00157     xmpData["Xmp.dc.publisher"] = "James Bond";  // creates an unordered array
00158     xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent";
00159 
00160     // Add a qualifer to an array element of Xmp.dc.creator (added above)
00161     tv.read("programmer");
00162     xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv);
00163 
00164     // Add an array of structures
00165     tv.read("");                                         // Clear the value
00166     tv.setXmpArrayType(Exiv2::XmpValue::xaBag);
00167     xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type.
00168 
00169     tv.setXmpArrayType(Exiv2::XmpValue::xaNone);
00170     tv.read("Birthday party");
00171     xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv);
00172     tv.read("Photographer");
00173     xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv);
00174 
00175     tv.read("Wedding ceremony");
00176     xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv);
00177     tv.read("Best man");
00178     xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv);
00179 
00180     // -------------------------------------------------------------------------
00181     // Output XMP properties
00182     for (Exiv2::XmpData::const_iterator md = xmpData.begin(); 
00183          md != xmpData.end(); ++md) {
00184         std::cout << std::setfill(' ') << std::left
00185                   << std::setw(44)
00186                   << md->key() << " "
00187                   << std::setw(9) << std::setfill(' ') << std::left
00188                   << md->typeName() << " "
00189                   << std::dec << std::setw(3)
00190                   << std::setfill(' ') << std::right
00191                   << md->count() << "  "
00192                   << std::dec << md->value()
00193                   << std::endl;
00194     }
00195 
00196     // -------------------------------------------------------------------------
00197     // Serialize the XMP data and output the XMP packet
00198     std::string xmpPacket;
00199     if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
00200         throw Exiv2::Error(1, "Failed to serialize XMP data");
00201     }
00202     std::cout << xmpPacket << "\n";
00203 
00204     // Cleanup
00205     Exiv2::XmpParser::terminate();
00206 
00207     return 0;
00208 }
00209 catch (Exiv2::AnyError& e) {
00210     std::cout << "Caught Exiv2 exception '" << e << "'\n";
00211     return -1;
00212 }

Generated on Sat Jul 4 23:52:05 2009 for Exiv2 by  doxygen 1.4.7