exiftool-vendored.pl 12.80.0 → 12.84.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bin/Changes +81 -0
  2. package/bin/MANIFEST +6 -18
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +1 -1
  5. package/bin/README +4 -2
  6. package/bin/build_geolocation +872 -0
  7. package/bin/config_files/example.config +2 -2
  8. package/bin/exiftool +61 -17
  9. package/bin/fmt_files/gpx.fmt +2 -1
  10. package/bin/fmt_files/gpx_wpt.fmt +2 -1
  11. package/bin/lib/Image/ExifTool/Apple.pm +51 -7
  12. package/bin/lib/Image/ExifTool/BuildTagLookup.pm +47 -31
  13. package/bin/lib/Image/ExifTool/CanonVRD.pm +19 -6
  14. package/bin/lib/Image/ExifTool/DJI.pm +29 -0
  15. package/bin/lib/Image/ExifTool/Exif.pm +19 -2
  16. package/bin/lib/Image/ExifTool/FujiFilm.pm +20 -7
  17. package/bin/lib/Image/ExifTool/GM.pm +552 -0
  18. package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  19. package/bin/lib/Image/ExifTool/Geolocation.pm +423 -178
  20. package/bin/lib/Image/ExifTool/Geotag.pm +26 -13
  21. package/bin/lib/Image/ExifTool/M2TS.pm +32 -4
  22. package/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
  23. package/bin/lib/Image/ExifTool/Microsoft.pm +1 -1
  24. package/bin/lib/Image/ExifTool/Nikon.pm +337 -27
  25. package/bin/lib/Image/ExifTool/NikonCustom.pm +55 -1
  26. package/bin/lib/Image/ExifTool/Olympus.pm +1 -0
  27. package/bin/lib/Image/ExifTool/OpenEXR.pm +21 -3
  28. package/bin/lib/Image/ExifTool/PNG.pm +3 -3
  29. package/bin/lib/Image/ExifTool/QuickTime.pm +45 -24
  30. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +66 -30
  31. package/bin/lib/Image/ExifTool/README +2 -0
  32. package/bin/lib/Image/ExifTool/Sony.pm +16 -7
  33. package/bin/lib/Image/ExifTool/TagLookup.pm +4827 -4778
  34. package/bin/lib/Image/ExifTool/TagNames.pod +953 -620
  35. package/bin/lib/Image/ExifTool/WriteQuickTime.pl +32 -9
  36. package/bin/lib/Image/ExifTool/Writer.pl +169 -130
  37. package/bin/lib/Image/ExifTool/XMP.pm +4 -2
  38. package/bin/lib/Image/ExifTool/XMP2.pl +3 -0
  39. package/bin/lib/Image/ExifTool.pm +106 -48
  40. package/bin/lib/Image/ExifTool.pod +47 -25
  41. package/bin/perl-Image-ExifTool.spec +1 -1
  42. package/bin/pp_build_exe.args +4 -4
  43. package/package.json +3 -3
@@ -168,7 +168,8 @@ sub ConvInvISO6709($)
168
168
  # requires at least 3 digits after the decimal point
169
169
  # (and as of Apr 2021, Google Photos doesn't accept coordinats
170
170
  # with more than 5 digits after the decimal place:
171
- # https://exiftool.org/forum/index.php?topic=11055.msg67171#msg67171 )
171
+ # https://exiftool.org/forum/index.php?topic=11055.msg67171#msg67171
172
+ # still a problem Apr 2024: https://exiftool.org/forum/index.php?msg=85761)
172
173
  my @fmt = ('%s%02d.%s%s','%s%03d.%s%s','%s%d.%s%s');
173
174
  my @limit = (90,180);
174
175
  foreach (@a) {
@@ -785,6 +786,7 @@ sub WriteQuickTime($$$)
785
786
  $et or return 1; # allow dummy access to autoload this package
786
787
  my ($mdat, @mdat, @mdatEdit, $edit, $track, $outBuff, $co, $term, $delCount);
787
788
  my (%langTags, $canCreate, $delGrp, %boxPos, %didDir, $writeLast, $err, $atomCount);
789
+ my ($tag, $lastTag, $errStr);
788
790
  my $outfile = $$dirInfo{OutFile} || return 0;
789
791
  my $raf = $$dirInfo{RAF}; # (will be null for lower-level atoms)
790
792
  my $dataPt = $$dirInfo{DataPt}; # (will be null for top-level atoms)
@@ -857,7 +859,10 @@ sub WriteQuickTime($$$)
857
859
  }
858
860
  $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT} if $$tagTablePtr{VARS};
859
861
 
862
+ $tag = $lastTag = '';
863
+
860
864
  for (;;) { # loop through all atoms at this level
865
+ $lastTag = $tag if $$tagTablePtr{$tag}; # keep track of last known tag
861
866
  if (defined $atomCount and --$atomCount < 0 and $dataPt) {
862
867
  # stop processing now and just copy the rest of the atom
863
868
  Write($outfile, substr($$dataPt, $raf->Tell())) or $rtnVal=$rtnErr, $err=1;
@@ -876,15 +881,15 @@ sub WriteQuickTime($$$)
876
881
  last;
877
882
  }
878
883
  my $size = Get32u(\$hdr, 0) - 8; # (atom size without 8-byte header)
879
- my $tag = substr($hdr, 4, 4);
884
+ $tag = substr($hdr, 4, 4);
880
885
  if ($size == -7) {
881
886
  # read the extended size
882
- $raf->Read($buff, 8) == 8 or $et->Error('Truncated extended atom'), last;
887
+ $raf->Read($buff, 8) == 8 or $errStr = 'Truncated extended atom', last;
883
888
  $hdr .= $buff;
884
889
  my ($hi, $lo) = unpack('NN', $buff);
885
890
  if ($hi or $lo > 0x7fffffff) {
886
891
  if ($hi > 0x7fffffff) {
887
- $et->Error('Invalid atom size');
892
+ $errStr = 'Invalid atom size';
888
893
  last;
889
894
  } elsif (not $et->Options('LargeFileSupport')) {
890
895
  $et->Error('End of processing at large atom (LargeFileSupport not enabled)');
@@ -892,7 +897,7 @@ sub WriteQuickTime($$$)
892
897
  }
893
898
  }
894
899
  $size = $hi * 4294967296 + $lo - 16;
895
- $size < 0 and $et->Error('Invalid extended atom size'), last;
900
+ $size < 0 and $errStr = 'Invalid extended atom size', last;
896
901
  } elsif ($size == -8) {
897
902
  if ($dataPt) {
898
903
  last if $$dirInfo{DirName} eq 'CanonCNTH'; # (this is normal for Canon CNTH atom)
@@ -908,7 +913,7 @@ sub WriteQuickTime($$$)
908
913
  }
909
914
  last;
910
915
  } elsif ($size < 0) {
911
- $et->Error('Invalid atom size');
916
+ $errStr = 'Invalid atom size';
912
917
  last;
913
918
  }
914
919
 
@@ -952,11 +957,11 @@ sub WriteQuickTime($$$)
952
957
  $tag = PrintableTagID($tag,3);
953
958
  if ($size > $maxReadLen and $got == 0x10000) {
954
959
  my $mb = int($size / 0x100000 + 0.5);
955
- $et->Error("'${tag}' atom is too large for rewriting ($mb MB)");
960
+ $errStr = "'${tag}' atom is too large for rewriting ($mb MB)";
956
961
  } else {
957
- $et->Error("Truncated '${tag}' atom");
962
+ $errStr = "Truncated '${tag}' atom";
958
963
  }
959
- return $rtnVal;
964
+ last;
960
965
  }
961
966
  }
962
967
  # save the handler type for this track
@@ -1446,6 +1451,24 @@ sub WriteQuickTime($$$)
1446
1451
  Write($outfile, $hdr, $buff) or $rtnVal=$rtnErr, $err=1, last;
1447
1452
  }
1448
1453
  }
1454
+ # ($errStr is set if there was an error that could possibly be due to an unknown trailer)
1455
+ if ($errStr) {
1456
+ if (($lastTag eq 'mdat' or $lastTag eq 'moov') and not $dataPt and (not $$tagTablePtr{$tag} or
1457
+ ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
1458
+ {
1459
+ my $nvTrail = $et->GetNewValueHash($Image::ExifTool::Extra{Trailer});
1460
+ if ($$et{DEL_GROUP}{Trailer} or ($nvTrail and not ($$nvTrail{Value} and $$nvTrail{Value}[0]))) {
1461
+ $errStr =~ s/ is too large.*//;
1462
+ $et->Warn('Deleted unknown trailer with ' . lcfirst($errStr));
1463
+ } else {
1464
+ $et->Warn('Unknown trailer with ' . lcfirst($errStr));
1465
+ $et->Error('Use "-trailer=" to delete unknown trailer');
1466
+ }
1467
+ } else {
1468
+ $et->Error($errStr);
1469
+ return $dataPt ? undef : 1;
1470
+ }
1471
+ }
1449
1472
  $et->VPrint(0, " [deleting $delCount $dirName tag".($delCount==1 ? '' : 's')."]\n") if $delCount;
1450
1473
 
1451
1474
  $createKeys &= ~0x01 unless $$addDirs{Keys}; # (Keys may have been written)
@@ -1234,7 +1234,8 @@ WriteAlso:
1234
1234
 
1235
1235
  #------------------------------------------------------------------------------
1236
1236
  # set new values from information in specified file
1237
- # Inputs: 0) ExifTool object reference, 1) source file name or reference, etc
1237
+ # Inputs: 0) ExifTool object reference, 1) source file name or reference, etc,
1238
+ # or ExifTool ref to use already-extracted tags from an ExifTool object,
1238
1239
  # 2-N) List of tags to set (or all if none specified), or reference(s) to
1239
1240
  # hash for options to pass to SetNewValue. The Replace option defaults
1240
1241
  # to 1 for SetNewValuesFromFile -- set this to 0 to allow multiple tags
@@ -1245,11 +1246,12 @@ WriteAlso:
1245
1246
  # be used to represent all tags in a group. An optional destination tag
1246
1247
  # may be specified with '>DSTTAG' ('DSTTAG<TAG' also works, but in this
1247
1248
  # case the source tag may also be an expression involving tag names).
1249
+ # Simple assignments are also allowed: 'DSTTAG[#][+-][^]=[string]'
1248
1250
  sub SetNewValuesFromFile($$;@)
1249
1251
  {
1250
1252
  local $_;
1251
1253
  my ($self, $srcFile, @setTags) = @_;
1252
- my ($key, $tag, @exclude, @reqTags);
1254
+ my ($srcExifTool, $key, $tag, @exclude, @reqTags, $info);
1253
1255
 
1254
1256
  # get initial SetNewValuesFromFile options
1255
1257
  my %opts = ( Replace => 1 ); # replace existing list items by default
@@ -1261,119 +1263,131 @@ sub SetNewValuesFromFile($$;@)
1261
1263
  }
1262
1264
  # expand shortcuts
1263
1265
  @setTags and ExpandShortcuts(\@setTags);
1264
- my $srcExifTool = Image::ExifTool->new;
1265
- # set flag to indicate we are being called from inside SetNewValuesFromFile()
1266
- $$srcExifTool{TAGS_FROM_FILE} = 1;
1267
- # synchronize and increment the file sequence number
1268
- $$srcExifTool{FILE_SEQUENCE} = $$self{FILE_SEQUENCE}++;
1269
1266
  # set options for our extraction tool
1270
1267
  my $options = $$self{OPTIONS};
1271
- # copy both structured and flattened tags by default (but flattened tags are "unsafe")
1272
- my $structOpt = defined $$options{Struct} ? $$options{Struct} : 2;
1273
- # copy structures only if no tags specified (since flattened tags are "unsafe")
1274
- $structOpt = 1 if $structOpt eq '2' and not @setTags;
1275
- # +------------------------------------------+
1276
- # ! DON'T FORGET!! Must consider each new !
1277
- # ! option to decide how it is handled here. !
1278
- # +------------------------------------------+
1279
- $srcExifTool->Options(
1280
- Binary => 1,
1281
- ByteUnit => $$options{ByteUnit},
1282
- Charset => $$options{Charset},
1283
- CharsetEXIF => $$options{CharsetEXIF},
1284
- CharsetFileName => $$options{CharsetFileName},
1285
- CharsetID3 => $$options{CharsetID3},
1286
- CharsetIPTC => $$options{CharsetIPTC},
1287
- CharsetPhotoshop=> $$options{CharsetPhotoshop},
1288
- Composite => $$options{Composite},
1289
- CoordFormat => $$options{CoordFormat} || '%d %d %.8f', # copy coordinates at high resolution unless otherwise specified
1290
- DateFormat => $$options{DateFormat},
1291
- Duplicates => 1,
1292
- Escape => $$options{Escape},
1293
- # Exclude (set below)
1294
- ExtendedXMP => $$options{ExtendedXMP},
1295
- ExtractEmbedded => $$options{ExtractEmbedded},
1296
- FastScan => $$options{FastScan},
1297
- Filter => $$options{Filter},
1298
- FixBase => $$options{FixBase},
1299
- Geolocation => $$options{Geolocation},
1300
- GeolocFeature => $$options{GeolocFeature},
1301
- GeolocMinPop => $$options{GeolocMinPop},
1302
- GeolocMaxDist => $$options{GeolocMaxDist},
1303
- GlobalTimeShift => $$options{GlobalTimeShift},
1304
- HexTagIDs => $$options{HexTagIDs},
1305
- IgnoreMinorErrors=>$$options{IgnoreMinorErrors},
1306
- IgnoreTags => $$options{IgnoreTags},
1307
- ImageHashType => $$options{ImageHashType},
1308
- Lang => $$options{Lang},
1309
- LargeFileSupport=> $$options{LargeFileSupport},
1310
- LimitLongValues => 10000000, # (10 MB)
1311
- List => 1,
1312
- ListItem => $$options{ListItem},
1313
- ListSep => $$options{ListSep},
1314
- MakerNotes => $$options{FastScan} && $$options{FastScan} > 1 ? undef : 1,
1315
- MDItemTags => $$options{MDItemTags},
1316
- MissingTagValue => $$options{MissingTagValue},
1317
- NoPDFList => $$options{NoPDFList},
1318
- NoWarning => $$options{NoWarning},
1319
- Password => $$options{Password},
1320
- PrintConv => $$options{PrintConv},
1321
- QuickTimeUTC => $$options{QuickTimeUTC},
1322
- RequestAll => $$options{RequestAll} || 1, # (is this still necessary now that RequestTags are being set?)
1323
- RequestTags => $$options{RequestTags},
1324
- SaveFormat => $$options{SaveFormat},
1325
- SavePath => $$options{SavePath},
1326
- ScanForXMP => $$options{ScanForXMP},
1327
- StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1,
1328
- Struct => $structOpt,
1329
- StructFormat => $$options{StructFormat},
1330
- SystemTags => $$options{SystemTags},
1331
- TimeZone => $$options{TimeZone},
1332
- Unknown => $$options{Unknown},
1333
- UserParam => $$options{UserParam},
1334
- Validate => $$options{Validate},
1335
- WindowsWideFile => $$options{WindowsWideFile},
1336
- XAttrTags => $$options{XAttrTags},
1337
- XMPAutoConv => $$options{XMPAutoConv},
1338
- );
1339
- $$srcExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
1340
- $$srcExifTool{ALT_EXIFTOOL} = $$self{ALT_EXIFTOOL};
1341
- foreach $tag (@setTags) {
1342
- next if ref $tag;
1343
- if ($tag =~ /^-(.*)/) {
1344
- # avoid extracting tags that are excluded
1345
- push @exclude, $1;
1346
- next;
1347
- }
1348
- # add specified tags to list of requested tags
1349
- $_ = $tag;
1350
- if (/(.+?)\s*(>|<)\s*(.+)/) {
1351
- if ($2 eq '>') {
1352
- $_ = $1;
1353
- } else {
1354
- $_ = $3;
1355
- /\$/ and push(@reqTags, /\$\{?(?:[-\w]+:)*([-\w?*]+)/g), next;
1356
- }
1357
- }
1358
- push @reqTags, $2 if /(^|:)([-\w?*]+)#?$/;
1359
- }
1360
- if (@exclude) {
1361
- ExpandShortcuts(\@exclude, 1);
1362
- $srcExifTool->Options(Exclude => \@exclude);
1363
- }
1364
- $srcExifTool->Options(RequestTags => \@reqTags) if @reqTags;
1365
1268
  my $printConv = $$options{PrintConv};
1366
1269
  if ($opts{Type}) {
1367
1270
  # save source type separately because it may be different than dst Type
1368
1271
  $opts{SrcType} = $opts{Type};
1369
1272
  # override PrintConv option with initial Type if given
1370
1273
  $printConv = ($opts{Type} eq 'PrintConv' ? 1 : 0);
1371
- $srcExifTool->Options(PrintConv => $printConv);
1372
1274
  }
1373
1275
  my $srcType = $printConv ? 'PrintConv' : 'ValueConv';
1276
+ my $structOpt = defined $$options{Struct} ? $$options{Struct} : 2;
1374
1277
 
1375
- # get all tags from source file (including MakerNotes block)
1376
- my $info = $srcExifTool->ImageInfo($srcFile);
1278
+ if (ref $srcFile and UNIVERSAL::isa($srcFile,'Image::ExifTool')) {
1279
+ $srcExifTool = $srcFile;
1280
+ $info = $srcExifTool->GetInfo({ PrintConv => $printConv });
1281
+ } else {
1282
+ $srcExifTool = Image::ExifTool->new;
1283
+ $srcExifTool->Options(PrintConv => $printConv);
1284
+ # set flag to indicate we are being called from inside SetNewValuesFromFile()
1285
+ $$srcExifTool{TAGS_FROM_FILE} = 1;
1286
+ # synchronize and increment the file sequence number
1287
+ $$srcExifTool{FILE_SEQUENCE} = $$self{FILE_SEQUENCE}++;
1288
+ # copy both structured and flattened tags by default (but flattened tags are "unsafe")
1289
+ # copy structures only if no tags specified (since flattened tags are "unsafe")
1290
+ $structOpt = 1 if $structOpt eq '2' and not @setTags;
1291
+ # +------------------------------------------+
1292
+ # ! DON'T FORGET!! Must consider each new !
1293
+ # ! option to decide how it is handled here. !
1294
+ # +------------------------------------------+
1295
+ $srcExifTool->Options(
1296
+ Binary => 1,
1297
+ ByteUnit => $$options{ByteUnit},
1298
+ Charset => $$options{Charset},
1299
+ CharsetEXIF => $$options{CharsetEXIF},
1300
+ CharsetFileName => $$options{CharsetFileName},
1301
+ CharsetID3 => $$options{CharsetID3},
1302
+ CharsetIPTC => $$options{CharsetIPTC},
1303
+ CharsetPhotoshop=> $$options{CharsetPhotoshop},
1304
+ Composite => $$options{Composite},
1305
+ CoordFormat => $$options{CoordFormat} || '%d %d %.8f', # copy coordinates at high resolution unless otherwise specified
1306
+ DateFormat => $$options{DateFormat},
1307
+ Duplicates => 1,
1308
+ Escape => $$options{Escape},
1309
+ # Exclude (set below)
1310
+ ExtendedXMP => $$options{ExtendedXMP},
1311
+ ExtractEmbedded => $$options{ExtractEmbedded},
1312
+ FastScan => $$options{FastScan},
1313
+ Filter => $$options{Filter},
1314
+ FixBase => $$options{FixBase},
1315
+ Geolocation => $$options{Geolocation},
1316
+ GeolocAltNames => $$options{GeolocAltNames},
1317
+ GeolocFeature => $$options{GeolocFeature},
1318
+ GeolocMinPop => $$options{GeolocMinPop},
1319
+ GeolocMaxDist => $$options{GeolocMaxDist},
1320
+ GlobalTimeShift => $$options{GlobalTimeShift},
1321
+ HexTagIDs => $$options{HexTagIDs},
1322
+ IgnoreGroups => $$options{IgnoreGroups},
1323
+ IgnoreMinorErrors=>$$options{IgnoreMinorErrors},
1324
+ IgnoreTags => $$options{IgnoreTags},
1325
+ ImageHashType => $$options{ImageHashType},
1326
+ Lang => $$options{Lang},
1327
+ LargeFileSupport=> $$options{LargeFileSupport},
1328
+ LimitLongValues => 10000000, # (10 MB)
1329
+ List => 1,
1330
+ ListItem => $$options{ListItem},
1331
+ ListSep => $$options{ListSep},
1332
+ MakerNotes => $$options{FastScan} && $$options{FastScan} > 1 ? undef : 1,
1333
+ MDItemTags => $$options{MDItemTags},
1334
+ MissingTagValue => $$options{MissingTagValue},
1335
+ NoPDFList => $$options{NoPDFList},
1336
+ NoWarning => $$options{NoWarning},
1337
+ Password => $$options{Password},
1338
+ PrintConv => $$options{PrintConv},
1339
+ QuickTimeUTC => $$options{QuickTimeUTC},
1340
+ RequestAll => $$options{RequestAll} || 1, # (is this still necessary now that RequestTags are being set?)
1341
+ RequestTags => $$options{RequestTags},
1342
+ SaveFormat => $$options{SaveFormat},
1343
+ SavePath => $$options{SavePath},
1344
+ ScanForXMP => $$options{ScanForXMP},
1345
+ StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1,
1346
+ Struct => $structOpt,
1347
+ StructFormat => $$options{StructFormat},
1348
+ SystemTags => $$options{SystemTags},
1349
+ TimeZone => $$options{TimeZone},
1350
+ Unknown => $$options{Unknown},
1351
+ UserParam => $$options{UserParam},
1352
+ Validate => $$options{Validate},
1353
+ WindowsWideFile => $$options{WindowsWideFile},
1354
+ XAttrTags => $$options{XAttrTags},
1355
+ XMPAutoConv => $$options{XMPAutoConv},
1356
+ );
1357
+ # reset Geolocation option if we aren't copying any geolocation tags
1358
+ if ($$options{Geolocation} and not grep /\bGeolocation/i, @setTags) {
1359
+ $self->VPrint(0, '(resetting unnecessary Geolocation option)');
1360
+ $$srcExifTool{OPTIONS}{Geolocation} = undef;
1361
+ }
1362
+ $$srcExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
1363
+ $$srcExifTool{ALT_EXIFTOOL} = $$self{ALT_EXIFTOOL};
1364
+ foreach $tag (@setTags) {
1365
+ next if ref $tag;
1366
+ if ($tag =~ /^-(.*)/) {
1367
+ # avoid extracting tags that are excluded
1368
+ push @exclude, $1;
1369
+ next;
1370
+ }
1371
+ # add specified tags to list of requested tags
1372
+ $_ = $tag;
1373
+ if (/(.+?)\s*(>|<)\s*(.+)/) {
1374
+ if ($2 eq '>') {
1375
+ $_ = $1;
1376
+ } else {
1377
+ $_ = $3;
1378
+ /\$/ and push(@reqTags, /\$\{?(?:[-\w]+:)*([-\w?*]+)/g), next;
1379
+ }
1380
+ }
1381
+ push @reqTags, $2 if /(^|:)([-\w?*]+)#?$/;
1382
+ }
1383
+ if (@exclude) {
1384
+ ExpandShortcuts(\@exclude, 1);
1385
+ $srcExifTool->Options(Exclude => \@exclude);
1386
+ }
1387
+ $srcExifTool->Options(RequestTags => \@reqTags) if @reqTags;
1388
+ # get all tags from source file (including MakerNotes block)
1389
+ $info = $srcExifTool->ImageInfo($srcFile);
1390
+ }
1377
1391
  return $info if $$info{Error} and $$info{Error} eq 'Error opening file';
1378
1392
  delete $$srcExifTool{VALUE}{Error}; # delete so we can check this later
1379
1393
 
@@ -1408,6 +1422,7 @@ sub SetNewValuesFromFile($$;@)
1408
1422
  #
1409
1423
  # 1) loop through input list of tags to set, and build @setList
1410
1424
  my (@setList, $set, %setMatches, $t, %altFiles);
1425
+ my $assign = 0;
1411
1426
  foreach $t (@setTags) {
1412
1427
  if (ref $t eq 'HASH') {
1413
1428
  # update current options
@@ -1422,18 +1437,22 @@ sub SetNewValuesFromFile($$;@)
1422
1437
  $tag = lc $t; # change tag/group names to all lower case
1423
1438
  my (@fg, $grp, $dst, $dstGrp, $dstTag, $isExclude);
1424
1439
  # handle redirection to another tag
1425
- if ($tag =~ /(.+?)\s*(>|<)\s*(.+)/) {
1440
+ if ($tag =~ /(.+?)\s*(>|<|=)(\s*)(.*)/) {
1426
1441
  $dstGrp = '';
1427
- my $opt;
1442
+ my ($opt, $op, $spc);
1428
1443
  if ($2 eq '>') {
1429
- ($tag, $dstTag) = ($1, $3);
1444
+ ($tag, $dstTag) = ($1, $4);
1430
1445
  # flag add and delete (eg. '+<' and '-<') redirections
1431
1446
  $opt = $1 if $tag =~ s/\s*([-+])$// or $dstTag =~ s/^([-+])\s*//;
1432
1447
  } else {
1433
- ($tag, $dstTag) = ($3, $1);
1448
+ ($dstTag, $op, $spc, $tag) = ($1, $2, $3, $4);
1434
1449
  $opt = $1 if $dstTag =~ s/\s*([-+])$//;
1435
- # handle expressions
1436
- if ($tag =~ /\$/) {
1450
+ if ($op eq '=') {
1451
+ # simple assignment ($tag will be the new value)
1452
+ $tag = $spc . $tag;
1453
+ undef $tag unless $dstTag =~ s/\^$// or length $tag;
1454
+ $$opts{ASSIGN} = ++$assign;
1455
+ } elsif ($tag =~ /\$/) { # handle expressions
1437
1456
  $tag = $t; # restore original case
1438
1457
  # recover leading whitespace (except for initial single space)
1439
1458
  $tag =~ s/(.+?)\s*(>|<) ?//;
@@ -1446,7 +1465,7 @@ sub SetNewValuesFromFile($$;@)
1446
1465
  }
1447
1466
  $$opts{Replace} = 0 if $dstTag =~ s/^\+//;
1448
1467
  # validate tag name(s)
1449
- unless ($$opts{EXPR} or ValidTagName($tag)) {
1468
+ unless ($$opts{EXPR} or $$opts{ASSIGN} or ValidTagName($tag)) {
1450
1469
  $self->Warn("Invalid tag name '${tag}'. Use '=' not '<' to assign a tag value");
1451
1470
  next;
1452
1471
  }
@@ -1464,7 +1483,7 @@ sub SetNewValuesFromFile($$;@)
1464
1483
  } else {
1465
1484
  $$opts{Replace} = 0 if $tag =~ s/^\+//;
1466
1485
  }
1467
- unless ($$opts{EXPR}) {
1486
+ unless ($$opts{EXPR} or $$opts{ASSIGN}) {
1468
1487
  $isExclude = ($tag =~ s/^-//);
1469
1488
  if ($tag =~ /(.*):(.+)/) {
1470
1489
  ($grp, $tag) = ($1, $2);
@@ -1534,6 +1553,8 @@ sub SetNewValuesFromFile($$;@)
1534
1553
  foreach $set (@setList) {
1535
1554
  $$set[2] and $setMatches{$set} = [ ];
1536
1555
  }
1556
+ # no need to search source tags if doing only assignments
1557
+ undef @tags if $assign == @setList;
1537
1558
  # 3) loop through all tags in source image and save tags matching each setTag
1538
1559
  my (%rtnInfo, $isAlt);
1539
1560
  foreach $tag (@tags) {
@@ -1586,21 +1607,26 @@ SET: foreach $set (@setList) {
1586
1607
  # get options for SetNewValue
1587
1608
  my $opts = $$set[3];
1588
1609
  # handle expressions
1589
- if ($$opts{EXPR}) {
1590
- my $val = $srcExifTool->InsertTagValues($$set[1], \@tags, 'Error');
1591
- my $err = $$srcExifTool{VALUE}{Error};
1592
- if ($err) {
1593
- # pass on any error as a warning unless it is suppressed
1594
- my $noWarn = $$srcExifTool{OPTIONS}{NoWarning};
1595
- unless ($noWarn and (eval { $err =~ /$noWarn/ } or
1596
- # (also apply expression to warning without "[minor] " prefix)
1597
- ($err =~ s/^\[minor\] //i and eval { $err =~ /$noWarn/ })))
1598
- {
1599
- $tag = NextFreeTagKey(\%rtnInfo, 'Warning');
1600
- $rtnInfo{$tag} = $$srcExifTool{VALUE}{Error};
1610
+ if ($$opts{EXPR} or $$opts{ASSIGN}) {
1611
+ my $val;
1612
+ if ($$opts{EXPR}) {
1613
+ $val = $srcExifTool->InsertTagValues($$set[1], \@tags, 'Error');
1614
+ my $err = $$srcExifTool{VALUE}{Error};
1615
+ if ($err) {
1616
+ # pass on any error as a warning unless it is suppressed
1617
+ my $noWarn = $$srcExifTool{OPTIONS}{NoWarning};
1618
+ unless ($noWarn and (eval { $err =~ /$noWarn/ } or
1619
+ # (also apply expression to warning without "[minor] " prefix)
1620
+ ($err =~ s/^\[minor\] //i and eval { $err =~ /$noWarn/ })))
1621
+ {
1622
+ $tag = NextFreeTagKey(\%rtnInfo, 'Warning');
1623
+ $rtnInfo{$tag} = $$srcExifTool{VALUE}{Error};
1624
+ }
1625
+ delete $$srcExifTool{VALUE}{Error};
1626
+ next unless defined $val;
1601
1627
  }
1602
- delete $$srcExifTool{VALUE}{Error};
1603
- next unless defined $val;
1628
+ } else {
1629
+ $val = $$set[1];
1604
1630
  }
1605
1631
  my ($dstGrp, $dstTag) = @{$$set[2]};
1606
1632
  $$opts{Protected} = 1 unless $dstTag =~ /[?*]/ and $dstTag ne '*';
@@ -3161,8 +3187,8 @@ sub PushValue($$$;$)
3161
3187
  # Inputs: 0) ExifTool object ref, 1) string with embedded tag names,
3162
3188
  # 2) reference to list of found tags or undef to use FOUND_TAGS, 3) Options:
3163
3189
  # undef - set missing tags to ''
3164
- # 'Error' - issue minor error on missing tag (and return undef)
3165
- # 'Warn' - issue minor warning on missing tag (and return undef)
3190
+ # 'Error' - issue minor error on missing tag (and return undef if error sent)
3191
+ # 'Warn' - issue minor warning on missing tag (and return undef if warning sent)
3166
3192
  # 'Silent' - just return undef on missing tag (no errors/warnings)
3167
3193
  # Hash ref - defined to interpolate as variables in string instead of values
3168
3194
  # --> receives tag/value pairs for interpolation of the variables
@@ -3448,6 +3474,19 @@ sub NoDups
3448
3474
  $_ = ($_[0] and $new eq $_) ? undef : $new;
3449
3475
  }
3450
3476
 
3477
+ #------------------------------------------------------------------------------
3478
+ # Utility routine to set in $_ image from current object
3479
+ # Inputs: 0-N) list of tags to copy
3480
+ # Returns: Return value from WriteInfo
3481
+ # Notes: - for use only in advanced formatting expressions
3482
+ sub SetTags(@)
3483
+ {
3484
+ my $self = $advFmtSelf;
3485
+ my $et = Image::ExifTool->new;
3486
+ $et->SetNewValuesFromFile($self, @_);
3487
+ return $et->WriteInfo(\$_);
3488
+ }
3489
+
3451
3490
  #------------------------------------------------------------------------------
3452
3491
  # Is specified tag writable
3453
3492
  # Inputs: 0) tag name, case insensitive (optional group name currently ignored)
@@ -3806,7 +3845,7 @@ sub GetGeolocateTags($$;$)
3806
3845
  'iptc' => [ qw(City Province-State Country-PrimaryLocationCode Country-PrimaryLocationName) ],
3807
3846
  'gps' => [ qw(GPSLatitude GPSLongitude GPSLatitudeRef GPSLongitudeRef) ],
3808
3847
  'xmp-exif' => [ qw(GPSLatitude GPSLongitude) ],
3809
- 'keys' => [ 'GPSCoordinates' ],
3848
+ 'keys' => [ 'GPSCoordinates', 'LocationName' ],
3810
3849
  'itemlist' => [ 'GPSCoordinates' ],
3811
3850
  'userdata' => [ 'GPSCoordinates' ],
3812
3851
  # more general groups not in this lookup: XMP and QuickTime
@@ -3818,7 +3857,7 @@ sub GetGeolocateTags($$;$)
3818
3857
  }
3819
3858
  # set default XMP City tags if necessary
3820
3859
  if (not $writeGPS and ($grps{xmp} or (not @tags and not $grps{quicktime}))) {
3821
- push @tags, qw(XMP:City XMP:State XMP:CountryCode XMP:Country);
3860
+ push @tags, qw(XMP:City XMP:State XMP:CountryCode XMP:Country Keys:LocationName);
3822
3861
  }
3823
3862
  $writeGPS = 1 unless defined $writeGPS; # (delete both City and GPS)
3824
3863
  # set default QuickTime tag if necessary
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
  require Exporter;
52
52
 
53
- $VERSION = '3.64';
53
+ $VERSION = '3.65';
54
54
  @ISA = qw(Exporter);
55
55
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
56
56
 
@@ -283,11 +283,12 @@ my %recognizedAttrs = (
283
283
  # NOTE: this lookup is duplicated in TagLookup.pm!!
284
284
  %specialStruct = (
285
285
  STRUCT_NAME => 1, # [optional] name of structure
286
- NAMESPACE => 1, # [mandatory] namespace prefix used for fields of this structure
286
+ NAMESPACE => 1, # [mandatory for XMP] namespace prefix used for fields of this structure
287
287
  NOTES => 1, # [optional] notes for documentation about this structure
288
288
  TYPE => 1, # [optional] rdf:type resource for struct (if used, the StructType flag
289
289
  # will be set automatically for all derived flattened tags when writing)
290
290
  GROUPS => 1, # [optional] specifies family group 2 name for the structure
291
+ SORT_ORDER => 1, # [optional] order for sorting fields in documentation
291
292
  );
292
293
  # XMP structures (each structure is similar to a tag table so we can
293
294
  # recurse through them in SetPropertyPath() as if they were tag tables)
@@ -2587,6 +2588,7 @@ my %sPantryItem = (
2587
2588
  EnhanceDenoiseAlreadyApplied => { Writable => 'boolean' }, #forum14760
2588
2589
  EnhanceDenoiseVersion => { }, #forum14760 integer?
2589
2590
  EnhanceDenoiseLumaAmount => { }, #forum14760 integer?
2591
+ # FujiRatingAlreadyApplied - boolean written by LR classic 13.2 (forum15815)
2590
2592
  );
2591
2593
 
2592
2594
  # IPTC Core namespace properties (Iptc4xmpCore) (ref 4)
@@ -1941,6 +1941,9 @@ my %sACDSeeRegionStruct = (
1941
1941
  ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
1942
1942
  ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
1943
1943
  },
1944
+ MotionPhoto => { Writable => 'integer' },
1945
+ MotionPhotoVersion => { Writable => 'integer' },
1946
+ MotionPhotoPresentationTimestampUs => { Writable => 'integer' },
1944
1947
  );
1945
1948
 
1946
1949
  # Google creations namespace (ref PH)