GetNewValue (for Keyword) intermittently returns List and String

Started by cburkins, August 19, 2018, 05:52:35 PM

Previous topic - Next topic

cburkins

Long-time user of perl API for exiftool.  Just great job Phil, very much appreciate your hard work !

I principally use exiftool to manipulate keywords, and just started using GetNewValue to query the queued values to be written.    Only using it for "Keywords".   Seems to intermittently return a list and a string.       Working on a code sample to show you what I mean.

-Chad

cburkins

Hmmm, making headway.    I'm experimenting with a tag name of "Keywords" vs "IPTC:Keywords".    The latter works consistently, but the former occasionally causes GetNewValue() to return a single string rather than a proper list.

cburkins

I think I fixed my problem by using a tag of "IPTC:Keywords" rather than "Keywords" (which has worked for me for years).   

Feels like this *might* be a bug, since it seems somewhat inconsistent.    Hoping to be helpful, I'll share my code and experimental data:

#!/usr/bin/perl

use strict;

use Image::ExifTool;
use km_common_module;

my $filename = $ARGV[0];
my $newKeyword = $ARGV[1];

my $exifTool = new Image::ExifTool;
$exifTool->ImageInfo($filename);

# New keyword does not exist in picture, so add it
my @origKeywords = $exifTool->GetValue('Keywords');
my @intendedKeywords = @origKeywords;
push @intendedKeywords, $newKeyword;

# Clear out the new values, and set keywords
$exifTool->SetNewValue();
$exifTool->SetNewValue(Keywords => \@intendedKeywords);
my @actualKeywords = $exifTool->GetNewValue('Keywords');

printf ("intended keywords (n=%02d)  ======>   %s\n", $#intendedKeywords, join(" == ", @intendedKeywords));
printf ("GetValue   (n=%02d)         ======>   %s\n", $#origKeywords, join(" == ", @origKeywords));
printf ("GetNewValue  (n=%02d)       ======>   %s\n", $#actualKeywords, join(" == ", @actualKeywords));

printf ("     --- writing file ------\n");
$exifTool->WriteInfo($filename);
$exifTool->ImageInfo($filename);
my @writtenKeywords = $exifTool->GetValue('Keywords');
printf ("   written keywords       ======>   %s\n", join(" == ", @writtenKeywords));
printf ("=============================================================================================================\n");


And here's the experimental run.  I ran the code 14 times in a row, adding a single keyword to the photo each time.   The first time, the keyword was "1", the 2nd time the keyword was "2", and so on.

There was a problem with the 7th and 13th iteration.  In each of those, when I called "GetNewValue()", I got back a single item (rather than a list of items), and in that single item, the string contained all the keywords.   Strange.   If I change the tag from "Keyword", to "IPTC:Keyword", I no longer get this error.

[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 1
intended keywords (n=02)  ======>   a == b == 1
GetValue   (n=01)         ======>   a == b
GetNewValue  (n=02)       ======>   a == b == 1
     --- writing file ------
   written keywords       ======>   a == b == 1
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 2
intended keywords (n=03)  ======>   a == b == 1 == 2
GetValue   (n=02)         ======>   a == b == 1
GetNewValue  (n=03)       ======>   a == b == 1 == 2
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 3
intended keywords (n=04)  ======>   a == b == 1 == 2 == 3
GetValue   (n=03)         ======>   a == b == 1 == 2
GetNewValue  (n=04)       ======>   a == b == 1 == 2 == 3
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 4
intended keywords (n=05)  ======>   a == b == 1 == 2 == 3 == 4
GetValue   (n=04)         ======>   a == b == 1 == 2 == 3
GetNewValue  (n=05)       ======>   a == b == 1 == 2 == 3 == 4
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 5
intended keywords (n=06)  ======>   a == b == 1 == 2 == 3 == 4 == 5
GetValue   (n=05)         ======>   a == b == 1 == 2 == 3 == 4
GetNewValue  (n=06)       ======>   a == b == 1 == 2 == 3 == 4 == 5
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 6
intended keywords (n=07)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6
GetValue   (n=06)         ======>   a == b == 1 == 2 == 3 == 4 == 5
GetNewValue  (n=07)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 7
intended keywords (n=08)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7
GetValue   (n=07)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6
GetNewValue  (n=00)       ======>   a, b, 1, 2, 3, 4, 5, 6, 7
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 8
intended keywords (n=09)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8
GetValue   (n=08)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7
GetNewValue  (n=09)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 9
intended keywords (n=10)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9
GetValue   (n=09)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8
GetNewValue  (n=10)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 10
intended keywords (n=11)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10
GetValue   (n=10)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9
GetNewValue  (n=11)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 11
intended keywords (n=12)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11
GetValue   (n=11)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10
GetNewValue  (n=12)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 12
intended keywords (n=13)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12
GetValue   (n=12)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11
GetNewValue  (n=13)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 13
intended keywords (n=14)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13
GetValue   (n=13)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12
GetNewValue  (n=00)       ======>   a, b, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$ ./testAddKeyword.pl /tmp/rekognition/testPhoto01.jpg 14
intended keywords (n=15)  ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13 == 14
GetValue   (n=14)         ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13
GetNewValue  (n=15)       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13 == 14
     --- writing file ------
   written keywords       ======>   a == b == 1 == 2 == 3 == 4 == 5 == 6 == 7 == 8 == 9 == 10 == 11 == 12 == 13 == 14
=============================================================================================================
[cburkins@bert KeywordMagic (changeKeyword2)]$

Phil Harvey

Interesting.  I'll post back tomorrow after I've had a chance to look into this in more detail.

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

Phil Harvey

OK.   This is not a bug, but it is somewhat confusing.  The apparent inconsistency occurs because you are setting a number of possible Keywords tags, and you aren't specifying which one you want when you call GetNewValue().  The Keywords tags you would be setting are IPTC:Keywords, PostScript:Keywords, MIE-Doc:Keywords, PDF:Keywords, XMP-pdf:Keywords, XMP-xmp:Keywords and XMP-acdsee:Keywords.  Some of these aren't List-type tags, and if you just call GetNewValue('Keywords') then any of these may be returned.  If you happen to get the value of a non-List type tag then you will get a comma-separated string instead of an ARRAY of values.

To illustrate:

> exiftool a.jpg -keywords=x -v2
Writing PDF:Keywords if tag exists
Writing PostScript:Keywords
Writing MIE-Doc:Keywords
Writing XMP-acdsee:Keywords if tag exists
Writing XMP-xmp:Keywords if tag exists
Writing XMP-pdf:Keywords if tag exists
Writing IPTC:Keywords
======== a.jpg
Rewriting a.jpg...


As you discovered, if you call either SetNewValue() or GetNewValues() with "IPTC:Keywords" instead of "Keywords", then the inconsistency goes away since you will be guaranteed to get the IPTC version of the tag, which is List-type.

- Phil

Edit:  I looked in a bit more detail, and the tag returned by ExifTool isn't just random.  It will preferentially return a tag that is being created (ie. no "if tag exists" in -v2 output), which in this case would be one of only 3 possibilities:  PostScript:Keywords, MIE-Doc:Keywords, or IPTC:Keywords.  But since the file type is not known at the time you call GetNewValue(), ExifTool doesn't know which of these will be written, so prioritizing the tags further than this would be problematic.
...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 ($).