How do I create array structures in XMP?

Started by Archive, May 12, 2010, 08:54:42 AM

Previous topic - Next topic

Archive

[Originally posted by nibheis on 2009-12-07 08:46:29-08]

Code:
Hello all,

I have been reading the online documentation and the provided configuration file sample...
...but I cannot get my user defined XMP tags to work the way I want.

I am trying to place, within an image, information about a set of overlays related to this image.
That is, for each image I'd like to describe 0 to n overlay planes.

Here the current configuration file I have:

--------------

%Image::ExifTool::UserDefined = (
        'Image::ExifTool::XMP::Main' => {
                myNS => {
                        SubDirectory => {
                                TagTable => 'Image::ExifTool::UserDefined::myNS',
                        },
                },
        },
);

%Image::ExifTool::UserDefined::myNS = (
        GROUPS => { 0 => 'XMP', 1 => 'XMP-myNS', 2 => 'Image'},
        NAMESPACE => { 'myNS' => 'http://x.y.z/test/' },
        WRITABLE => 'string',

        overlays                        => {
                SubDirectory    => { },
                Struct          => 'overlaysStruct',
        },

        overlaysOverlay                         => { List => 1 },
        overlaysOverlayId_overlay_type          => { },
        overlaysOverlayData                     => { },
);

%Image::ExifTool::UserDefined::xmpStruct = (
        overlayStruct   => {
                NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
                id_overlay_type => { },
                data            => { },
        },

        overlaysStruct  => {
                NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
                overlay         => {
                        SubDirectory    => { },
                        Struct          => 'overlayStruct',
                        List            => 'Seq',
                },
        },
);

--------------
This allows me to set the "data" field for one overlay this way:
exiftool -XMP-myNS:OverlaysOverlayData="45" test_session_2_105_2.png

Which gives me (exiftool -XMP -b test_session_2_105_2.png):

-----

<?xpacket begin='***' id='W5M0MpCehiHzreSzNTczkc9d'?>
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 8.00'>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>

 <rdf:Description rdf:about=''
  xmlns:myNS='http://x.y.z/test/'>
  <myNS:overlays rdf:parseType='Resource'>
   <myNS:overlay>
    <rdf:Seq>
     <rdf:li rdf:parseType='Resource'>
      <myNS:data>45</myNS:data>
     </rdf:li>
    </rdf:Seq>
   </myNS:overlay>
  </myNS:overlays>
 </rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end='r'?>

------
Now the question is, how do I add a new list item?
I tried:
 - exiftool -XMP-myNS:OverlaysOverlay2Data="45" test_session_2_105_2.png
 - exiftool -XMP-myNS:OverlaysOverlay[2]Data="45" test_session_2_105_2.png
without success.

I think something is wrong with my configuration. Or did I miss something obvious?
Any hint? Please help me :)

Archive

[Originally posted by exiftool on 2009-12-07 11:44:55-08]

Using XMP structures is tricky, and I'm impressed with
how close you came.  Basically, the only thing you are missing
is the "List" flag for the flattened tags.  Also, the "overlaysOverlay"
tag is a structure too:

Code:
%Image::ExifTool::UserDefined = (
    'Image::ExifTool::XMP::Main' => {
        myNS => {
            SubDirectory => {
                TagTable => 'Image::ExifTool::UserDefined::myNS',
            },
        },
    },
);

%Image::ExifTool::UserDefined::myNS = (
    GROUPS => { 0 => 'XMP', 1 => 'XMP-myNS', 2 => 'Image'},
    NAMESPACE => { 'myNS' => 'http://x.y.z/test/' },
    WRITABLE => 'string',

    overlays => {
        SubDirectory    => { },
        Struct          => 'overlaysStruct',
    },

    overlaysOverlay => {
        SubDirectory    => { },
        Struct          => 'overlayStruct',
    },
    overlaysOverlayId_overlay_type => { List => 1 },
    overlaysOverlayData            => { List => 1 },
);

%Image::ExifTool::UserDefined::xmpStruct = (
    overlayStruct   => {
        NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
        id_overlay_type => { },
        data            => { },
    },

    overlaysStruct  => {
        NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
        overlay         => {
            Struct  => 'overlayStruct',
            List    => 'Seq',
        },
    },
);

With this, you can add extra items to the structure with
commands like:

Code:
exiftool -XMP-myNS:OverlaysOverlayData+="new data" out.xmp

Note that ExifTool isn't very flexible when it comes to handling structures,
and the new elements are added to the first structure in the list which
doesn't already contain the specified element.

- Phil

Archive

[Originally posted by nibheis on 2009-12-07 12:24:52-08]

Thanks a lot!

You need not to be impressed... it kind of took me a week to come with this half working solution.

Let me play with this a bit, and I'll probably have more questions Smiley

Also, thank you for providing us with such a nice tool.

Best regards.

Archive

[Originally posted by exiftool on 2009-12-07 17:26:12-08]

I took another look at your post to try to understand what you
are trying to do, and can't figure out why you would want a 2-level
structure scheme.  You can create a list of structures more simply
like this:

Code:
%Image::ExifTool::UserDefined = (
    'Image::ExifTool::XMP::Main' => {
        myNS => {
            SubDirectory => {
                TagTable => 'Image::ExifTool::UserDefined::myNS',
            },
        },
    },
);

%Image::ExifTool::UserDefined::myNS = (
    GROUPS => { 0 => 'XMP', 1 => 'XMP-myNS', 2 => 'Image'},
    NAMESPACE => { 'myNS' => 'http://x.y.z/test/' },
    WRITABLE => 'string',

    overlays => {
        SubDirectory    => { },
        Struct          => 'overlayStruct',
        List            => 'Seq',
    },
    overlaysId_overlay_type => { List => 1 },
    overlaysData            => { List => 1 },
);

%Image::ExifTool::UserDefined::xmpStruct = (
    overlayStruct   => {
        NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
        id_overlay_type => { },
        data            => { },
    },
);

Code:
> exiftool -overlaysId_overlay_type+="type A" -OverlaysData+="data A" a.xmp
    1 image files created

> exiftool -overlaysId_overlay_type+="type B" -OverlaysData+="data B" a.xmp
    1 image files updated

> cat a.xmp
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 8.01'>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>

 <rdf:Description rdf:about=''
  xmlns:myNS='http://x.y.z/test/'>
  <myNS:overlays>
   <rdf:Seq>
    <rdf:li rdf:parseType='Resource'>
     <myNS:data>data A</myNS:data>
     <myNS:id_overlay_type>type A</myNS:id_overlay_type>
    </rdf:li>
    <rdf:li rdf:parseType='Resource'>
     <myNS:data>data B</myNS:data>
     <myNS:id_overlay_type>type B</myNS:id_overlay_type>
    </rdf:li>
   </rdf:Seq>
  </myNS:overlays>
 </rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end='w'?>

(note that I had to remove the unprintable character in the
quotes of the xpacket "begin" for the forum to
accept my post.)

- Phil

Archive

[Originally posted by nibheis on 2009-12-08 06:27:02-08]

That is just great Smiley

You are right, I do not need a 2-level structure scheme.

I guess I introduced the 2nd level while I was trying some wild things...

Now, I come up with some questions regarding the array handling from the cmd line:

- from your example: it is not possible to add 'data B' in a new item unless 'dataA' was entered, and that's a current limitation. The only solution is to add a fake 'dataA', is this it?

- If I add to remove the typeA/DataA entry after typeB/DataB was entered.. I need to export the data first, remove it from the XMP, then re-add typeB/DataB only. Is there no simpler way of doing it?

- The only way to read the sequentially the data in this list is to do a structured export of the data and parse it, is that right?

I am ok with all this, no pb, but if this can be done in a more comfortable way, please let me know.

Maybe I'll try to document a bit (configuration, and command line examples) to ease the (relative) pain for the next person trying to use arrays in XMP. How can I help?

Thank you for your time, Sir!

Archive

[Originally posted by exiftool on 2009-12-08 13:05:26-08]

Code:
"from your example: it is not possible to add 'data B' in a new item unless 'dataA' was
entered, and that's a current limitation. The only solution is to add a fake 'dataA', is this it?"

Yes.

Code:
"If I add to remove the typeA/DataA entry after typeB/DataB was entered.. I need to
export the data first, remove it from the XMP, then re-add typeB/DataB only. Is there no simpler
way of doing it?"

You can remove any specific value like this:

Code:
exiftool -overlaysdata-="data A"

which may or may not help you out.

Code:
"The only way to read the sequentially the data in this list is to do a structured export
of the data and parse it, is that right?"

I'm not sure what you mean by reading sequentially.  Currently there are
2 ways to get structured output of XMP information:

Code:
1)  -b -xmp
2)  -json -struct

It has been on my list for quite a while to properly implement support
of XMP structures, but I haven't yet done this.  A large part of the problem
is that I haven't figured out a good way to enter structured information
on the command line.

- Phil

Phil Harvey

#6
Although the config file shown in the previous post will should still work, the definition of user-defined structures has been simplified as of ExifTool version 8.46.  The corresponding config file now looks like this:

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::XMP::Main' => {
        myNS => {
            SubDirectory => {
                TagTable => 'Image::ExifTool::UserDefined::myNS',
            },
        },
    },
);

%Image::ExifTool::UserDefined::myNS = (
    GROUPS => { 0 => 'XMP', 1 => 'XMP-myNS', 2 => 'Image'},
    NAMESPACE => { 'myNS' => 'http://x.y.z/test/' },
    WRITABLE => 'string',

    overlays => {
        Struct          => {
            NAMESPACE       => { 'myNS' => 'http://x.y.z/test/' },
            id_overlay_type => { },
            data            => { },
        },
        List            => 'Seq',
    },
);

1; # end


See the config file documentation for details.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).