"User Field Definitions"

Started by EzraButler, July 10, 2019, 07:30:07 AM

Previous topic - Next topic

EzraButler

Hi,

I was able to create 16 user-defined IPTC tags, and the data shows up when I exiftool filename. But I'm trying to mimic the workflow of MediaPro, which allows users to add additional metadata to those tag names. I'm not sure why, but without that additional metadata, the DAM is unable to read those fields.

When I look at the XML from MediaPro, I see that they have two different things.

<!ELEMENT UserFields (UserField_1?, UserField_2?, UserField_3?, UserField_4?, UserField_5?, UserField_6?,
UserField_7?, UserField_8?, UserField_9?, UserField_10?, UserField_11?, UserField_12?, UserField_13?,
UserField_14?, UserField_15?, UserField_16?)>
<!ELEMENT UserField_1 (#PCDATA)>
<!ELEMENT UserField_2 (#PCDATA)>
<!ELEMENT UserField_3 (#PCDATA)>
<!ELEMENT UserField_4 (#PCDATA)>
<!ELEMENT UserField_5 (#PCDATA)>
<!ELEMENT UserField_6 (#PCDATA)>
<!ELEMENT UserField_7 (#PCDATA)>
<!ELEMENT UserField_8 (#PCDATA)>
<!ELEMENT UserField_9 (#PCDATA)>
<!ELEMENT UserField_10 (#PCDATA)>
<!ELEMENT UserField_11 (#PCDATA)>
<!ELEMENT UserField_12 (#PCDATA)>
<!ELEMENT UserField_13 (#PCDATA)>
<!ELEMENT UserField_14 (#PCDATA)>
<!ELEMENT UserField_15 (#PCDATA)>
<!ELEMENT UserField_16 (#PCDATA)>
and

<CatalogType>
<Catalog pathType = "MAC">Test</Catalog>
<UserFieldList>
<UserFieldDefinition>Asset State</UserFieldDefinition>
<UserFieldDefinition>Original Filename</UserFieldDefinition>
<UserFieldDefinition>IsOuttake</UserFieldDefinition>
<UserFieldDefinition>Cover Display Date</UserFieldDefinition>
<UserFieldDefinition>issue date</UserFieldDefinition>
<UserFieldDefinition>Article Page Number</UserFieldDefinition>
<UserFieldDefinition>color</UserFieldDefinition>
<UserFieldDefinition>format</UserFieldDefinition>
<UserFieldDefinition>storage number</UserFieldDefinition>
<UserFieldDefinition>item number</UserFieldDefinition>
<UserFieldDefinition>condition</UserFieldDefinition>
<UserFieldDefinition>original size</UserFieldDefinition>
<UserFieldDefinition>Third Parties</UserFieldDefinition>
<UserFieldDefinition>Is Published</UserFieldDefinition>
<UserFieldDefinition>Caption</UserFieldDefinition>
</UserFieldList>
<MediaItemList>
<MediaItem>
in the beginning of their catalog type.


%Image::ExifTool::UserDefined = (
'Image::ExifTool::IPTC::ApplicationRecord' => {
        # IPTC:NewIPTCTag
        203 => {
            Name => 'UserField_1',
            Format => 'string[0,24]',
        },

        204 => {
            Name => 'UserField_2',
            Format => 'string[0,24]',
        },
       
205 => {
            Name => 'UserField_3',
            Format => 'string[0,16]',
        },


Is there any way to append these User Field Definitions to the files? Or am I doing something wrong by treating this as a directory and not a catalog?

Thank you,
Ezra





Phil Harvey

Hi Ezra,

I'm a bit lost.  I don't understand what you are trying to do.  Can you give a specific example?

- 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 ($).

EzraButler

Hi Phil,
Thank you for the quick reply!

I have a CSV of data that I want to put in the exif data of 10k+ images so a friend could upload those images into their company's DAM.

The company uses 16 user defined fields as additional meta data for their images, which I have added as well.

I successfully used exiftool to modify the exif data in a test of 10 images via CSV, including data from 5 of the user defined fields.

When I sent him the files, he told me that their DAM does not recognize the data in the user defined fields that I created. When I went through the XML data he provided of a typical collection that he uploads to their DAM (after updating the exif data in MediaPro), I noticed that the XML contains the defined "Userfield_1" custom field set up, as well as a "user field definition" describing what the userfield contained.

That is the only difference I can figure out between the result of my exiftool export and the files that he usually exports through MediaPro.

So, I'm trying to figure out if there is another "user field definition" field in the exif data or if there is a way to create catalog metadata with the definitions accompanying the files.

(I'm very new to the world of exif data and image catalogs/collections, and am just trying to help a friend not have to manually update the exif data on 10k+ files.)

As you can see in the attachments -- some data is in the exiftool result that is not in the MediaPro result.

Ezra

EzraButler

Hi Phil,

I found my basic mistake. They use XMP user fields, and I was creating IPTC user fields. I now just have to figure out how to do those.
Sorry for the bother!

Ezra

EzraButler

Ok, after much research, I finally found the correct question to ask.

mediapro has an XMP tag of UserFields.
Therefore, I just want to add the tags to the config file.

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::XMP::mediapro' => {
   UserFields => { Name => 'Asset State' },
   UserFields => { Name => 'Original Filename' },
   UserFields => { Name => 'IsOuttake' },
   UserFields => { Name => 'Cover Display Date' },
   UserFields => { Name => 'issue date' },
   UserFields => { Name => 'Article Page Number' },
   UserFields => { Name => 'color' },
   UserFields => { Name => 'format' },
   UserFields => { Name => 'storage number' },
   UserFields => { Name => 'item number' },
   UserFields => { Name => 'condition' },
   UserFields => { Name => 'original size' },
   UserFields => { Name => 'Third Parties' },
   UserFields => { Name => 'Is Published' },
   UserFields => { Name => 'Caption' },

    },
);

1;


And my goal is to have this as the result:
---- XMP-mediapro ----
User Fields         : Asset State=Hi-Res Retouched, Original Filename=a22652.tif, IsOuttake=false, Cover Display Date=April 15, 2019, issue date=2019-04-15, Third Parties=Pixels, Is Published=false, Caption="Weird. It says we'll all die this year."


I know that something is wrong about my config file, but I'm just not sure what the correct syntax is for each field.

Thank you again, and sorry to be a bother.

StarGeek

I could be wrong, but I don't think you need to make a new config file.  Exiftool can already create MediaPro UserFields.

According to the XMP Tag page on MediaPro, Userfields is a list type tag.  So to create your example output, your command would be something like

exiftool -Userfields="Asset State=Hi-Res Retouched" -Userfields="Original Filename=a22652.tif" -Userfields="IsOuttake=false" -Userfields="Cover Display Date=April 15, 2019" -Userfields="issue date=2019-04-15" -Userfields="Third Parties=Pixels" -Userfields="Is Published=false" -Userfields=Caption="Weird. It says we'll all die this year."" FileOrDir

That would set all the Userfields and overwrite any previously existing data.  Change to -Userfields+= to add without overwriting.  See FAQ #17 for more info on list type tags.



* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

EzraButler

Thank you StarGeek. This is extremely helpful.

What would the headers of the CSV be in this case? Is there a way to apply those fields to the entire column?

Userfields+= "IsOuttake" and Userfields= IsOuttake don't work, and I would rather not have to modify every cell of the sheet by appending the tag name with "IsOuttake=false".

The command line that I'm using right now is exiftool -csv=test.csv -sep ", " . and it works perfectly for all other Exif data (besides for these. Is there a way to leave the column headers as "IsOuttake" and then apply the Userfields tag to all those columns in the command line?

Thank you again.

StarGeek

Unfortunately, since Userfields is a single tag, even though MediaPro doesn't display it as such, the column would be simply Userfields and the contents of the column would be all the data you listed, using the -sep ", " option as you have listed.

I do have an idea to work around it, I'll see if I can work it out.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

#8
Ok, here's a config file that you can expand upon for each of your UserFields.  There is still some work that you will need to do

First of all, you probably have to change the CSV header names a bit.  A tag name can't have a space in it.  For example, "Original Filename" would have to be changed to OriginalFilename in the CSV header.

To add a new UserField tag, you would copy the section between the dash lines.  Then rename the tag name on the first line.  Going with the example of "Original Filename", IsOuttake => { would become OriginalFilename => { (no spaces here).

Then you have to change the three lines marked with "Change This".  Change the "IsOuttake" in those lines to the name of the new UserField.  You do want to include the spaces in these changes.  Continuing the "Original Filename" example, these lines would become
'XMP-mediapro:UserFields' => q {return "Original Filename=$val";},
my @Filtered = grep {m/^Original Filename=/ } @HSList;
@Filtered = map {s/^Original Filename=// ; $_} @Filtered ;


It is very important to remember that if you assign values using these, you have to treat them as if directly assigning values UserFields and you have to obey all the rules for list type tags as laid out in FAQ #17.  For example, if you already have other UserFields set and run the command
exiftool -config UserFields.config -OriginalFilename=Image.tif FILE
Then all previous UserFields values will be overwritten and all that is left will be "Original Filename=Image.tif" The correct way to add that without overwriting would be -OriginalFilename+=Image.tif

# Config file to write values to MediaPro Userfields, format it as FIELD=VALUE tag pairs, and treate
# each item as an individual tag.
#
# These tag names MUST be treated carefully and as if they were being added to a List type tag
# as described in exiftool FAQ #17 <https://exiftool.org/faq.html#Q17>
# If you simply assign a value, such as -IsOuttake=True, then this value will OVERWRITE
# all previous Userfields values.
#
# Requires exiftool ver 10.13 or earlier, or 10.98 or later

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
#---------------------------
IsOuttake => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "IsOuttake=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^IsOuttake=/ } @HSList; # Change This
@Filtered = map {s/^IsOuttake=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},
#---------------------------
########
},
);

#------------------------------------------------------------------------------
1;  #end


Edit: Oops, forgot to comment out the dash lines
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

EzraButler

You are incredible! Thank you so very much. This works almost perfectly!

One last question: Why is the "Cover Display Date" which should be formatted as "March 25, 2019" returning Cover Display Date=ARRAY(0x7f9699156c10)? Shouldn't it be treating it like any other string?

Thank you again!!

Ezra

StarGeek

Yeah, something is wrong there.  I based this on a tag I created for another purpose and had a similar error, but I thought I fixed it.

Can you post the config file you used?
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

Oops, forgot to comment out the dash lines.  Edited previous post.

Here's what I made for CoverDisplayDate and it seemed to work.
#---------------------------
CoverDisplayDate => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Cover Display Date=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Cover Display Date=/ } @HSList; # Change This
@Filtered = map {s/^Cover Display Date=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},
#---------------------------


* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

EzraButler

Something is not working with that. :-/

Here is the relevant output:
(A few of the other files have a similar problem with the caption, as well.) Is there some sort of limit on content type I'm not seeing here?

Thank you again and sorry for the annoyance.


---- XMP-mediapro ----
User Fields                     : Asset State=Hi-Res Retouched, Caption="Five-second rule!", Cover Display Date=ARRAY(0x7fcd5c15fbd8), IsOuttake=FALSE, Is Published=FALSE, issue date=2019-03-25, Third Parties=Pixels

---- Composite ----
Asset State                     : Hi-Res Retouched
Caption                         : "Five-second rule!"
Cover Display Date              : ARRAY(0x7fcd5c15fbd8)
Image Size                      : 4928x4286
Is Outtake                      : FALSE
Is Published                    : FALSE
Issue Date                      : 2019-03-25
Megapixels                      : 21.1
Third Parties                   : Pixels


and here is my config file:

# Config file to write values to MediaPro Userfields, format it as FIELD=VALUE tag pairs, and treat
# each item as an individual tag.
#
# These tag names MUST be treated carefully and as if they were being added to a List type tag
# as described in exiftool FAQ #17 <https://exiftool.org/faq.html#Q17>
# If you simply assign a value, such as -IsOuttake=True, then this value will OVERWRITE
# all previous Userfields values.
#
# Requires exiftool ver 10.13 or earlier, or 10.98 or later

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
AssetState => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Asset State=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Asset State=/ } @HSList; # Change This
@Filtered = map {s/^Asset State=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

OriginalFilename => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Original Filename =$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Original Filename=/ } @HSList; # Change This
@Filtered = map {s/^Original Filename=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},


IsOuttake => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "IsOuttake=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^IsOuttake=/ } @HSList; # Change This
@Filtered = map {s/^IsOuttake=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

CoverDisplayDate => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Cover Display Date=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Cover Display Date=/ } @HSList; # Change This
@Filtered = map {s/^Cover Display Date=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

IssueDate => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "issue date=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^issue date=/ } @HSList; # Change This
@Filtered = map {s/^issue date=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

ArticlePageNumber => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Article Page Number=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Article Page Number=/ } @HSList; # Change This
@Filtered = map {s/^Article Page Number=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

Color => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "color=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^color=/ } @HSList; # Change This
@Filtered = map {s/^color=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

Format => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "format=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^format=/ } @HSList; # Change This
@Filtered = map {s/^format=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

StorageNumber => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "storage number=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^storage number=/ } @HSList; # Change This
@Filtered = map {s/^storage number=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

ItemNumber => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "item number=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^item number=/ } @HSList; # Change This
@Filtered = map {s/^item number=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

Condition => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "condition=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^condition=/ } @HSList; # Change This
@Filtered = map {s/^condition=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

OriginalSize => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "original size=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^original size=/ } @HSList; # Change This
@Filtered = map {s/^original size=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

ThirdParties => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Third Parties=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Third Parties=/ } @HSList; # Change This
@Filtered = map {s/^Third Parties=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

IsPublished => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Is Published=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Is Published=/ } @HSList; # Change This
@Filtered = map {s/^Is Published=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},

Caption => {
Require => 'XMP-mediapro:UserFields',
Writable => 1,
List => 'Bag',
WriteAlso => {
'XMP-mediapro:UserFields' => q {return "Caption=$val";}, # Change This
},
ValueConv => q{
my @HSList = ref $val[0] eq 'ARRAY' ? @{$val[0]} : (defined $val[0] ?( $val[0] ):());
my @Filtered = grep {m/^Caption=/ } @HSList; # Change This
@Filtered = map {s/^Caption=// ; $_} @Filtered ; # Change This
return @Filtered ? \@Filtered :undef;
},
},
########
},
);

#------------------------------------------------------------------------------
1;  #end

StarGeek

I can't seem to replicate the problem here.  I copy/pasted your config into a new file, tried to set and read some values, set UserFields to your example value and listed all the tags.   The CoverDisplayDate writes and reads correctly.

What version of exiftool are you using?
What is your exact command?
If you are using a csv file, can you share that?

Now, there is possible problems because some of your tag names are the same as already existing tag names, XMP-acdsee:CaptionXMP-pmi:ColorXMP-getty:OriginalFileNameXMP-prism:CoverDisplayDate,  and XMP-dc:Format. But the only effect there seemed to be that it would write to both the tag and the UserFields.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

EzraButler

I use exiftool -csv=test.csv -sep ", " . and the CSV is attached.
I installed exiftool a few weeks ago, the line at the bottom of the man page says "perl v5.18.4"