Extended xmpsample.cpp, related bugfixes and tweaks.
This commit is contained in:
+14
-13
@@ -6,17 +6,6 @@ Exif and IPTC classes. The property-repository is XmpProperties.
|
||||
In addition to the expected new members, class Image also
|
||||
has a new interface to access the raw XMP packet.
|
||||
|
||||
Todo: XMP support is controlled with the ENABLE_XMP directive
|
||||
in config/config.mk.in. This will be a configure option
|
||||
eventually. For now, comment the line "ENABLE_XMP = 1" either
|
||||
in config.mk.in before running ./configure or in config.mk to
|
||||
build without XMP support.
|
||||
|
||||
Exiv2 uses the Adobe XMP toolkit (XMP SDK) to parse
|
||||
and serialize XMP packets (only the XMPCore component).
|
||||
|
||||
Supported XMP value types
|
||||
-------------------------
|
||||
All XMP value types are supported: Simple types, structures,
|
||||
arrays, property qualifiers and language alternatives.
|
||||
|
||||
@@ -35,16 +24,28 @@ namespaces can be registered.
|
||||
The specialized Exiv2 values XmpArrayValue and LangAltValue are
|
||||
provided to simplify the use of XMP properties.
|
||||
|
||||
See xmpsample.cpp for examples of how to set various types of
|
||||
XMP properties.
|
||||
|
||||
Note: Unlike Exif and IPTC tags, XMP properties do not have
|
||||
a tag number.
|
||||
|
||||
Todo: Conversion between XMP and Exif/IPTC metadata.
|
||||
|
||||
XMP toolkit installation
|
||||
Todo: XMP support is controlled with the ENABLE_XMP directive
|
||||
in config/config.mk.in. This will be a configure option
|
||||
eventually. For now, comment the line "ENABLE_XMP = 1" either
|
||||
in config.mk.in before running ./configure or in config.mk to
|
||||
build without XMP support.
|
||||
|
||||
Exiv2 uses the Adobe XMP Toolkit (XMP SDK) to parse
|
||||
and serialize XMP packets (only the XMPCore component).
|
||||
|
||||
XMP Toolkit installation
|
||||
========================
|
||||
This is what worked for me on a Debian GNU/Linux (testing)
|
||||
system. Your mileage may vary. Please check with Adobe if
|
||||
you encounter problems with the XMP toolkit installation.
|
||||
you encounter problems with the XMP Toolkit installation.
|
||||
|
||||
Installation directory
|
||||
----------------------
|
||||
|
||||
@@ -133,3 +133,7 @@ bug tracking system</a>.</p>
|
||||
@example iptceasy.cpp
|
||||
The quickest way to access, set or modify IPTC metadata
|
||||
*/
|
||||
/*!
|
||||
@example xmpsample.cpp
|
||||
Sample usage of high-level XMP classes.
|
||||
*/
|
||||
|
||||
+2
-3
@@ -78,9 +78,9 @@ namespace Exiv2 {
|
||||
ErrMsg( 33, N_("This does not look like a CRW image")),
|
||||
ErrMsg( 34, N_("%1: Not supported")), // %1=function
|
||||
ErrMsg( 35, N_("No namespace info available for XMP prefix `%1'")), // %1=prefix
|
||||
ErrMsg( 36, N_("No XMP property list for prefix `%1'")), // %1=prefix
|
||||
ErrMsg( 36, N_("No prefix registered for namespace `%1'")), // %1=namespace
|
||||
ErrMsg( 37, N_("Size of %1 JPEG segment is larger than 65535 bytes")), // %1=type of metadata (Exif, IPTC, JPEG comment)
|
||||
ErrMsg( 38, N_("Unknown XMP property `%1:%2'")), // %1=prefix, %2=property name
|
||||
ErrMsg( 38, N_("Unhandled Xmpdatum %1 of type %2")), // %1=key, %2=value type
|
||||
ErrMsg( 39, N_("Unhandled XMP node %1 with opt=%2")), // %1=key, %2=XMP Toolkit option flags
|
||||
ErrMsg( 40, N_("XMP Toolkit error %1: %2")), // %1=XMP_Error::GetID(), %2=XMP_Error::GetErrMsg()
|
||||
ErrMsg( 41, N_("Failed to decode Lang Alt property %1 with opt=%2")), // %1=property path, %3=XMP Toolkit option flags
|
||||
@@ -89,7 +89,6 @@ namespace Exiv2 {
|
||||
ErrMsg( 44, N_("Failed to determine property name from path %1, namespace %2")), // %1=property path, %2=namespace
|
||||
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
|
||||
|
||||
// Last error message (message is not used)
|
||||
ErrMsg( -2, N_("(Unknown Error)"))
|
||||
|
||||
+11
-11
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include "value.hpp"
|
||||
#include "metadatum.hpp"
|
||||
#include "i18n.h" // NLS support.
|
||||
#include "xmp.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@@ -793,8 +794,10 @@ namespace Exiv2 {
|
||||
const std::string& prefix)
|
||||
{
|
||||
std::string ns2 = ns;
|
||||
if (ns2.substr(ns2.size() - 1, 1) != "/") ns2 += "/";
|
||||
if ( ns2.substr(ns2.size() - 1, 1) != "/"
|
||||
&& ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/";
|
||||
nsRegistry_[ns2] = prefix;
|
||||
XmpParser::registerNs(ns2, prefix);
|
||||
}
|
||||
|
||||
std::string XmpProperties::prefix(const std::string& ns)
|
||||
@@ -827,28 +830,26 @@ namespace Exiv2 {
|
||||
|
||||
const char* XmpProperties::propertyTitle(const XmpKey& key)
|
||||
{
|
||||
return propertyInfo(key)->title_;
|
||||
const XmpPropertyInfo* pi = propertyInfo(key);
|
||||
return pi ? pi->title_ : 0;
|
||||
}
|
||||
|
||||
const char* XmpProperties::propertyDesc(const XmpKey& key)
|
||||
{
|
||||
return propertyInfo(key)->desc_;
|
||||
const XmpPropertyInfo* pi = propertyInfo(key);
|
||||
return pi ? pi->desc_ : 0;
|
||||
}
|
||||
|
||||
TypeId XmpProperties::propertyType(const XmpKey& key)
|
||||
{
|
||||
const XmpPropertyInfo* pi = propertyInfo(key, false);
|
||||
const XmpPropertyInfo* pi = propertyInfo(key);
|
||||
return pi ? pi->typeId_ : xmpText;
|
||||
}
|
||||
|
||||
const XmpPropertyInfo* XmpProperties::propertyInfo(const XmpKey& key,
|
||||
bool doThrow)
|
||||
const XmpPropertyInfo* XmpProperties::propertyInfo(const XmpKey& key)
|
||||
{
|
||||
const XmpPropertyInfo* pl = propertyList(key.groupName());
|
||||
if (!pl) {
|
||||
if (doThrow) throw Error(36, key.groupName());
|
||||
else return 0;
|
||||
}
|
||||
if (!pl) return 0;
|
||||
const XmpPropertyInfo* pi = 0;
|
||||
for (int i = 0; pl[i].name_ != 0; ++i) {
|
||||
if (std::string(pl[i].name_) == key.tagName()) {
|
||||
@@ -856,7 +857,6 @@ namespace Exiv2 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pi && doThrow) throw Error(38, key.groupName(), key.tagName());
|
||||
return pi;
|
||||
}
|
||||
|
||||
|
||||
+11
-16
@@ -108,15 +108,15 @@ namespace Exiv2 {
|
||||
/*!
|
||||
@brief Return the title (label) of the property.
|
||||
@param key The property key
|
||||
@return The title (label) of the property
|
||||
@throw Error if the key is invalid.
|
||||
@return The title (label) of the property, 0 if the
|
||||
key is of an unknown property.
|
||||
*/
|
||||
static const char* propertyTitle(const XmpKey& key);
|
||||
/*!
|
||||
@brief Return the description of the property.
|
||||
@param key The property key
|
||||
@return The description of the property
|
||||
@throw Error if the key is invalid.
|
||||
@return The description of the property, 0 if the
|
||||
key is of an unknown property.
|
||||
*/
|
||||
static const char* propertyDesc(const XmpKey& key);
|
||||
/*!
|
||||
@@ -128,21 +128,16 @@ namespace Exiv2 {
|
||||
static TypeId propertyType(const XmpKey& key);
|
||||
/*!
|
||||
@brief Return information for the property for key.
|
||||
Always returns a valid pointer.
|
||||
@param key The property key
|
||||
@param doThrow Flag indicating whether to throw an Error or
|
||||
return 0 if the key is not valid or unknown.
|
||||
@return a pointer to the property information
|
||||
@throw Error if the key is unknown and the \em doThrow
|
||||
flag is true.
|
||||
@return A pointer to the property information, 0 if the
|
||||
key is of an unknown property.
|
||||
*/
|
||||
static const XmpPropertyInfo* propertyInfo(const XmpKey& key,
|
||||
bool doThrow =true);
|
||||
static const XmpPropertyInfo* propertyInfo(const XmpKey& key);
|
||||
/*!
|
||||
@brief Return the namespace name for the schema associated
|
||||
with \em prefix.
|
||||
@param prefix Prefix
|
||||
@return the namespace name
|
||||
@return The namespace name
|
||||
@throw Error if no namespace is registered with \em prefix.
|
||||
*/
|
||||
static std::string ns(const std::string& prefix);
|
||||
@@ -150,7 +145,7 @@ namespace Exiv2 {
|
||||
@brief Return the namespace description for the schema associated
|
||||
with \em prefix.
|
||||
@param prefix Prefix
|
||||
@return the namespace description
|
||||
@return The namespace description
|
||||
@throw Error if no namespace is registered with \em prefix.
|
||||
*/
|
||||
static const char* nsDesc(const std::string& prefix);
|
||||
@@ -166,14 +161,14 @@ namespace Exiv2 {
|
||||
@brief Return information about a schema namespace for \em prefix.
|
||||
Always returns a valid pointer.
|
||||
@param prefix The prefix
|
||||
@return a pointer to the related information
|
||||
@return A pointer to the related information
|
||||
@throw Error if no namespace is registered with \em prefix.
|
||||
*/
|
||||
static const XmpNsInfo* nsInfo(const std::string& prefix);
|
||||
/*!
|
||||
@brief Return the (preferred) prefix for schema namespace \em ns.
|
||||
@param ns Schema namespace
|
||||
@return the prefix or an empty string if namespace \em ns is not
|
||||
@return The prefix or an empty string if namespace \em ns is not
|
||||
registered.
|
||||
*/
|
||||
static std::string prefix(const std::string& ns);
|
||||
|
||||
+1
-1
@@ -652,7 +652,7 @@ namespace Exiv2 {
|
||||
//! Set the XMP array type to indicate that an XMP value is an array.
|
||||
void setXmpArrayType(XmpArrayType xmpArrayType);
|
||||
//! Set the XMP struct type to indicate that an XMP value is a structure.
|
||||
void setXmpStruct(XmpStruct xmpStruct);
|
||||
void setXmpStruct(XmpStruct xmpStruct =xsStruct);
|
||||
/*!
|
||||
@brief Read the value from a character buffer.
|
||||
|
||||
|
||||
+17
-9
@@ -387,6 +387,17 @@ namespace Exiv2 {
|
||||
}
|
||||
}
|
||||
|
||||
bool XmpParser::registerNs(const std::string& ns,
|
||||
const std::string& prefix)
|
||||
{
|
||||
initialize();
|
||||
#ifdef EXV_HAVE_XMP_TOOLKIT
|
||||
return SXMPMeta::RegisterNamespace(ns.c_str(), prefix.c_str(), 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef EXV_HAVE_XMP_TOOLKIT
|
||||
int XmpParser::decode( XmpData& xmpData,
|
||||
const std::string& xmpPacket)
|
||||
@@ -549,15 +560,8 @@ namespace Exiv2 {
|
||||
}
|
||||
|
||||
SXMPMeta meta;
|
||||
|
||||
for (XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) {
|
||||
|
||||
std::string ns = XmpProperties::ns(i->groupName());
|
||||
|
||||
// Todo: Make sure the namespace is registered with XMP-SDK
|
||||
|
||||
// Todo: What about structure namespaces?
|
||||
|
||||
const std::string ns = XmpProperties::ns(i->groupName());
|
||||
XMP_OptionBits options = 0;
|
||||
|
||||
if (i->typeId() == langAlt) {
|
||||
@@ -605,6 +609,7 @@ namespace Exiv2 {
|
||||
#endif
|
||||
meta.SetProperty(ns.c_str(), item.c_str(), i->toString(idx).c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (i->typeId() == xmpText) {
|
||||
if (i->count() == 0) {
|
||||
@@ -619,7 +624,10 @@ namespace Exiv2 {
|
||||
#endif
|
||||
meta.SetProperty(ns.c_str(), i->tagName().c_str(), i->toString(0).c_str(), options);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Don't let any Xmpdatum go by unnoticed
|
||||
throw Error(38, i->tagName(), TypeInfo::typeName(i->typeId()));
|
||||
}
|
||||
meta.SerializeToBuffer(&xmpPacket, kXMP_UseCompactFormat);
|
||||
|
||||
@@ -771,7 +779,7 @@ namespace {
|
||||
property = propPath.substr(idx + 1);
|
||||
std::string prefix = Exiv2::XmpProperties::prefix(schemaNs);
|
||||
if (prefix.empty()) {
|
||||
throw Exiv2::Error(47, propPath, schemaNs);
|
||||
throw Exiv2::Error(36, propPath, schemaNs);
|
||||
}
|
||||
return Exiv2::XmpKey::AutoPtr(new Exiv2::XmpKey(prefix, property));
|
||||
} // makeXmpKey
|
||||
|
||||
+14
-2
@@ -32,9 +32,9 @@
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "metadatum.hpp"
|
||||
#include "types.hpp"
|
||||
#include "value.hpp"
|
||||
#include "properties.hpp"
|
||||
#include "value.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
@@ -245,6 +245,7 @@ namespace Exiv2 {
|
||||
the XMP toolkit to do the job.
|
||||
*/
|
||||
class XmpParser {
|
||||
friend void XmpProperties::registerNs(const std::string&, const std::string&);
|
||||
public:
|
||||
/*!
|
||||
@brief Decode XMP metadata from an XMP packet \em xmpPacket into
|
||||
@@ -295,6 +296,17 @@ namespace Exiv2 {
|
||||
static void terminate();
|
||||
|
||||
private:
|
||||
/*!
|
||||
@brief Register a namespace with the XMP Toolkit.
|
||||
|
||||
XmpProperties::registerNs calls this to synchronize namespaces.
|
||||
|
||||
@return \em true if the registered prefix matches the suggested prefix.
|
||||
*/
|
||||
static bool registerNs(const std::string& ns,
|
||||
const std::string& prefix);
|
||||
|
||||
// DATA
|
||||
static bool initialized_; //! Indicates if the XMP Toolkit has been initialized
|
||||
|
||||
}; // class XmpParser
|
||||
|
||||
+62
-13
@@ -1,8 +1,7 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// xmpsample.cpp, $Rev$
|
||||
// Sample/test for high level XMP classes
|
||||
// Sample/test for high level XMP classes. See also addmoddel.cpp
|
||||
|
||||
#include "value.hpp"
|
||||
#include "xmp.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
@@ -10,31 +9,79 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace Exiv2;
|
||||
|
||||
int main()
|
||||
try {
|
||||
// The XMP property container
|
||||
Exiv2::XmpData xmpData;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Exiv2 has specialized values for simple XMP properties, arrays of simple
|
||||
// properties and language alternatives.
|
||||
|
||||
// Add a simple XMP property in a known namespace
|
||||
Exiv2::Value::AutoPtr v = Exiv2::Value::create(xmpText);
|
||||
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::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");
|
||||
// Add an ordered array of text values.
|
||||
v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt.
|
||||
v->read("1) The first creator"); // The sequence in which the array
|
||||
v->read("2) The second creator"); // elements are added is their
|
||||
v->read("3) And another one"); // order in the array.
|
||||
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
|
||||
v = Exiv2::Value::create(Exiv2::langAlt);
|
||||
v->read("lang=de-DE Hallo, Welt"); // The default doesn't need a
|
||||
v->read("Hello, World"); // qualifier
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.dc.description"), v.get());
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Register a namespace which Exiv2 doesn't know yet. This is only needed
|
||||
// when properties are added manually. If the XMP metadata is read from an
|
||||
// image, namespaces are decoded and registered at the same time.
|
||||
Exiv2::XmpProperties::registerNs("myNamespace/", "ns");
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// There are no specialized values for structures, qualifiers and nested
|
||||
// types. However, these can be added by using a XmpTextValue and a path as
|
||||
// the key.
|
||||
|
||||
// Add a structure
|
||||
Exiv2::XmpTextValue tv("16");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:w"), &tv);
|
||||
tv.read("9");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:h"), &tv);
|
||||
tv.read("inch");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpDM.videoFrameSize/stDim:unit"), &tv);
|
||||
|
||||
// Add an element with a qualifier (using the namespace registered earlier)
|
||||
tv.read("James Bond");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.dc.publisher"), &tv);
|
||||
tv.read("secret agent");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.dc.publisher/?ns:role"), &tv);
|
||||
|
||||
// Add a qualifer to an array element of Xmp.dc.creator (added above)
|
||||
tv.read("programmer");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.dc.creator[2]/?ns:role"), &tv);
|
||||
|
||||
// Add an array of structures
|
||||
tv.read("");
|
||||
tv.setXmpArrayType(Exiv2::XmpValue::xaBag);
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type.
|
||||
tv.setXmpArrayType(Exiv2::XmpValue::xaNone);
|
||||
|
||||
tv.read("Birtday party");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:name"), &tv);
|
||||
tv.read("Photographer");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[1]/stJob:role"), &tv);
|
||||
|
||||
tv.read("Wedding ceremony");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:name"), &tv);
|
||||
tv.read("Best man");
|
||||
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef[2]/stJob:role"), &tv);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Output XMP properties
|
||||
for (Exiv2::XmpData::const_iterator md = xmpData.begin();
|
||||
md != xmpData.end(); ++md) {
|
||||
@@ -50,6 +97,7 @@ try {
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Serialize the XMP data and output the XMP packet
|
||||
std::string xmpPacket;
|
||||
if (0 != Exiv2::XmpParser::encode(xmpPacket, xmpData)) {
|
||||
@@ -59,6 +107,7 @@ try {
|
||||
|
||||
// Cleanup
|
||||
Exiv2::XmpParser::terminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exiv2::AnyError& e) {
|
||||
|
||||
@@ -279,3 +279,87 @@ Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field2 XmpText 12
|
||||
>
|
||||
> <?xpacket end="w"?>
|
||||
\ No newline at end of file
|
||||
Xmp.dc.format XmpText 10 image/jpeg
|
||||
Xmp.dc.creator XmpSeq 3 1) The first creator, 2) The second creator, 3) And another one
|
||||
Xmp.dc.description LangAlt 2 lang="de-DE" Hallo, Welt, lang="x-default" Hello, World
|
||||
Xmp.xmpDM.videoFrameSize/stDim:w XmpText 2 16
|
||||
Xmp.xmpDM.videoFrameSize/stDim:h XmpText 1 9
|
||||
Xmp.xmpDM.videoFrameSize/stDim:unit XmpText 4 inch
|
||||
Xmp.dc.publisher XmpText 10 James Bond
|
||||
Xmp.dc.publisher/?ns:role XmpText 12 secret agent
|
||||
Xmp.dc.creator[2]/?ns:role XmpText 10 programmer
|
||||
Xmp.xmpBJ.JobRef XmpText 0
|
||||
Xmp.xmpBJ.JobRef[1]/stJob:name XmpText 13 Birtday party
|
||||
Xmp.xmpBJ.JobRef[1]/stJob:role XmpText 12 Photographer
|
||||
Xmp.xmpBJ.JobRef[2]/stJob:name XmpText 16 Wedding ceremony
|
||||
Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.1.1">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:ns="myNamespace/"
|
||||
xmlns:xmpDM="http://ns.adobe.com/xmp/1.0/DynamicMedia/"
|
||||
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
|
||||
xmlns:xapBJ="http://ns.adobe.com/xap/1.0/bj/"
|
||||
xmlns:stJob="http://ns.adobe.com/xap/1.0/sType/Job#"
|
||||
dc:format="image/jpeg">
|
||||
<dc:creator>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1) The first creator</rdf:li>
|
||||
<rdf:li rdf:parseType="Resource">
|
||||
<rdf:value>2) The second creator</rdf:value>
|
||||
<ns:role>programmer</ns:role>
|
||||
</rdf:li>
|
||||
<rdf:li>3) And another one</rdf:li>
|
||||
</rdf:Seq>
|
||||
</dc:creator>
|
||||
<dc:description>
|
||||
<rdf:Alt>
|
||||
<rdf:li xml:lang="x-default">Hello, World</rdf:li>
|
||||
<rdf:li xml:lang="de-DE">Hallo, Welt</rdf:li>
|
||||
</rdf:Alt>
|
||||
</dc:description>
|
||||
<dc:publisher rdf:parseType="Resource">
|
||||
<rdf:value>James Bond</rdf:value>
|
||||
<ns:role>secret agent</ns:role>
|
||||
</dc:publisher>
|
||||
<xmpDM:videoFrameSize
|
||||
stDim:w="16"
|
||||
stDim:h="9"
|
||||
stDim:unit="inch"/>
|
||||
<xapBJ:JobRef>
|
||||
<rdf:Bag>
|
||||
<rdf:li
|
||||
stJob:name="Birtday party"
|
||||
stJob:role="Photographer"/>
|
||||
<rdf:li
|
||||
stJob:name="Wedding ceremony"
|
||||
stJob:role="Best man"/>
|
||||
</rdf:Bag>
|
||||
</xapBJ:JobRef>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<?xpacket end="w"?>
|
||||
|
||||
@@ -52,6 +52,10 @@ $binpath/xmpparse ${testfile} > t1 2>&1
|
||||
$binpath/xmpparse ${testfile}-new > t2 2>&1
|
||||
diff t1 t2
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# xmpsample
|
||||
$binpath/xmpsample
|
||||
|
||||
) > $results 2>&1
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user