This is just out of idle curiosity, since I have a workaround. I have the following code (yes, I know I'm not checking return codes, yadda-yadda :-D):
my $setNameType = 1;
...
{
...
$success = $exifTool->SetNewValue('RegionName' => \@regionName);
$success = $exifTool->SetNewValue('RegionType' => \@regionType);
$setNameType = 0;
$success = $exifTool->SetNewValue('RegionAreaUnit' => \@regionAreaUnit);
$success = $exifTool->SetNewValue('RegionAreaX' => \@regionAreaX);
$success = $exifTool->SetNewValue('RegionAreaY' => \@regionAreaY);
$success = $exifTool->SetNewValue('RegionAreaW' => \@regionAreaW);
$success = $exifTool->SetNewValue('RegionAreaH' => \@regionAreaH);
$exifTool->WriteInfo($file);
$info = $exifTool->ImageInfo($file);
}
if (defined $$info{RegionName} && @{$$info{RegionName}} > 0) {
@regionName = uniq(@{$$info{RegionName}});
# if RegionName exists, assume corresponding RegionType exists as well
@regionType = @{$$info{RegionType}};
if (@regionName < @{$$info{RegionName}}) {
splice @regionType, 1, @{$$info{RegionName}} - @regionName;
}
# use the regionName as the basis for Keywords, Subject, etc.
$updates = 1; # we'll always update
if ($setNameType) {
$success = $exifTool->SetNewValue('RegionName' => \@regionName);
$success = $exifTool->SetNewValue('RegionType' => \@regionType);
}
$success = $exifTool->SetNewValue('Keywords' => \@regionName);
$success = $exifTool->SetNewValue('Subject' => \@regionName);
}
...
$exifTool->WriteInfo($file);
Assume that going in @regionName is [foo, bar, baz], and @regionType is [Face, Face, Face]. If I remove the lines referring to $setNameType (i.e., no assignment and no conditional), the RegionName tag eventually gets written as [foo, bar, baz, foo, bar, baz], and RegionType is [Face, Face, Face, Face, Face, Face]. The duplication is what surprises me, as I though SetNewValue overwrites by default. If I use setNameType as shown, I get what I expect (e.g. no duplication). Can someone clue me to what I'm missing?
Multiple setNewValue calls add up for list types. To prevent that, set the Replace option. See the documentation (https://exiftool.org/ExifTool.html#SetNewValue)
In general I would recommend writing these as structured tags (ie. add structures to XMP-mwg-rs:RegionList). Usually it is easier this way to ensure that you are making the proper associations.
- Phil
Thanks, guys! I saw "0 = Overwrite existing value(s)" in AddValue as the default and thought that would take care of it, completely missed Replace. The structured tags look good, I'll give them a whirl.
Totally confused. So I do: my $info = $exifTool->ImageInfo($file);
I thought that when I used@{$$info{RegionName}}
I would get a count of the elements in the RegionName array. Instead, I get what I consider to be the first element of the array, a string. I think I'm getting lost in the levels of indirection.
Perl's handling of list variables is probably what was confusing you ;D
When you use an array (list) variable in scalar context, you get the number of elements in the array, but when you use it in list context, you get the elements themselves.
Example:
my @list = ( "One", 2 ,3 ,4, "Five" );
my $list = @list;
print "$list\n";
print "@list\n";
will give the following output:
5
One 2 3 4 Five
(print by default just shows all elements with a space in between. To do this comma separated, do something like this:
print join(", ", @list) . "\n";
Hope this helps,
Hayo
I agree with Hayo's assessment. But you must be careful about the context. Your @{$$info{RegionName}} should return the array, provided that $$info{RegionName} was an ARRAY reference. Then what you get depends on the context:
$var = @{$$info{RegionName}}; # scalar context returns number of elements in the array
($var) = @{$$info{RegionName}}; # list context returns first element of the array
- Phil
OK, maybe it's context confusion. :P Here's some more detail:
if (!defined $$info{RegionName} || @{$$info{RegionName}} == 0)
Perl complains:
Can't use string ("Joe Smith") as an ARRAY ref while "strict refs" in use at ../../../../Metadata/EXIF/ExifTool/exiftidy.pl line 216.
So what's the syntax for getting the number of elements from $$info{RegionName} (or, erm, what it refers to)?
OK. I think we have to step back a bit. I said:
Quoteprovided that $$info{RegionName} was an ARRAY reference
You must check this since it may be a scalar if there is just one element:
if (ref $$info{RegionName} eq 'ARRAY') {
$num = @{$$info{RegionName}};
} elsif (defined $$info{RegionName}) {
$num = 1;
} else {
$num = 0;
}
- Phil
Wait, so if a list/array has only one element, it's always interpreted as a scalar? BTW, thanks for your help with this, Phil (Hayo too!).
Hi Tom,
No, arrays are always interpreted as arrays. However, a reference can point to anything so you have to know what it is pointing to. Normally you do know what it is, but in this case it turns out it can be either. exiftool treats it as a scalar if there is just one element which I hadn't expected myself either, but it is probably mentioned in the documentation ;D
Quote from: Hayo Baan on April 13, 2016, 12:58:49 PM
it is probably mentioned in the documentation ;D
Hmmm. If it is, I can't find it, other than this quote:
an array reference
may be used to indicate a list
(emphasis added)
Depending on the options, a list with a single item may sometimes be returned as an ARRAY ref (eg. if Struct is used), and a list with multiple items may be returned as a SCALAR (eg. if the List option isn't set).
- Phil