Project

General

Profile

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.jpg
I 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:Name
I 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 Poelz
However, 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.

    (1-10/10)