Add XMP Tag in Bag without overwriting old Bag Element
Added by David Poelz over 4 years ago
I want to add a region Tag without overwriting the existing ones.
I found the following piece of command lines:
exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:w 1600" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:h 800" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:unit pixel" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList ''" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name Firstname Lastname" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Type Face" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:x 0.275312" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:y 0.3775" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:w 0.164375" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:h 0.28125" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:unit normalized" pic.jpg
This overwrites the first element in the RegionList Bag. Is there a way to add a new element to the RegionList Bag?
Replies (10)
RE: Add XMP Tag in Bag without overwriteing old Bag Element - Added by Robin Mills over 4 years ago
David:
I believe this is possible. Alan's our XMP/metadata engineer and can probably enlighten you. I think this command needs a bag in it:
exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList XmpBag" pic.jpgI think you have to add the XmpBag (or XmpSeq), then add the elements.
I haven't worked much in this part of the code. I thought we had a test script or a discussion in the man page about this, however I seem to be mistaken. Perhaps this was discussed in the forum. Try searching for XmpBag and XmpSeq.
If you find the solution, please share it in this topic. If you're stuck, come back and I'll investigate more deeply.
RE: Add XMP Tag in Bag without overwriteing old Bag Element - Added by David Poelz over 4 years ago
Hi Robin
thanks you you quick reply. I searched the forum ,the bug reports and the wiki for XMPBag and XMPSeq and read all resulting threads. Unfortunatly I didn't find a solution. If you could look at it again more deeply it would be great. Thanks in advance.
RE: Add XMP Tag in Bag without overwriteing old Bag Element - Added by Robin Mills over 4 years ago
I've looked a little more about this. And this seems to be working OK. Here's my script. I do have dual nationality, so I've represented that with an XmpBag:
#!/bin/bash cp test/data/exiv2-empty.jpg empty.jpg exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList ''" empty.jpg exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name Robin Mills" empty.jpg exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality Scottish" empty.jpg exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name Hoo Can Fly" empty.jpg exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Nationality Chinese" empty.jpg exiv2 -px empty.jpg ; echo ---- exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpBag Scottish" empty.jpg exiv2 -px empty.jpg ; echo ---- exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpBag American" empty.jpg exiv2 -px empty.jpg ; echo ---- exiv2 -pX empty.jpg | xmllint --format - # That's all Folks! ##And here's the output:
Xmp.mwg-rs.Regions XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList XmpText 0 type="Bag" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name XmpText 11 Robin Mills Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpText 8 Scottish Xmp.mwg-rs.Regions/mwg-rs:RegionList[2] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name XmpText 11 Hoo Can Fly Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Nationality XmpText 7 Chinese ---- Xmp.mwg-rs.Regions XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList XmpText 0 type="Bag" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name XmpText 11 Robin Mills Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpBag 1 Scottish Xmp.mwg-rs.Regions/mwg-rs:RegionList[2] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name XmpText 11 Hoo Can Fly Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Nationality XmpText 7 Chinese ---- Xmp.mwg-rs.Regions XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList XmpText 0 type="Bag" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name XmpText 11 Robin Mills Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpBag 2 Scottish, American Xmp.mwg-rs.Regions/mwg-rs:RegionList[2] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name XmpText 11 Hoo Can Fly Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Nationality XmpText 7 Chinese ---- <?xml version="1.0"?> <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description xmlns:mwg-rs="http://www.metadataworkinggroup.com/schemas/regions/" rdf:about=""> <mwg-rs:Regions rdf:parseType="Resource"> <mwg-rs:RegionList> <rdf:Bag> <rdf:li> <rdf:Description mwg-rs:Name="Robin Mills"> <mwg-rs:Nationality> <rdf:Bag> <rdf:li>Scottish</rdf:li> <rdf:li>American</rdf:li> </rdf:Bag> </mwg-rs:Nationality> </rdf:Description> </rdf:li> <rdf:li mwg-rs:Name="Hoo Can Fly" mwg-rs:Nationality="Chinese"/> </rdf:Bag> </mwg-rs:RegionList> </mwg-rs:Regions> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="w"?>
As I've said, I'm not an XMP Engineer. Perhaps you're expecting different behaviour.
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by David Poelz over 4 years ago
I think i meant something different
Step 1: I add a Region Tag to a picture. i can use the code
exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:w 1600" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:h 800" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:AppliedToDimensions/stDim:unit pixel" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList ''" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name Firstname Lastname" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Type Face" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:x 0.275312" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:y 0.3775" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:w 0.164375" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:h 0.28125" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:unit normalized" pic.jpg
Step 2: I want to add add other element to the regionList but i need to find out if and how many elements there are already in the regionList so i can set the index [x] correctly. So i would do:
exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Name AnotherFirstname AnotherLastname" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Type Face" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Area/stArea:x 0.5" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Area/stArea:y 0.5" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Area/stArea:w 0.3" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Area/stArea:h 0.2" pic.jpg exiv2 mo -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[x]/mwg-rs:Area/stArea:unit normalized" pic.jpg
How can i find X?
Or if i stay with your example: can you add "Hoo Can Fly" without the index [2] ?
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by Robin Mills over 4 years ago
A good question (although I've given you a good answer to a different question!).
Good old grep can help you:
521 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -px empty.jpg | grep Name | grep "Hoo Can Fly" Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name XmpText 11 Hoo Can Fly 522 rmills@rmillsmbp:~/gnu/exiv2/trunk $You might need to use XSLT's count() function on the XML. Can I encourage you to take a look at the documentation for Adobe's XMPsdk. Exiv2 puts a modest veneer over Adobe's code. If Adobe provide a short hand for "the last+1", it'll probably work fine from Exiv2. For sure the syntax
[]
seems to be "the last one":532 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[]/mwg-rs:Name 'Andreas Huggel'" empty.jpg 533 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -px empty.jpg Xmp.mwg-rs.Regions XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList XmpText 0 type="Bag" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Name XmpText 11 Robin Mills Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:Nationality XmpBag 2 Scottish, American Xmp.mwg-rs.Regions/mwg-rs:RegionList[2] XmpText 0 type="Struct" Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Name XmpText 14 Andreas Huggel Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]/mwg-rs:Nationality XmpText 7 Chinese 534 rmills@rmillsmbp:~/gnu/exiv2/trunk $This has updated
Xmp.mwg-rs.Regions/mwg-rs:RegionList[2]
which has changed Hoo's name. Perhaps there is a syntax for "last + 1". I've unsuccessfully tried *
and -1
and 0
.RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by David Poelz over 4 years ago
Thank you that helps a lot. Initially i hoped that i can tell exiv2 to add the element as last+1. But now i know that I have to parse the existing xmp tags first and the enter the new data at the right position.
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by Robin Mills over 4 years ago
You're welcome. Happy Users, that's wot we want! A couple of observations:
1) The XMPsdk embedded in Exiv2 supports the syntax [last()]
, which amount to the same as []
. It doesn't support [last()+1]
2) Parsing XMPsdk output strings is non trivial. For example:
Xmp.mwg-rs.Regions/mwg-rs:RegionList[1]/mwg-rs:NameI have written a parser in
<exiv2dir>/samples/exiv2json.cpp
. It uses a recursive algorithm and I recommend a double shot of expresso before reading that code. If you discover/invent a simpler parser, I'll be happy to accept your suggestions.
My parser objectForKey()
parses the string to a Jzon object which is supported in samples/Jzon.cpp
. I'll be happy to discuss the parser if you want to use that in your application. I am willing to discuss it on Skype 'clanmills' (or FaceTime or Google Hangouts).
3) It's probably not too difficult to add syntax such as [+]
to XMPsdk to represent [last()+1]
. However, I never change the XMPsdk code that ships in Exiv2. As with the parser, I'll be happy to discuss this via Skype if you want to add this to your local sources.
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by David Poelz over 4 years ago
Thank you for your offer. I am a Java developer though and never touched C code. So I doubt that i am able to discuss you parser in any meaningfuly way :)
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by Robin Mills over 4 years ago
Oh, the Java and C++/STL languages are almost identical. The big difference is that Java runs using the JavaVM and C++ generates native code. And Java is delivered with amazing libraries. However the languages are very similar.
If you have difficulty parsing those strings, I can help you with the Java to get that done.
RE: Add XMP Tag in Bag without overwriting old Bag Element - Added by Robin Mills over 4 years ago
I've made more discoveries about this by reading the code in xmpsdk/src/XMPCore_Impl.cpp. ExpandXPath() has the following comments:
// qualName A top level property or struct field. // *[index] An element of an array. // *[last()] The last element of an array. // *[fieldName="value"] An element in an array of structs, chosen by a field value. // *[@xml:lang="value"] An element in an alt-text array, chosen by the xml:lang qualifier. // *[?qualName="value"] An element in an array, chosen by a qualifier value. // @xml:lang An xml:lang qualifier. // ?qualName A general qualifier.We can use this to add the name 'David' in
[3]
637 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[3]/mwg-rs:Name David" empty.jpg 638 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -px empty.jpg | grep David Xmp.mwg-rs.Regions/mwg-rs:RegionList[3]/mwg-rs:Name XmpText 5 David 639 rmills@rmillsmbp:~/gnu/exiv2/trunk $And I can edit you!
639 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[mwg-rs:Name='David']/mwg-rs:Name David Poelz" empty.jpg 640 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -px empty.jpg | grep David Xmp.mwg-rs.Regions/mwg-rs:RegionList[3]/mwg-rs:Name XmpText 11 David PoelzHowever, there seems to be a bug in parsing the syntax:
*[fieldName="value"]
if value has a space: 649 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -M "set Xmp.mwg-rs.Regions/mwg-rs:RegionList[mwg-rs:Name='David Poelz']/mwg-rs:Name David" empty.jpg Error: XMP Toolkit error 102: No terminating quote for array selector Error: Failed to encode XMP metadata. 650 rmills@rmillsmbp:~/gnu/exiv2/trunk $I cannot find any mention of this feature in the XMPsdk documentation:
657 rmills@rmillsmbp:~/gnu/xmpsdk/XMP-Toolkit-SDK-CC201607 $ find . -name "*.pdf" -exec ls -alt {} \; -rw-r--r--+ 1 rmills staff 211367 Aug 1 2016 ./docs/XMPAddendumProgrammersGuide.pdf -rw-r--r--+ 1 rmills staff 263041 Aug 1 2016 ./docs/XMPFilesPluginSDK.pdf -rw-r--r--+ 1 rmills staff 644034 Aug 1 2016 ./docs/XMPProgrammersGuide.pdf -rw-r--r--+ 1 rmills staff 511034 Aug 1 2016 ./docs/XMPSpecificationPart1.pdf -rw-r--r--+ 1 rmills staff 383354 Aug 1 2016 ./docs/XMPSpecificationPart2.pdf -rw-r--r--+ 1 rmills staff 823648 Aug 1 2016 ./docs/XMPSpecificationPart3.pdf -rwxr-xr-x+ 1 rmills staff 10806 Aug 1 2016 ./samples/testfiles/BlueSquare.pdf -rw-r--r--+ 1 rmills staff 163352 Aug 1 2016 ./XMP-Toolkit-SDK-Overview.pdf 658 rmills@rmillsmbp:~/gnu/xmpsdk/XMP-Toolkit-SDK-CC201607 $I couldn't find anything about this in the XMPsdk forum: https://forums.adobe.com/thread/1817442.