Added type keyword to XmpTextValue, added test with a command file that generates the same XMP packet as xmpsample.

This commit is contained in:
Andreas Huggel 2007-10-16 15:57:27 +00:00
parent 7c2e5a705a
commit f51e7e0512
7 changed files with 249 additions and 26 deletions

View File

@ -20,7 +20,9 @@ try {
xmpData["Xmp.dc.source"] = "xmpsample.cpp"; // a simple text value
xmpData["Xmp.dc.subject"] = "Palmtree"; // an array item
xmpData["Xmp.dc.subject"] = "Rubbertree"; // add a 2nd array item
xmpData["Xmp.dc.title"] = "lang=en-US Beach"; // a language alternative
// a language alternative with two entries and without default
xmpData["Xmp.dc.title"] = "lang=de-DE Sonnenuntergang am Strand";
xmpData["Xmp.dc.title"] = "lang=en-US Sunset on the beach";
// -------------------------------------------------------------------------
// Any properties can be set provided the namespace is known. Values of any
@ -86,11 +88,9 @@ try {
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 an element with a qualifier (using the namespace registered above)
xmpData["Xmp.dc.publisher"] = "James Bond"; // creates an unordered array
xmpData["Xmp.dc.publisher[1]/?ns:role"] = "secret agent";
// Add a qualifer to an array element of Xmp.dc.creator (added above)
tv.read("programmer");
@ -102,7 +102,7 @@ try {
xmpData.add(Exiv2::XmpKey("Xmp.xmpBJ.JobRef"), &tv); // Set the array type.
tv.setXmpArrayType(Exiv2::XmpValue::xaNone);
tv.read("Birtday party");
tv.read("Birthday 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);

View File

@ -90,6 +90,7 @@ 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_("Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `%1', `%2', `%3'")), // %1=namespace, %2=property path, %3=value
ErrMsg( 48, N_("Invalid XmpText type `%1'")), // %1=type
// Last error message (message is not used)
ErrMsg( -2, N_("(Unknown Error)"))

View File

@ -495,7 +495,36 @@ namespace Exiv2 {
int XmpTextValue::read(const std::string& buf)
{
value_ = buf;
// support a type=Alt,Bag,Seq,Struct indicator
std::string b = buf;
std::string type;
if (buf.length() > 5 && buf.substr(0, 5) == "type=") {
std::string::size_type pos = buf.find_first_of(' ');
type = buf.substr(5, pos-5);
// Strip quotes (so you can also specify the type without quotes)
if (type[0] == '"') type = type.substr(1);
if (type[type.length()-1] == '"') type = type.substr(0, type.length()-1);
b.clear();
if (pos != std::string::npos) b = buf.substr(pos+1);
}
if (!type.empty()) {
if (type == "Alt") {
setXmpArrayType(XmpValue::xaAlt);
}
else if (type == "Bag") {
setXmpArrayType(XmpValue::xaBag);
}
else if (type == "Seq") {
setXmpArrayType(XmpValue::xaSeq);
}
else if (type == "Struct") {
setXmpStruct();
}
else {
throw Error(48, type);
}
}
value_ = b;
return 0;
}
@ -516,6 +545,24 @@ namespace Exiv2 {
std::ostream& XmpTextValue::write(std::ostream& os) const
{
bool del = false;
if (xmpArrayType() != XmpValue::xaNone) {
switch (xmpArrayType()) {
case XmpValue::xaAlt: os << "type=\"Alt\""; break;
case XmpValue::xaBag: os << "type=\"Bag\""; break;
case XmpValue::xaSeq: os << "type=\"Seq\""; break;
case XmpValue::xaNone: break; // just to suppress the warning
}
del = true;
}
else if (xmpStruct() != XmpValue::xsNone) {
switch (xmpStruct()) {
case XmpValue::xsStruct: os << "type=\"Struct\""; break;
case XmpValue::xsNone: break; // just to suppress the warning
}
del = true;
}
if (del && !value_.empty()) os << " ";
return os << value_;
}

View File

@ -716,6 +716,21 @@ namespace Exiv2 {
//! @name Manipulators
//@{
/*!
@brief Read a simple property value from \em buf to set the value.
Sets the value to the contents of \em buf. A optional keyword,
\em type is supported to set the XMP value type. This is useful for
complex value types for which Exiv2 does not have direct support.
The format of \em buf is:
<BR>
<CODE>[type=["]Alt|Bag|Seq|Struct["] ]text</CODE>
<BR>
@return 0 if successful.
*/
virtual int read(const std::string& buf);
//@}

82
test/data/cmdxmp.txt Normal file
View File

@ -0,0 +1,82 @@
# Sample Exiv2 command file for XMP tags
# --------------------------------------
# Set basic properties. Exiv2 uses the value type of the XMP specification
# for the property, if it is not specified. The default XMP value type
# for unknown properties is a simple text value.
# A simple text property.
set Xmp.dc.source xmpsample.cpp
# An array item (unordered array).
set Xmp.dc.subject "Palmtree"
# Add a 2nd array item
set Xmp.dc.subject "Rubbertree"
# A language alternative (without a default)
set Xmp.dc.title lang=en-US Sunset on the beach
set Xmp.dc.title lang=de-DE Sonnenuntergang am Strand
# Any properties can be set provided the namespace is known.
set Xmp.dc.one -1
set Xmp.dc.two 3.1415
set Xmp.dc.three 5/7
set Xmp.dc.four 255
set Xmp.dc.five 256
set Xmp.dc.six false
set Xmp.dc.seven Seven
# The value type can be specified. Exiv2 has support for a limited number
# of specific XMP types with built-in types: The basic XmpText, array
# types XmpAlt (alternative array), XmpBag (unordered array), XmpSeq
# (ordered array) and language alternatives LangAlt.
# Simple text property with explicitly specified value type
set Xmp.dc.format XmpText "image/jpeg"
# An ordered array
set Xmp.dc.creator XmpSeq "1) The first creator"
set Xmp.dc.creator "2) The second creator"
set Xmp.dc.creator "3) And another one"
# A language alternative. The default entry of a langauge alternative
# doesn't need a language qualifier.
set Xmp.dc.description LangAlt lang=de-DE Hallo, Welt
set Xmp.dc.description LangAlt Hello, World
# According to the XMP specification, Xmp.tiff.ImageDescription is an
# alias for Xmp.dc.description. Exiv2 treats an alias just like any
# other property.
set Xmp.tiff.ImageDescription TIFF image description
set Xmp.tiff.ImageDescription lang=de-DE TIFF Bildbeschreibung
# Register a namespace which Exiv2 doesn't know yet with a prefix.
reg ns myNamespace/
# There are no built-in Exiv2 value types for structures, qualifiers and
# nested types. However, these can be added by using an XmpText value and a
# path as the key.
# Add a structure
set Xmp.xmpDM.videoFrameSize/stDim:w 16
set Xmp.xmpDM.videoFrameSize/stDim:h 9
set Xmp.xmpDM.videoFrameSize/stDim:unit inch
# Add an element with a qualifier (using the namespace registered earlier)
set Xmp.dc.publisher James Bond
set Xmp.dc.publisher/?ns:role secret agent
# Add a qualifer to an array element of Xmp.dc.creator (added above)
set Xmp.dc.creator[2]/?ns:role programmer
# Add an array of structures. First set a text property with just the
# array type. (Note: this is not the same as creating an XmpBag property.)
set Xmp.xmpBJ.JobRef XmpText type=Bag
# Then set the array items. Each of them is a structure with two elements.
set Xmp.xmpBJ.JobRef[1]/stJob:name XmpText Birthday party
set Xmp.xmpBJ.JobRef[1]/stJob:role XmpText Photographer
set Xmp.xmpBJ.JobRef[2]/stJob:name Wedding ceremony
set Xmp.xmpBJ.JobRef[2]/stJob:role Best man

View File

@ -9,7 +9,7 @@ Xmp.xmp.ModifyDate XmpText 25 2005-09-07T15:09:51-
Xmp.xmp.MetadataDate XmpText 25 2006-04-10T13:37:10-07:00
Xmp.xmpMM.DocumentID XmpText 37 uuid:9A3B7F52214211DAB6308A7391270C13
Xmp.xmpMM.InstanceID XmpText 37 uuid:B59AC1B3214311DAB6308A7391270C13
Xmp.xmpMM.DerivedFrom XmpText 0
Xmp.xmpMM.DerivedFrom XmpText 0 type="Struct"
Xmp.xmpMM.DerivedFrom/stRef:instanceID XmpText 37 uuid:9A3B7F4F214211DAB6308A7391270C13
Xmp.xmpMM.DerivedFrom/stRef:documentID XmpText 37 uuid:9A3B7F4E214211DAB6308A7391270C13
Xmp.photoshop.ColorMode XmpText 1 3
@ -40,7 +40,7 @@ Xmp.exif.NativeDigest XmpText 414 36864,40960,40961,37
Xmp.iptc.IntellectualGenre XmpText 7 Profile
Xmp.iptc.Location XmpText 17 Moore family farm
Xmp.iptc.CountryCode XmpText 2 US
Xmp.iptc.CreatorContactInfo XmpText 0
Xmp.iptc.CreatorContactInfo XmpText 0 type="Struct"
Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrExtadr XmpText 30 Big Newspaper, 123 Main Street
Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity XmpText 6 Boston
Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrRegion XmpText 13 Massachusetts
@ -81,7 +81,7 @@ Xmp.xmp.ModifyDate XmpText 25 2005-03-13T02:01:44-
Xmp.xmp.MetadataDate XmpText 25 2007-01-08T13:25:45+01:00
Xmp.xmp.CreatorTool XmpText 26 Adobe Photoshop CS Windows
Xmp.xmpMM.DocumentID XmpText 58 adobe:docid:photoshop:0f410643-9396-11d9-bb8e-a67e6693b6e9
Xmp.xmpMM.DerivedFrom XmpText 0
Xmp.xmpMM.DerivedFrom XmpText 0 type="Struct"
Xmp.xmpMM.DerivedFrom/stRef:instanceID XmpText 41 uuid:0f410640-9396-11d9-bb8e-a67e6693b6e9
Xmp.xmpMM.DerivedFrom/stRef:documentID XmpText 58 adobe:docid:photoshop:e4d002a0-9392-11d9-bb8e-a67e6693b6e9
Xmp.xmpMM.InstanceID XmpText 41 uuid:0f410644-9396-11d9-bb8e-a67e6693b6e9
@ -148,7 +148,7 @@ Xmp.ns1.SimpleProp2 XmpText 13 Simple2 value
Xmp.ns1.SimpleProp2/?xml:lang XmpText 9 x-default
Xmp.ns1.ArrayProp1 XmpBag 2 Item1.1 value, Item1.2 value
Xmp.ns1.ArrayProp2 LangAlt 2 lang="x-one" Item2.1 value, lang="x-two" Item2.2 value
Xmp.ns1.StructProp XmpText 0
Xmp.ns1.StructProp XmpText 0 type="Struct"
Xmp.ns1.StructProp/ns2:Field1 XmpText 12 Field1 value
Xmp.ns1.StructProp/ns2:Field2 XmpText 12 Field2 value
Xmp.ns1.QualProp1 XmpText 10 Prop value
@ -156,10 +156,10 @@ Xmp.ns1.QualProp1/?ns2:Qual XmpText 10 Qual value
Xmp.ns1.QualProp2 XmpText 10 Prop value
Xmp.ns1.QualProp2/?xml:lang XmpText 9 x-default
Xmp.ns1.QualProp2/?ns2:Qual XmpText 10 Qual value
Xmp.ns1.NestedStructProp XmpText 0
Xmp.ns1.NestedStructProp/ns2:Outer XmpText 0
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle XmpText 0
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner XmpText 0
Xmp.ns1.NestedStructProp XmpText 0 type="Struct"
Xmp.ns1.NestedStructProp/ns2:Outer XmpText 0 type="Struct"
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle XmpText 0 type="Struct"
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner XmpText 0 type="Struct"
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field1 XmpText 12 Field1 value
Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field2 XmpText 12 Field2 value
-----> Encoding XMP data to write to xmpsdk.xmp-new <-----
@ -281,7 +281,7 @@ Xmp.ns1.NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field2 XmpText 12
\ No newline at end of file
Xmp.dc.source XmpText 13 xmpsample.cpp
Xmp.dc.subject XmpBag 2 Palmtree, Rubbertree
Xmp.dc.title LangAlt 1 lang="en-US" Beach
Xmp.dc.title LangAlt 2 lang="de-DE" Sonnenuntergang am Strand, lang="en-US" Sunset on the beach
Xmp.dc.one XmpText 2 -1
Xmp.dc.two XmpText 6 3.1415
Xmp.dc.three XmpText 3 5/7
@ -296,11 +296,11 @@ Xmp.tiff.ImageDescription LangAlt 2 lang="x-default" TIF
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.publisher XmpBag 1 James Bond
Xmp.dc.publisher[1]/?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 XmpText 0 type="Bag"
Xmp.xmpBJ.JobRef[1]/stJob:name XmpText 14 Birthday 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
@ -332,7 +332,8 @@ Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
</dc:subject>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="en-US">Beach</rdf:li>
<rdf:li xml:lang="de-DE">Sonnenuntergang am Strand</rdf:li>
<rdf:li xml:lang="en-US">Sunset on the beach</rdf:li>
</rdf:Alt>
</dc:title>
<dc:creator>
@ -351,9 +352,13 @@ Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
<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>
<rdf:Bag>
<rdf:li rdf:parseType="Resource">
<rdf:value>James Bond</rdf:value>
<ns:role>secret agent</ns:role>
</rdf:li>
</rdf:Bag>
</dc:publisher>
<tiff:ImageDescription>
<rdf:Alt>
@ -368,7 +373,7 @@ Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
<xapBJ:JobRef>
<rdf:Bag>
<rdf:li
stJob:name="Birtday party"
stJob:name="Birthday party"
stJob:role="Photographer"/>
<rdf:li
stJob:name="Wedding ceremony"
@ -400,3 +405,69 @@ Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man
<?xpacket end="w"?>
File 1/1: exiv2-empty.jpg
Set Xmp.dc.source "xmpsample.cpp" (XmpText)
Set Xmp.dc.subject "Palmtree" (XmpBag)
Set Xmp.dc.subject "Rubbertree" (XmpBag)
Set Xmp.dc.title "lang=en-US Sunset on the beach" (LangAlt)
Set Xmp.dc.title "lang=de-DE Sonnenuntergang am Strand" (LangAlt)
Set Xmp.dc.one "-1" (XmpText)
Set Xmp.dc.two "3.1415" (XmpText)
Set Xmp.dc.three "5/7" (XmpText)
Set Xmp.dc.four "255" (XmpText)
Set Xmp.dc.five "256" (XmpText)
Set Xmp.dc.six "false" (XmpText)
Set Xmp.dc.seven "Seven" (XmpText)
Set Xmp.dc.format "image/jpeg" (XmpText)
Set Xmp.dc.creator "1) The first creator" (XmpSeq)
Set Xmp.dc.creator "2) The second creator" (XmpSeq)
Set Xmp.dc.creator "3) And another one" (XmpSeq)
Set Xmp.dc.description "lang=de-DE Hallo, Welt" (LangAlt)
Set Xmp.dc.description "Hello, World" (LangAlt)
Set Xmp.tiff.ImageDescription "TIFF image description" (LangAlt)
Set Xmp.tiff.ImageDescription "lang=de-DE TIFF Bildbeschreibung" (LangAlt)
Reg ns="myNamespace/"
Set Xmp.xmpDM.videoFrameSize/stDim:w "16" (XmpText)
Set Xmp.xmpDM.videoFrameSize/stDim:h "9" (XmpText)
Set Xmp.xmpDM.videoFrameSize/stDim:unit "inch" (XmpText)
Set Xmp.dc.publisher "James Bond" (XmpBag)
Set Xmp.dc.publisher/?ns:role "secret agent" (XmpText)
Set Xmp.dc.creator[2]/?ns:role "programmer" (XmpText)
Set Xmp.xmpBJ.JobRef "type=Bag" (XmpText)
Set Xmp.xmpBJ.JobRef[1]/stJob:name "Birthday party" (XmpText)
Set Xmp.xmpBJ.JobRef[1]/stJob:role "Photographer" (XmpText)
Set Xmp.xmpBJ.JobRef[2]/stJob:name "Wedding ceremony" (XmpText)
Set Xmp.xmpBJ.JobRef[2]/stJob:role "Best man" (XmpText)
File 1/1: exiv2-empty.jpg
Xmp.dc.source XmpText 13 xmpsample.cpp
Xmp.dc.one XmpText 2 -1
Xmp.dc.two XmpText 6 3.1415
Xmp.dc.three XmpText 3 5/7
Xmp.dc.four XmpText 3 255
Xmp.dc.five XmpText 3 256
Xmp.dc.six XmpText 5 false
Xmp.dc.seven XmpText 5 Seven
Xmp.dc.format XmpText 10 image/jpeg
Xmp.dc.subject XmpBag 2 Palmtree, Rubbertree
Xmp.dc.title LangAlt 2 lang="de-DE" Sonnenuntergang am Strand, lang="en-US" Sunset on the beach
Xmp.dc.creator XmpText 0 type="Seq"
Xmp.dc.creator[1] XmpText 20 1) The first creator
Xmp.dc.creator[2] XmpText 21 2) The second creator
Xmp.dc.creator[2]/?ns:role XmpText 10 programmer
Xmp.dc.creator[3] XmpText 18 3) And another one
Xmp.dc.description LangAlt 2 lang="x-default" Hello, World, lang="de-DE" Hallo, Welt
Xmp.dc.publisher XmpText 0 type="Bag"
Xmp.dc.publisher/?ns:role XmpText 12 secret agent
Xmp.dc.publisher[1] XmpText 10 James Bond
Xmp.tiff.ImageDescription LangAlt 2 lang="x-default" TIFF image description, lang="de-DE" TIFF Bildbeschreibung
Xmp.xmpDM.videoFrameSize XmpText 0 type="Struct"
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.xmpBJ.JobRef XmpText 0 type="Bag"
Xmp.xmpBJ.JobRef[1] XmpText 0 type="Struct"
Xmp.xmpBJ.JobRef[1]/stJob:name XmpText 14 Birthday party
Xmp.xmpBJ.JobRef[1]/stJob:role XmpText 12 Photographer
Xmp.xmpBJ.JobRef[2] XmpText 0 type="Struct"
Xmp.xmpBJ.JobRef[2]/stJob:name XmpText 16 Wedding ceremony
Xmp.xmpBJ.JobRef[2]/stJob:role XmpText 8 Best man

View File

@ -24,6 +24,7 @@ fi
# Main routine
(
binpath="$VALGRIND ../../samples"
exiv2="$VALGRIND ../../src/exiv2"
cd ./tmp
# ----------------------------------------------------------------------
@ -54,6 +55,12 @@ diff t1 t2
# xmpsample
$binpath/xmpsample
# ----------------------------------------------------------------------
# XMP sample commands
cp -f ../data/exiv2-empty.jpg .
$exiv2 -v -m ../data/cmdxmp.txt exiv2-empty.jpg
$exiv2 -v -px exiv2-empty.jpg
) > $results 2>&1
# ----------------------------------------------------------------------