exiftool-vendored.exe 12.97.0 → 13.0.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 (29) hide show
  1. package/bin/exiftool_files/exiftool.pl +221 -41
  2. package/bin/exiftool_files/lib/File/RandomAccess.pm +5 -2
  3. package/bin/exiftool_files/lib/Image/ExifTool/APP12.pm +3 -2
  4. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +2 -1
  5. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +1 -1
  6. package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.dat +0 -0
  7. package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +4 -3
  8. package/bin/exiftool_files/lib/Image/ExifTool/Import.pm +7 -3
  9. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +4 -3
  10. package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +3 -4
  11. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +2 -1
  12. package/bin/exiftool_files/lib/Image/ExifTool/Lytro.pm +2 -2
  13. package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +10 -2
  14. package/bin/exiftool_files/lib/Image/ExifTool/PhaseOne.pm +2 -1
  15. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +17 -6
  16. package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +88 -9
  17. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +6 -1
  18. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +14 -9
  19. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +40 -23
  20. package/bin/exiftool_files/lib/Image/ExifTool/WritePDF.pl +47 -21
  21. package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +16 -4
  22. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +16 -6
  23. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +19 -4
  24. package/bin/exiftool_files/lib/Image/ExifTool/XMPStruct.pl +15 -7
  25. package/bin/exiftool_files/lib/Image/ExifTool.pm +37 -12
  26. package/bin/exiftool_files/lib/Image/ExifTool.pod +31 -8
  27. package/bin/exiftool_files/readme_windows.txt +8 -13
  28. package/bin/exiftool_files/windows_exiftool.txt +32 -10
  29. package/package.json +7 -7
@@ -11,7 +11,7 @@ use strict;
11
11
  use warnings;
12
12
  require 5.004;
13
13
 
14
- my $version = '12.97';
14
+ my $version = '13.00';
15
15
 
16
16
  # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
17
17
  my $exePath;
@@ -47,6 +47,8 @@ sub PrintCSV();
47
47
  sub AddGroups($$$$);
48
48
  sub ConvertBinary($);
49
49
  sub IsEqual($$);
50
+ sub Printable($);
51
+ sub LengthUTF8($);
50
52
  sub Infile($;$);
51
53
  sub AddSetTagsFile($;$);
52
54
  sub Warning($$);
@@ -142,6 +144,7 @@ my $csvAdd; # flag to add CSV information to existing lists
142
144
  my $csvDelim; # delimiter for CSV files
143
145
  my $csvSaveCount; # save counter for last CSV file loaded
144
146
  my $deleteOrig; # 0=restore original files, 1=delete originals, 2=delete w/o asking
147
+ my $diff; # file name for comparing differences
145
148
  my $disableOutput; # flag to disable normal output
146
149
  my $doSetFileName; # flag set if FileName may be written
147
150
  my $doUnzip; # flag to extract info from .gz and .bz2 files
@@ -248,11 +251,13 @@ my %optArgs = (
248
251
  '-csvdelim' => 1,
249
252
  '-d' => 1, '-dateformat' => 1,
250
253
  '-D' => 0, # necessary to avoid matching lower-case equivalent
254
+ '-diff' => 1,
251
255
  '-echo' => 1, '-echo#' => 1,
252
256
  '-efile' => 1, '-efile#' => 1, '-efile!' => 1, '-efile#!' => 1,
253
257
  '-ext' => 1, '--ext' => 1, '-ext+' => 1, '--ext+' => 1,
254
258
  '-extension' => 1, '--extension' => 1, '-extension+' => 1, '--extension+' => 1,
255
259
  '-fileorder' => 1, '-fileorder#' => 1,
260
+ '-file#' => 1,
256
261
  '-geotag' => 1,
257
262
  '-globaltimeshift' => 1,
258
263
  '-i' => 1, '-ignore' => 1,
@@ -324,7 +329,7 @@ sub Exit {
324
329
  exit shift;
325
330
  }
326
331
  # my warning and error routines (NEVER say "die"!)
327
- sub Warn {
332
+ sub Warn {
328
333
  if ($quiet < 2 or $_[0] =~ /^Error/) {
329
334
  my $oldWarn = $SIG{'__WARN__'};
330
335
  delete $SIG{'__WARN__'};
@@ -485,6 +490,7 @@ undef $comma;
485
490
  undef $csv;
486
491
  undef $csvAdd;
487
492
  undef $deleteOrig;
493
+ undef $diff;
488
494
  undef $disableOutput;
489
495
  undef $doSetFileName;
490
496
  undef $doUnzip;
@@ -956,6 +962,11 @@ for (;;) {
956
962
  next;
957
963
  }
958
964
  (/^D$/ or $a eq 'decimal') and $showTagID = 'D', next;
965
+ if (/^diff$/i) {
966
+ $diff = shift;
967
+ defined $diff or Error("Expecting file name for -$_ option\n"), $badCmd=1;
968
+ next;
969
+ }
959
970
  /^delete_original(!?)$/i and $deleteOrig = ($1 ? 2 : 1), next;
960
971
  /^list_dir$/i and $listDir = 1, next;
961
972
  (/^e$/ or $a eq '-composite') and $mt->Options(Composite => 0), next;
@@ -1498,8 +1509,11 @@ if ($overwriteOrig > 1 and $outOpt) {
1498
1509
  next;
1499
1510
  }
1500
1511
 
1501
- if ($tagOut and ($csv or %printFmt or $tabFormat or $xml or ($verbose and $html))) {
1502
- Warn "Sorry, -W may not be combined with -csv, -htmlDump, -j, -p, -t or -X\n";
1512
+ if (($tagOut or defined $diff) and ($csv or $json or %printFmt or $tabFormat or $xml or
1513
+ ($verbose and $html)))
1514
+ {
1515
+ my $opt = $tagOut ? '-W' : '-diff';
1516
+ Warn "Sorry, $opt may not be combined with -csv, -htmlDump, -j, -p, -t or -X\n";
1503
1517
  $rtnVal = 1;
1504
1518
  next;
1505
1519
  }
@@ -1754,9 +1768,14 @@ if (@newValues) {
1754
1768
  $rtnVal = 1;
1755
1769
  next;
1756
1770
  }
1757
- if ($isWriting and @tags and not $outOpt) {
1758
- my ($tg, $s) = @tags > 1 ? ("$tags[0] ...", 's') : ($tags[0], '');
1759
- Warn "Ignored superfluous tag name$s or invalid option$s: -$tg\n";
1771
+ if ($isWriting) {
1772
+ if (defined $diff) {
1773
+ Error "Can't use -diff option when writing tags\n";
1774
+ next;
1775
+ } elsif (@tags and not $outOpt) {
1776
+ my ($tg, $s) = @tags > 1 ? ("$tags[0] ...", 's') : ($tags[0], '');
1777
+ Warn "Ignored superfluous tag name$s or invalid option$s: -$tg\n";
1778
+ }
1760
1779
  }
1761
1780
  # save current state of new values if setting values from target file
1762
1781
  # or if we may be translating to a different format
@@ -1801,8 +1820,7 @@ if ($outOpt) {
1801
1820
  $type = Image::ExifTool::GetFileExtension($outOpt);
1802
1821
  $type = uc($outOpt) unless defined $type;
1803
1822
  }
1804
- Warn "Can't write $type files\n";
1805
- $rtnVal = 1;
1823
+ Error "Can't write $type files\n";
1806
1824
  next;
1807
1825
  }
1808
1826
  $scanWritable = $type unless CanCreate($type);
@@ -1900,10 +1918,7 @@ if (@dbKeys) {
1900
1918
  # process all specified files
1901
1919
  ProcessFiles($mt);
1902
1920
 
1903
- if ($filtered and not $validFile) {
1904
- Warn "No file with specified extension\n";
1905
- $rtnVal = 1;
1906
- }
1921
+ Error "No file with specified extension\n" if $filtered and not $validFile;
1907
1922
 
1908
1923
  # print CSV information if necessary
1909
1924
  PrintCSV() if $csv and not $isWriting;
@@ -2011,7 +2026,7 @@ Exit $rtnValApp; # all done
2011
2026
  sub GetImageInfo($$)
2012
2027
  {
2013
2028
  my ($et, $orig) = @_;
2014
- my (@foundTags, $info, $file, $ind, $g8);
2029
+ my (@foundTags, @found2, $info, $info2, $et2, $file, $file2, $ind, $g8);
2015
2030
 
2016
2031
  # set window title for this file if necessary
2017
2032
  if (defined $windowTitle) {
@@ -2148,7 +2163,7 @@ sub GetImageInfo($$)
2148
2163
  }
2149
2164
  # can't make use of $info if verbose because we must reprocess
2150
2165
  # the file anyway to generate the verbose output
2151
- undef $info if $verbose or defined $fastCondition;
2166
+ undef $info if $verbose or defined $fastCondition or defined $diff;
2152
2167
  } elsif ($file =~ s/^(\@JSON:)(.*)/$1/) {
2153
2168
  # read JSON file from command line
2154
2169
  my $dat = $2;
@@ -2180,7 +2195,7 @@ sub GetImageInfo($$)
2180
2195
 
2181
2196
  my $lineCount = 0;
2182
2197
  my ($fp, $outfile, $append);
2183
- if ($textOut and ($verbose or $et->Options('PrintCSV')) and not $tagOut) {
2198
+ if ($textOut and ($verbose or $et->Options('PrintCSV')) and not ($tagOut or defined $diff)) {
2184
2199
  ($fp, $outfile, $append) = OpenOutputFile($orig);
2185
2200
  $fp or EFile($file), ++$countBad, return;
2186
2201
  # delete file if we exit prematurely (unless appending)
@@ -2225,7 +2240,7 @@ sub GetImageInfo($$)
2225
2240
  require Image::ExifTool::HTML;
2226
2241
  my $f = Image::ExifTool::HTML::EscapeHTML($file);
2227
2242
  print "<!-- $f -->\n";
2228
- } elsif (not ($json or $xml)) {
2243
+ } elsif (not ($json or $xml or defined $diff)) {
2229
2244
  $o = \*STDOUT if ($multiFile and not $quiet) or $progress;
2230
2245
  }
2231
2246
  }
@@ -2254,10 +2269,37 @@ sub GetImageInfo($$)
2254
2269
  } else {
2255
2270
  @foundTags = @tags;
2256
2271
  }
2272
+ if (defined $diff) {
2273
+ $file2 = FilenameSPrintf($diff, $orig);
2274
+ if ($file eq $file2) {
2275
+ Warn "Error: Diffing file with itself - $file2\n";
2276
+ EFile($file);
2277
+ ++$countBad;
2278
+ return;
2279
+ }
2280
+ if ($et->Exists($file2)) {
2281
+ $showGroup = 1 unless defined $showGroup;
2282
+ $allGroup = 1 unless defined $allGroup;
2283
+ $et->Options(Duplicates => 1, Sort => "Group$showGroup", Verbose => 0);
2284
+ $et2 = Image::ExifTool->new;
2285
+ $et2->Options(%{$$et{OPTIONS}});
2286
+ @found2 = @foundTags;
2287
+ $info2 = $et2->ImageInfo($file2, \@found2);
2288
+ } else {
2289
+ $info2 = { Error => "Diff file not found" };
2290
+ }
2291
+ if ($$info2{Error}) {
2292
+ Warn "Error: $$info2{Error} - $file2\n";
2293
+ EFile($file);
2294
+ ++$countBad;
2295
+ return;
2296
+ }
2297
+ }
2257
2298
  # extract the information
2258
2299
  $info = $et->ImageInfo(Infile($pipe), \@foundTags);
2259
2300
  $et->Options(Duplicates => $oldDups);
2260
2301
  }
2302
+
2261
2303
  # all done now if we already wrote output text file (eg. verbose option)
2262
2304
  if ($fp) {
2263
2305
  if (defined $outfile) {
@@ -2271,7 +2313,7 @@ sub GetImageInfo($$)
2271
2313
  }
2272
2314
  }
2273
2315
  if ($info->{Error}) {
2274
- Warn "Error: $info->{Error} - $file\n";
2316
+ Warn "Error: $$info{Error} - $file\n";
2275
2317
  EFile($file);
2276
2318
  ++$countBad;
2277
2319
  return;
@@ -2295,6 +2337,105 @@ sub GetImageInfo($$)
2295
2337
  $tmpText = $outfile unless $append;
2296
2338
  }
2297
2339
 
2340
+ # print differences if requested
2341
+ if (defined $diff) {
2342
+ my (%done2, $wasDiff, @diffs, @groupTags2);
2343
+ my $v = $verbose || 0;
2344
+ print $fp "======== diff < $file > $file2\n";
2345
+ my ($g2, $same) = (0, 0); # start with $g2 false, but not equal to '' to avoid infinite loop
2346
+ for (;;) {
2347
+ my $tag = shift @foundTags;
2348
+ my ($g, $tag2);
2349
+ if (defined $tag) {
2350
+ $g = $et->GetGroup($tag, $showGroup);
2351
+ } else {
2352
+ for (;;) {
2353
+ $tag2 = shift @found2;
2354
+ defined $tag2 or $g = '', last;
2355
+ $done2{$tag2} or $g = $et2->GetGroup($tag2, $showGroup), last;
2356
+ }
2357
+ }
2358
+ if ($g ne $g2) {
2359
+ my $t2;
2360
+ # add any outstanding tags from diff file not yet handled in previous group ($g2)
2361
+ foreach $t2 (@groupTags2) {
2362
+ next if $done2{$t2};
2363
+ my $val2 = $et2->GetValue($t2);
2364
+ next unless defined $val2;
2365
+ my $name = $outFormat < 1 ? $et2->GetDescription($t2) : GetTagName($t2);
2366
+ my $len = LengthUTF8($name);
2367
+ my $pad = $outFormat < 2 ? ' ' x ($len < 32 ? 32 - $len : 0) : '';
2368
+ if ($allGroup) {
2369
+ my $grp = "[$g2]";
2370
+ $grp .= ' ' x (15 - length($grp)) if length($grp) < 15 and $outFormat < 2;
2371
+ push @diffs, sprintf "> %s %s%s: %s\n", $grp, $name, $pad, Printable($val2);
2372
+ } else {
2373
+ push @diffs, sprintf "> %s%s: %s\n", $name, $pad, Printable($val2);
2374
+ }
2375
+ $done2{$t2} = 1;
2376
+ }
2377
+ my $str = '';
2378
+ $v and ($same or $v > 1) and $str = " ($same same tag" . ($same==1 ? '' : 's') . ')';
2379
+ if (not $allGroup) {
2380
+ print $fp "---- $g2 ----$str\n" if $g2 and ($str or @diffs);
2381
+ } elsif ($str and $g2) {
2382
+ printf $fp " %-13s%s\n", $g2, $str;
2383
+ }
2384
+ # print all differences for this group
2385
+ @diffs and print($fp @diffs), $wasDiff = 1, @diffs = ();
2386
+ last unless $g;
2387
+ ($g2, $same) = ($g, 0);
2388
+ # build list of all tags in the new group of the diff file
2389
+ @groupTags2 = ();
2390
+ foreach $t2 (@found2) {
2391
+ $done2{$t2} or $g ne $et2->GetGroup($t2, $showGroup) or push @groupTags2, $t2;
2392
+ }
2393
+ }
2394
+ next unless defined $tag;
2395
+ my $val = $et->GetValue($tag);
2396
+ next unless defined $val; # (just in case)
2397
+ my $name = GetTagName($tag);
2398
+ # get matching tag key from diff file
2399
+ my @tags2 = grep /^$name( |$)/, @groupTags2;
2400
+ $name = $et->GetDescription($tag) if $outFormat < 1;
2401
+ my ($val2, $t2);
2402
+ foreach $t2 (@tags2) {
2403
+ next if $done2{$t2};
2404
+ $tag2 = $t2;
2405
+ $val2 = $et2->GetValue($t2);
2406
+ last;
2407
+ }
2408
+ if (defined $val2 and IsEqual($val, $val2)) {
2409
+ ++$same;
2410
+ } else {
2411
+ my $len = LengthUTF8($name);
2412
+ my $pad = $outFormat < 2 ? ' ' x ($len < 32 ? 32 - $len : 0) : '';
2413
+ if ($allGroup) {
2414
+ my $grp = "[$g]";
2415
+ $grp .= ' ' x (15 - length($grp)) if length($grp) < 15 and $outFormat < 2;
2416
+ push @diffs, sprintf "< %s %s%s: %s\n", $grp, $name, $pad, Printable($val);
2417
+ if (defined $val2) {
2418
+ $grp = ' ' x length($grp), $name = ' ' x $len if $v < 3;
2419
+ push @diffs, sprintf "> %s %s%s: %s\n", $grp, $name, $pad, Printable($val2);
2420
+ }
2421
+ } else {
2422
+ push @diffs, sprintf "< %s%s: %s\n", $name, $pad, Printable($val);
2423
+ $name = ' ' x $len if $v < 3;
2424
+ push @diffs, sprintf "> %s%s %s\n", $name, $pad, Printable($val2) if defined $val2;
2425
+ }
2426
+ }
2427
+ $done2{$tag2} = 1 if defined $tag2;
2428
+ }
2429
+ print $fp "(no metadata differences)\n" unless $wasDiff;
2430
+ undef $tmpText;
2431
+ if (defined $outfile) {
2432
+ ++$created{$outfile};
2433
+ close($fp);
2434
+ undef $tmpText;
2435
+ }
2436
+ ++$count;
2437
+ return;
2438
+ }
2298
2439
  # restore state of comma flag for this file if appending
2299
2440
  $comma = $outComma{$outfile} if $append and ($textOverwrite & 0x02);
2300
2441
 
@@ -2763,21 +2904,7 @@ TAG: foreach $tag (@foundTags) {
2763
2904
  # pad description to a constant length
2764
2905
  # (get actual character length when using alternate languages
2765
2906
  # because these descriptions may contain UTF8-encoded characters)
2766
- my $padLen = $wid;
2767
- if (not $fixLen) {
2768
- $padLen -= length $desc;
2769
- } elsif ($fixLen == 1) {
2770
- $padLen -= length Encode::decode_utf8($desc);
2771
- } else {
2772
- my $gcstr = eval { Unicode::GCString->new(Encode::decode_utf8($desc)) };
2773
- if ($gcstr) {
2774
- $padLen -= $gcstr->columns;
2775
- } else {
2776
- $padLen -= length Encode::decode_utf8($desc);
2777
- Warning($et, 'Unicode::GCString problem. Columns may be misaligned');
2778
- $fixLen = 1;
2779
- }
2780
- }
2907
+ my $padLen = $wid - LengthUTF8($desc);
2781
2908
  $padLen = 0 if $padLen < 0;
2782
2909
  $buff .= $desc . (' ' x $padLen) . ": $val\n";
2783
2910
  } elsif ($outFormat == 2) {
@@ -3008,7 +3135,7 @@ sub SetImageInfo($$$)
3008
3135
  }
3009
3136
  $found = 1;
3010
3137
  $verbose and print $vout "Setting new values from $csv database\n";
3011
- foreach $tag (sort keys %$csvInfo) {
3138
+ foreach $tag (OrderedKeys($csvInfo)) {
3012
3139
  next if $tag =~ /\b(SourceFile|Directory|FileName)$/i; # don't write these
3013
3140
  my ($rtn, $wrn) = $et->SetNewValue($tag, $$csvInfo{$tag},
3014
3141
  Protected => 1, AddValue => $csvAdd,
@@ -3424,8 +3551,7 @@ sub FormatXML($$$)
3424
3551
  } elsif (ref $val eq 'HASH') {
3425
3552
  $gt = " rdf:parseType='Resource'>";
3426
3553
  my $val2 = '';
3427
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
3428
- foreach (@keys) {
3554
+ foreach (OrderedKeys($val)) {
3429
3555
  # (some variable-namespace XML structure fields may have a different group)
3430
3556
  my ($ns, $tg) = ($grp, $_);
3431
3557
  if (/^(.*?):(.*)/) {
@@ -3509,7 +3635,7 @@ sub FormatJSON($$$;$)
3509
3635
  print $fp $bra;
3510
3636
  foreach (@$val) {
3511
3637
  print $fp ',' if $comma;
3512
- FormatJSON($fp, $_, $ind);
3638
+ FormatJSON($fp, $_, $ind, $quote);
3513
3639
  $comma = 1,
3514
3640
  }
3515
3641
  print $fp $ket,
@@ -3517,8 +3643,7 @@ sub FormatJSON($$$;$)
3517
3643
  } elsif (ref $val eq 'HASH') {
3518
3644
  my ($bra, $ket, $sep) = $json == 1 ? ('{','}',':') : ('Array(',')',' =>');
3519
3645
  print $fp $bra;
3520
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
3521
- foreach (@keys) {
3646
+ foreach (OrderedKeys($val)) {
3522
3647
  print $fp ',' if $comma;
3523
3648
  my $key = EscapeJSON($_, 1);
3524
3649
  print $fp qq(\n$ind $key$sep );
@@ -3526,7 +3651,7 @@ sub FormatJSON($$$;$)
3526
3651
  if ($showTagID and $_ eq 'id' and $showTagID eq 'H' and $$val{$_} =~ /^\d+\.\d+$/) {
3527
3652
  print $fp qq{"$$val{$_}"};
3528
3653
  } else {
3529
- FormatJSON($fp, $$val{$_}, "$ind ");
3654
+ FormatJSON($fp, $$val{$_}, "$ind ", $quote);
3530
3655
  }
3531
3656
  $comma = 1,
3532
3657
  }
@@ -3675,6 +3800,59 @@ sub IsEqual($$)
3675
3800
  return 1;
3676
3801
  }
3677
3802
 
3803
+ #------------------------------------------------------------------------------
3804
+ # Get the printable rendition of a value
3805
+ # Inputs: 0) value (may be a reference)
3806
+ # Returns: de-referenced value
3807
+ sub Printable($)
3808
+ {
3809
+ my $val = shift;
3810
+ if (ref $val) {
3811
+ if ($structOpt) {
3812
+ require Image::ExifTool::XMP;
3813
+ $val = Image::ExifTool::XMP::SerializeStruct($mt, $val);
3814
+ } elsif (ref $val eq 'ARRAY') {
3815
+ $val = join($listSep, @$val);
3816
+ } elsif (ref $val eq 'SCALAR') {
3817
+ $val = '(Binary data '.length($$val).' bytes)';
3818
+ }
3819
+ }
3820
+ if ($escapeC) {
3821
+ $val =~ s/([\0-\x1f\\\x7f])/$escC{$1} || sprintf('\x%.2x', ord $1)/eg;
3822
+ } else {
3823
+ # translate unprintable chars in value and remove trailing spaces
3824
+ $val =~ tr/\x01-\x1f\x7f/./;
3825
+ $val =~ s/\x00//g;
3826
+ $val =~ s/\s+$//;
3827
+ }
3828
+ return $val;
3829
+ }
3830
+
3831
+ #------------------------------------------------------------------------------
3832
+ # Get character length of a UTF-8 string
3833
+ # Inputs: 0) string
3834
+ # Returns: number of characters (not bytes) in the UTF-8 string
3835
+ sub LengthUTF8($)
3836
+ {
3837
+ my $str = shift;
3838
+ my $len;
3839
+ if (not $fixLen) {
3840
+ $len = length $str;
3841
+ } elsif ($fixLen == 1) {
3842
+ $len = length Encode::decode_utf8($str);
3843
+ } else {
3844
+ my $gcstr = eval { Unicode::GCString->new(Encode::decode_utf8($str)) };
3845
+ if ($gcstr) {
3846
+ $len = $gcstr->columns;
3847
+ } else {
3848
+ $len = length Encode::decode_utf8($str);
3849
+ Warning($mt, 'Unicode::GCString problem. Columns may be misaligned');
3850
+ $fixLen = 1;
3851
+ }
3852
+ }
3853
+ return $len;
3854
+ }
3855
+
3678
3856
  #------------------------------------------------------------------------------
3679
3857
  # Add tag list for copying tags from specified file
3680
3858
  # Inputs: 0) set tags file name (or FMT), 1) options for SetNewValuesFromFile()
@@ -4648,7 +4826,9 @@ sub Help()
4648
4826
  my $docFile = "$Image::ExifTool::exeDir/exiftool_files/windows_exiftool.txt";
4649
4827
  # try backslashes first if it seems we may be running in cmd.exe
4650
4828
  $docFile =~ tr/\//\\/ if $ENV{ComSpec} or $docFile =~ /\\/;
4651
- system(qq{more < "$docFile"}) and warn "Error running more $docFile\n";
4829
+ # trap warnings and run in eval to avoid Perl bug which gives "Can't spawn" warning on ^C
4830
+ local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] };
4831
+ eval { system(qq{more < "$docFile"}) };
4652
4832
  }
4653
4833
 
4654
4834
  # end
@@ -41,7 +41,7 @@ require 5.002;
41
41
  require Exporter;
42
42
 
43
43
  use vars qw($VERSION @ISA @EXPORT_OK);
44
- $VERSION = '1.12';
44
+ $VERSION = '1.13';
45
45
  @ISA = qw(Exporter);
46
46
 
47
47
  sub Read($$$);
@@ -158,7 +158,10 @@ sub Seek($$;$)
158
158
  $self->Slurp(); # read whole file into buffer
159
159
  $newPos = $num + $self->{LEN}; # relative to end of file
160
160
  }
161
- if ($newPos >= 0) {
161
+ if ($newPos >= 0 and
162
+ # can't go backwards in unbuffered non-seekable file
163
+ (not $self->{NoBuffer} or $newPos >= $self->{POS}))
164
+ {
162
165
  $self->{POS} = $newPos;
163
166
  $rtnVal = 1;
164
167
  }
@@ -14,7 +14,7 @@ use strict;
14
14
  use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
 
17
- $VERSION = '1.13';
17
+ $VERSION = '1.14';
18
18
 
19
19
  sub ProcessAPP12($$$);
20
20
  sub ProcessDucky($$$);
@@ -72,7 +72,7 @@ sub WriteDucky($$$);
72
72
  StrobeTime => { },
73
73
  Resolution => { },
74
74
  Protect => { },
75
- ConTake => { },
75
+ ContTake => { },
76
76
  ImageSize => { PrintConv => '$val=~tr/-/x/;$val' },
77
77
  ColorMode => { },
78
78
  Zoom => { },
@@ -278,6 +278,7 @@ sub ProcessAPP12($$$)
278
278
  $tagInfo = { Name => ucfirst $tag };
279
279
  # put in Camera group if information in "Camera" section
280
280
  $$tagInfo{Groups} = { 2 => 'Camera' } if $section =~ /camera/i;
281
+ $et->VPrint(0, $$et{INDENT}, "[adding APP12:$$tagInfo{Name}]\n");
281
282
  AddTagToTable($tagTablePtr, $tag, $tagInfo);
282
283
  }
283
284
  $et->FoundTag($tagInfo, $val);
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '4.81';
91
+ $VERSION = '4.82';
92
92
 
93
93
  # Note: Removed 'USM' from 'L' lenses since it is redundant - PH
94
94
  # (or is it? Ref 32 shows 5 non-USM L-type lenses)
@@ -6999,6 +6999,7 @@ my %ciMaxFocal = (
6999
6999
  314 => 'Canon RF 24-105mm F2.8 L IS USM Z', #42
7000
7000
  315 => 'Canon RF-S 10-18mm F4.5-6.3 IS STM', #42
7001
7001
  316 => 'Canon RF 35mm F1.4 L VCM', #42
7002
+ 317 => 'Canon RF-S 3.9mm F3.5 STM DUAL FISHEYE', #42
7002
7003
  318 => 'Canon RF 28-70mm F2.8 IS STM', #42
7003
7004
  # Note: add new RF lenses to %canonLensTypes with ID 61182
7004
7005
  },
@@ -2931,7 +2931,7 @@ my %opcodeInfo = (
2931
2931
  0xa433 => { Name => 'LensMake', Writable => 'string' }, #24
2932
2932
  0xa434 => { Name => 'LensModel', Writable => 'string' }, #24
2933
2933
  0xa435 => { Name => 'LensSerialNumber', Writable => 'string' }, #24
2934
- 0xa436 => { Name => 'Title', Writable => 'string', Avoid => 1 }, #33
2934
+ 0xa436 => { Name => 'ImageTitle', Writable => 'string' }, #33
2935
2935
  0xa437 => { Name => 'Photographer', Writable => 'string' }, #33
2936
2936
  0xa438 => { Name => 'ImageEditor', Writable => 'string' }, #33
2937
2937
  0xa439 => { Name => 'CameraFirmware', Writable => 'string' }, #33
@@ -31,7 +31,7 @@ use vars qw($VERSION);
31
31
  use Image::ExifTool qw(:Public);
32
32
  use Image::ExifTool::GPS;
33
33
 
34
- $VERSION = '1.78';
34
+ $VERSION = '1.79';
35
35
 
36
36
  sub JITTER() { return 2 } # maximum time jitter
37
37
 
@@ -1127,8 +1127,9 @@ sub SetGeoValues($$;$)
1127
1127
  $iExt = $i1;
1128
1128
  }
1129
1129
  if (abs($time - $tn) > $geoMaxExtSecs) {
1130
- $err or $err = 'Time is too far from nearest GPS fix'.' '.abs($time-$tn).' > '.$geoMaxExtSecs;
1131
- $et->VPrint(2, ' Nearest fix: ', PrintFixTime($tn), "\n") if $verbose > 2;
1130
+ $err or $err = 'Time is too far from nearest GPS fix';
1131
+ $et->VPrint(2, ' Nearest fix: ', PrintFixTime($tn), ' (',
1132
+ int(abs $time-$tn), " sec away)\n") if $verbose > 2;
1132
1133
  $fix = { } if $$geotag{DateTimeOnly};
1133
1134
  } else {
1134
1135
  $fix = $$points{$tn};
@@ -12,7 +12,7 @@ require Exporter;
12
12
 
13
13
  use vars qw($VERSION @ISA @EXPORT_OK);
14
14
 
15
- $VERSION = '1.12';
15
+ $VERSION = '1.13';
16
16
  @ISA = qw(Exporter);
17
17
  @EXPORT_OK = qw(ReadCSV ReadJSON);
18
18
 
@@ -87,6 +87,7 @@ sub ReadCSV($$;$$)
87
87
  $fileInfo{$tags[$i]} =
88
88
  (defined $missingValue and $vals[$i] eq $missingValue) ? undef : $vals[$i];
89
89
  }
90
+ $fileInfo{_ordered_keys_} = \@tags;
90
91
  # figure out the file name to use
91
92
  if ($fileInfo{SourceFile}) {
92
93
  $$database{$fileInfo{SourceFile}} = \%fileInfo;
@@ -173,7 +174,7 @@ Tok: for (;;) {
173
174
  }
174
175
  # see what type of object this is
175
176
  if ($tok eq '{') { # object (hash)
176
- $rtnVal = { } unless defined $rtnVal;
177
+ $rtnVal = { _ordered_keys_ => [ ] } unless defined $rtnVal;
177
178
  for (;;) {
178
179
  # read "KEY":"VALUE" pairs
179
180
  unless (defined $key) {
@@ -189,6 +190,7 @@ Tok: for (;;) {
189
190
  $pos = pos $$buffPt;
190
191
  return undef unless defined $val;
191
192
  $$rtnVal{$key} = $val;
193
+ push @{$$rtnVal{_ordered_keys_}}, $key;
192
194
  undef $key;
193
195
  }
194
196
  # scan to delimiting ',' or bounding '}'
@@ -345,7 +347,9 @@ option for a list of valid character sets.
345
347
  These functions return an error string, or undef on success and populate the
346
348
  database hash with entries from the CSV or JSON file. Entries are keyed
347
349
  based on the SourceFile column of the CSV or JSON information, and are
348
- stored as hash lookups of tag name/value for each SourceFile.
350
+ stored as hash lookups of tag name/value for each SourceFile. The order
351
+ of the keys (CSV column order or order in a JSON object) is stored as an
352
+ ARRAY reference in a special "_ordered_keys_" element of this hash.
349
353
 
350
354
  =back
351
355
 
@@ -14,7 +14,7 @@ use strict;
14
14
  use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
 
17
- $VERSION = '1.08';
17
+ $VERSION = '1.09';
18
18
 
19
19
  # map for writing metadata to InDesign files (currently only write XMP)
20
20
  my %indMap = (
@@ -104,9 +104,10 @@ sub ProcessIND($$)
104
104
  # this must be null padding or we have a possible error
105
105
  last if $hdr =~ /^\0+$/;
106
106
  # (could be up to 4095 bytes of non-null garbage plus 4095 null bytes from ExifTool)
107
- $raf->Read($buff, 8196) and $hdr .= $buff;
107
+ $raf->Read($buff, 8192) and $hdr .= $buff;
108
+ my $n = length $hdr;
108
109
  $hdr =~ s/\0+$//; # remove trailing nulls
109
- if (length($hdr) > 4095) {
110
+ if ($n > 8190 or length($hdr) > 4095) {
110
111
  $err = 'Corrupt file or unsupported InDesign version';
111
112
  last;
112
113
  }
@@ -14,7 +14,7 @@ use vars qw($VERSION);
14
14
  use Image::ExifTool qw(:DataAccess :Utils);
15
15
  use Image::ExifTool::Import;
16
16
 
17
- $VERSION = '1.08';
17
+ $VERSION = '1.09';
18
18
 
19
19
  sub ProcessJSON($$);
20
20
  sub ProcessTag($$$$%);
@@ -92,8 +92,7 @@ sub ProcessTag($$$$%)
92
92
  return unless $et->Options('Struct') > 1;
93
93
  }
94
94
  # support hashes with ordered keys
95
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
96
- foreach (@keys) {
95
+ foreach (Image::ExifTool::OrderedKeys($val)) {
97
96
  my $tg = $tag . ((/^\d/ and $tag =~ /\d$/) ? '_' : '') . ucfirst;
98
97
  $tg =~ s/([^a-zA-Z])([a-z])/$1\U$2/g;
99
98
  ProcessTag($et, $tagTablePtr, $tg, $$val{$_}, %flags, Flat => 1);
@@ -155,7 +154,7 @@ sub ProcessJSON($$)
155
154
 
156
155
  # extract tags from JSON database
157
156
  foreach $key (sort keys %database) {
158
- foreach $tag (sort keys %{$database{$key}}) {
157
+ foreach $tag (Image::ExifTool::OrderedKeys($database{$key})) {
159
158
  my $val = $database{$key}{$tag};
160
159
  # (ignore SourceFile if generated automatically by ReadJSON)
161
160
  next if $tag eq 'SourceFile' and defined $val and $val eq '*';
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.40';
19
+ $VERSION = '1.41';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -574,6 +574,7 @@ my %j2cMarker = (
574
574
  2 => {
575
575
  Name => 'CompatibleBrands',
576
576
  Format => 'undef[$size-8]',
577
+ List => 1, # (for documentation only)
577
578
  # ignore any entry with a null, and return others as a list
578
579
  ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
579
580
  },
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::Import;
17
17
 
18
- $VERSION = '1.03';
18
+ $VERSION = '1.04';
19
19
 
20
20
  sub ExtractTags($$$);
21
21
 
@@ -106,7 +106,7 @@ sub ExtractTags($$$)
106
106
  my ($et, $meta, $parent) = @_;
107
107
  ref $meta eq 'HASH' or $et->Warn('Invalid LFP metadata'), return;
108
108
  my ($key, $val, $name, $tagTablePtr);
109
- foreach $key (sort keys %$meta) {
109
+ foreach $key (Image::ExifTool::OrderedKeys($meta)) {
110
110
  my $tag = $parent . ucfirst($key);
111
111
  foreach $val (ref $$meta{$key} eq 'ARRAY' ? @{$$meta{$key}} : $$meta{$key}) {
112
112
  ref $val eq 'HASH' and ExtractTags($et, $val, $tag), next;