How to return the tag name AND the tag value in a user-defined composite tag?

Started by CWCorrea, September 01, 2021, 04:29:43 AM

Previous topic - Next topic

CWCorrea

Hello Phil and forum members.

I'm looking for a way to return the tag name AND the tag value in a user-defined composite tag, where many tags are "desired" and the user-defined tag returns the name and the value of one of the tags after applying some logic (for example: return the tag with the lower value, or return the first non-empty tag of the desired tag list).

I've been exploring the GetTagName function, but it seems to me that I don't have enough Perl knowledge to apply it in a user-defined tag context.

I have read the Image::ExifTool Perl Library Module documentation and also I've been searching the forum and the config files in the forum for a clue on how to implement this, but I can only find examples of the API usage context.

I would appreciate any help to implement this. Thanks!

Christian W.




Below I have a couple of examples of how I would like to use this:

1. This composite tag returns the earliest date. In its current implementation is not possible to know which tag contains the earliest date.


    EarliestDate => {
        Desire => {
            0 => 'DateTimeOriginal',
            1 => 'CreateDate',
            2 => 'ModifyDate',
            3 => 'FileModifyDate',
        },
            ValueConv => q{
                my $earliest = '9';
                foreach (@val) {
                    next if (not defined ($_));
                    $earliest = $_ if $earliest gt $_ and $_ gt "1970:01:01";
                }
                return $earliest;
            },
    },


Let's say that a file has two dates: "CreateDate" and "FileModifyDate"

CreateDate             : 2014:10:31 13:15:35
FileModifyDate         : 2014:11:17 11:12:47-05:00

The current "EarliestDate" user-defined tag will return the earliest date like this:

EarliestDate             : 2014:10:31 13:15:35

I would like EarliestDate to return this:

EarliestDate             : [CreateDate] 2014:10:31 13:15:35




2. This composite tag returns the first defined and non-empty tag.


    FirstDefinedTag => {
        Desire => {
              0 => 'Tag0',
              1 => 'Tag1',
              2 => 'Tag2',
              3 => 'Tag3',
              4 => 'Tag4',
              5 => 'Tag5',
        },
        ValueConv => q{
            for my $tag (@val) {
                if (defined ($tag)) {
                    next if ( $tag eq '' );
                    return $tag;
                }
            }
        },
    },


Let's say that a file has the "Tag4" defined with value "XYZ"

Tag4                 : XYZ

The current "FirstDefinedTag" user-defined tag will return this:

FirstDefinedTag      : XYZ

I would like FirstDefinedTag to return this:

FirstDefinedTag      : [Tag4] XYZ


StarGeek

I do not believe there is a way to get the tag name directly like that, though Phil would have to comment and verify.  He's AFK for a few weeks, though.

The only way I can think of to do this would be to hard code a list of the tags and lookup off of that.  You also have to change foreach into a for loop in order to get the index number.

As an example.  I have not tested this out so there might still be a syntax error.
EarliestDate => {
Desire => {
0 => 'DateTimeOriginal',
1 => 'CreateDate',
2 => 'ModifyDate',
3 => 'FileModifyDate',
},
ValueConv => q{
my $tagnameArr = ('DateTimeOriginal','CreateDate','ModifyDate','FileModifyDate');
my $earliest = '9';
my $earliestTagName;
for my $i (0 .. $#val) {
next if (not defined ($val[$i]));
if ($earliest gt $val[$i] and $val[$i] gt "1970:01:01") {
$earliest = $val[$i];
$earliestTagName = $tagnameArr[$i];
}
}
return '['.$earliestTagName.'] '.$earliest;
},
},

* 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).

CWCorrea

Hello StarGeek.

Thank you for your prompt answer. I like your idea of hard coding the list of tags for lookup. It implies some maintenance tasks when the user-defined tag is modified, but it is a good starting point.

I only had to change the array definition to:


my @tagnameArr = ('DateTimeOriginal','CreateDate','ModifyDate','FileModifyDate');


I will continue exploring the way to use the GetTagName function (and learning more Perl), as I believe the Image::ExifTool Perl Library Module will give me more flexibility in the future. In the meantime, the hard-coded array of tags is a good solution for my needs.

Thanks again!

Christian W.

CWCorrea

Hello Phil,

I'd appreciate your suggestions on how to return the tag name AND the tag value in a user-defined composite tag, where many tags are "desired" and the user-defined tag returns the name and the value of one of the tags after applying some logic (for example: return the tag with the lower value, or return the first non-empty tag of the desired tag list).

For a couple of years I have been using StarGeek's suggestion of hard coding the list of tags in an array for tag name lookup, but doing this requires editing the array of tags each time the "desired" tag list is changed. I hope there is a better way to do this without hard coding the list of tags.

Following is an example of a composite tag to return the earliest date in a list of tags using a hardcoded list of tags:

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        EarliestDate => {
            Desire => {
                0 => 'DateTimeOriginal',
                1 => 'CreateDate',
                2 => 'ModifyDate',
                3 => 'FileModifyDate',
            },
                ValueConv => q{
                    my $earliest = '9';
                    my @tagnameArr = ('DateTimeOriginal','CreateDate','ModifyDate','FileModifyDate');
                    my $earliestTagName;
                    for my $i (0 .. $#val) {
                        next if (not defined ($val[$i]));
                        if ($earliest gt $val[$i] and $val[$i] gt "1970:01:01") {
                            $earliest = $val[$i];
                            $earliestTagName = $tagnameArr[$i];
                        }
                    }
                    return '['.$earliestTagName.'] '.$earliest;
                },
        },
    },
);

Let's say that a file has two dates: "CreateDate" and "FileModifyDate"

CreateDate             : 2014:10:31 13:15:35
FileModifyDate         : 2014:11:17 11:12:47-05:00

The EarliestDate tag returns this:

EarliestDate           : [CreateDate] 2014:10:31 13:15:35

I appreciate your comments on this. Thank you.

Christian W.

Phil Harvey

You could do this:

%Image::ExifTool::myTagList = (
    0 => 'DateTimeOriginal',
    1 => 'CreateDate',
    2 => 'ModifyDate',
    3 => 'FileModifyDate',
);

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        EarliestDate => {
            Desire => \%Image::ExifTool::myTagList,
            ValueConv => q{
                my $earliest = '9';
                my $earliestTagName;
                for my $i (0 .. $#val) {
                    next if (not defined ($val[$i]));
                    if ($earliest gt $val[$i] and $val[$i] gt "1970:01:01") {
                        $earliest = $val[$i];
                        $earliestTagName = $Image::ExifTool::myTagList{$i};
                    }
                }
                return '['.$earliestTagName.'] '.$earliest;
            },
        },
    },
);
1;

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

CWCorrea