exiftool_vendored 12.97.0 → 12.99.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40145323efe802f85d7d63896f6625f4f814d99c0b7af905187c5e4723a2d280
4
- data.tar.gz: 507b11c61f464d9afab44d071d9da8e306378589cbe60b505b25336bce853bf7
3
+ metadata.gz: 857ae11921e86ed35a6ca857a912acf876501c139db5e5646b08ebab6a30d02c
4
+ data.tar.gz: 27bb568a8097d27f5519718fc010df5acddc3976d465bb872492f4bb29f03e7f
5
5
  SHA512:
6
- metadata.gz: 3cbeb84218d46abc790daa396a9b48adf8ce36b57c948fa854fa3c441b1d269b8ef5540363c2940ed620254156aee55e7814cf6ae38df9e28d5fc291ae119c2c
7
- data.tar.gz: '097ce6e1cb57f52cf953407ffca02f4f466a7d7662d20eed17d3355644aa2680fdb397c1fbf8032ed461f2b2f0d374e3a02e47cb95e50cddcb80e2938d3bed02'
6
+ metadata.gz: a60c7457c7f88cff4e5f7c78c95463f9f04961ccb67e318518c0b5d86fb9782f043dc422155e33e7309f6e1db3567545d5aab6a597c764f40ec642dde0973c10
7
+ data.tar.gz: e97a2b5852aa0fd3b8debe38ff11abe65c3850a681526cb40aa65e03dafabcdc0560371b544218918a32221a314b08c5fd0041184a5dcfe7b8f76ad26f9ea537
data/bin/Changes CHANGED
@@ -7,6 +7,33 @@ RSS feed: https://exiftool.org/rss.xml
7
7
  Note: The most recent production release is Version 12.76. (Other versions are
8
8
  considered development releases, and are not uploaded to MetaCPAN.)
9
9
 
10
+ Oct. 18, 2024 - Version 12.99
11
+
12
+ - Added -diff option to compare the metadata in two files
13
+ - Added a new Canon lens (thanks Norbert Wasser)
14
+ - Decode GPS from 70mai A810 dashcam videos
15
+ - Decode a new QuickTime tag
16
+ - Patched to recognize C2PA APP11 JUMBF header with incorrect byte order
17
+ written by buggy Microsoft software
18
+ - Patched to maintain order of entries in a JSON object when reading
19
+ - Patched to maintain order of CSV columns when setting tags from a CSV file
20
+ - Patched to maintain order of XMP lang-alt entries when writing/copying
21
+ - Fixed typo in an APP12 tag name
22
+ - API Changes:
23
+ - Structured values returned as HASH references with the Struct option may
24
+ contain a new "_ordered_keys_" entry used to preserve the order of the
25
+ entries
26
+ - Added the OrderedKeys method to
27
+ return the ordered or sorted keys from a returned structure value
28
+
29
+ Oct. 8, 2024 - Version 12.98
30
+
31
+ - Added write support for PDF files with huge offsets
32
+ - Added a number of new Sony LensType values (thanks Jos Roost)
33
+ - Require -v4 or higher to output "JPG RST" lines
34
+ - Patched problem with -fast option when reading HEIC file via a pipe
35
+ - Patched to avoid hang when reading some corrupted XMP
36
+
10
37
  Sept. 25, 2024 - Version 12.97
11
38
 
12
39
  - Added ability to ignore up to 4095 bytes of garbage at the end of an INDD
@@ -143,7 +170,7 @@ June 7, 2024 - Version 12.86
143
170
  - Patched some Olympus WB_RBLevels tags to allow 4 values to be written as per
144
171
  some newer models
145
172
  - Fixed issue when writing IPTC date tags with a date/time value containing
146
- subseconds with 4 or more digits
173
+ subseconds with 4 or more digits
147
174
 
148
175
  May 21, 2024 - Version 12.85
149
176
 
data/bin/META.json CHANGED
@@ -50,5 +50,5 @@
50
50
  }
51
51
  },
52
52
  "release_status" : "stable",
53
- "version" : "12.97"
53
+ "version" : "12.99"
54
54
  }
data/bin/META.yml CHANGED
@@ -31,4 +31,4 @@ recommends:
31
31
  Time::HiRes: '0'
32
32
  requires:
33
33
  perl: '5.004'
34
- version: '12.97'
34
+ version: '12.99'
data/bin/README CHANGED
@@ -109,8 +109,8 @@ your home directory, then you would type the following commands in a
109
109
  terminal window to extract and run ExifTool:
110
110
 
111
111
  cd ~/Desktop
112
- gzip -dc Image-ExifTool-12.97.tar.gz | tar -xf -
113
- cd Image-ExifTool-12.97
112
+ gzip -dc Image-ExifTool-12.99.tar.gz | tar -xf -
113
+ cd Image-ExifTool-12.99
114
114
  ./exiftool t/images/ExifTool.jpg
115
115
 
116
116
  Note: These commands extract meta information from one of the test images.
@@ -82,7 +82,8 @@
82
82
  },
83
83
  # add more user-defined EXIF tags here...
84
84
  },
85
- # the Geotag feature writes these additional GPS tags if available:
85
+ # the Geotag feature writes GPSPitch and GPSRoll tags, but these
86
+ # aren't standard EXIF so we define custom tags here:
86
87
  'Image::ExifTool::GPS::Main' => {
87
88
  # Example 2. GPS:GPSPitch
88
89
  0xd000 => {
data/bin/exiftool CHANGED
@@ -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 = '12.99';
15
15
 
16
16
  # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
17
17
  my $exePath;
@@ -56,6 +56,8 @@ sub PrintCSV();
56
56
  sub AddGroups($$$$);
57
57
  sub ConvertBinary($);
58
58
  sub IsEqual($$);
59
+ sub Printable($);
60
+ sub LengthUTF8($);
59
61
  sub Infile($;$);
60
62
  sub AddSetTagsFile($;$);
61
63
  sub Warning($$);
@@ -150,6 +152,7 @@ my $csvAdd; # flag to add CSV information to existing lists
150
152
  my $csvDelim; # delimiter for CSV files
151
153
  my $csvSaveCount; # save counter for last CSV file loaded
152
154
  my $deleteOrig; # 0=restore original files, 1=delete originals, 2=delete w/o asking
155
+ my $diff; # file name for comparing differences
153
156
  my $disableOutput; # flag to disable normal output
154
157
  my $doSetFileName; # flag set if FileName may be written
155
158
  my $doUnzip; # flag to extract info from .gz and .bz2 files
@@ -256,11 +259,13 @@ my %optArgs = (
256
259
  '-csvdelim' => 1,
257
260
  '-d' => 1, '-dateformat' => 1,
258
261
  '-D' => 0, # necessary to avoid matching lower-case equivalent
262
+ '-diff' => 1,
259
263
  '-echo' => 1, '-echo#' => 1,
260
264
  '-efile' => 1, '-efile#' => 1, '-efile!' => 1, '-efile#!' => 1,
261
265
  '-ext' => 1, '--ext' => 1, '-ext+' => 1, '--ext+' => 1,
262
266
  '-extension' => 1, '--extension' => 1, '-extension+' => 1, '--extension+' => 1,
263
267
  '-fileorder' => 1, '-fileorder#' => 1,
268
+ '-file#' => 1,
264
269
  '-geotag' => 1,
265
270
  '-globaltimeshift' => 1,
266
271
  '-i' => 1, '-ignore' => 1,
@@ -332,7 +337,7 @@ sub Exit {
332
337
  exit shift;
333
338
  }
334
339
  # my warning and error routines (NEVER say "die"!)
335
- sub Warn {
340
+ sub Warn {
336
341
  if ($quiet < 2 or $_[0] =~ /^Error/) {
337
342
  my $oldWarn = $SIG{'__WARN__'};
338
343
  delete $SIG{'__WARN__'};
@@ -472,6 +477,7 @@ undef $comma;
472
477
  undef $csv;
473
478
  undef $csvAdd;
474
479
  undef $deleteOrig;
480
+ undef $diff;
475
481
  undef $disableOutput;
476
482
  undef $doSetFileName;
477
483
  undef $doUnzip;
@@ -943,6 +949,11 @@ for (;;) {
943
949
  next;
944
950
  }
945
951
  (/^D$/ or $a eq 'decimal') and $showTagID = 'D', next;
952
+ if (/^diff$/i) {
953
+ $diff = shift;
954
+ defined $diff or Error("Expecting file name for -$_ option\n"), $badCmd=1;
955
+ next;
956
+ }
946
957
  /^delete_original(!?)$/i and $deleteOrig = ($1 ? 2 : 1), next;
947
958
  /^list_dir$/i and $listDir = 1, next;
948
959
  (/^e$/ or $a eq '-composite') and $mt->Options(Composite => 0), next;
@@ -1501,8 +1512,11 @@ if ($overwriteOrig > 1 and $outOpt) {
1501
1512
  next;
1502
1513
  }
1503
1514
 
1504
- if ($tagOut and ($csv or %printFmt or $tabFormat or $xml or ($verbose and $html))) {
1505
- Warn "Sorry, -W may not be combined with -csv, -htmlDump, -j, -p, -t or -X\n";
1515
+ if (($tagOut or defined $diff) and ($csv or $json or %printFmt or $tabFormat or $xml or
1516
+ ($verbose and $html)))
1517
+ {
1518
+ my $opt = $tagOut ? '-W' : '-diff';
1519
+ Warn "Sorry, $opt may not be combined with -csv, -htmlDump, -j, -p, -t or -X\n";
1506
1520
  $rtnVal = 1;
1507
1521
  next;
1508
1522
  }
@@ -1757,9 +1771,14 @@ if (@newValues) {
1757
1771
  $rtnVal = 1;
1758
1772
  next;
1759
1773
  }
1760
- if ($isWriting and @tags and not $outOpt) {
1761
- my ($tg, $s) = @tags > 1 ? ("$tags[0] ...", 's') : ($tags[0], '');
1762
- Warn "Ignored superfluous tag name$s or invalid option$s: -$tg\n";
1774
+ if ($isWriting) {
1775
+ if (defined $diff) {
1776
+ Error "Can't use -diff option when writing tags\n";
1777
+ next;
1778
+ } elsif (@tags and not $outOpt) {
1779
+ my ($tg, $s) = @tags > 1 ? ("$tags[0] ...", 's') : ($tags[0], '');
1780
+ Warn "Ignored superfluous tag name$s or invalid option$s: -$tg\n";
1781
+ }
1763
1782
  }
1764
1783
  # save current state of new values if setting values from target file
1765
1784
  # or if we may be translating to a different format
@@ -1804,8 +1823,7 @@ if ($outOpt) {
1804
1823
  $type = Image::ExifTool::GetFileExtension($outOpt);
1805
1824
  $type = uc($outOpt) unless defined $type;
1806
1825
  }
1807
- Warn "Can't write $type files\n";
1808
- $rtnVal = 1;
1826
+ Error "Can't write $type files\n";
1809
1827
  next;
1810
1828
  }
1811
1829
  $scanWritable = $type unless CanCreate($type);
@@ -1903,10 +1921,7 @@ if (@dbKeys) {
1903
1921
  # process all specified files
1904
1922
  ProcessFiles($mt);
1905
1923
 
1906
- if ($filtered and not $validFile) {
1907
- Warn "No file with specified extension\n";
1908
- $rtnVal = 1;
1909
- }
1924
+ Error "No file with specified extension\n" if $filtered and not $validFile;
1910
1925
 
1911
1926
  # print CSV information if necessary
1912
1927
  PrintCSV() if $csv and not $isWriting;
@@ -2014,7 +2029,7 @@ Exit $rtnValApp; # all done
2014
2029
  sub GetImageInfo($$)
2015
2030
  {
2016
2031
  my ($et, $orig) = @_;
2017
- my (@foundTags, $info, $file, $ind, $g8);
2032
+ my (@foundTags, @found2, $info, $info2, $et2, $file, $file2, $ind, $g8);
2018
2033
 
2019
2034
  # set window title for this file if necessary
2020
2035
  if (defined $windowTitle) {
@@ -2151,7 +2166,7 @@ sub GetImageInfo($$)
2151
2166
  }
2152
2167
  # can't make use of $info if verbose because we must reprocess
2153
2168
  # the file anyway to generate the verbose output
2154
- undef $info if $verbose or defined $fastCondition;
2169
+ undef $info if $verbose or defined $fastCondition or defined $diff;
2155
2170
  } elsif ($file =~ s/^(\@JSON:)(.*)/$1/) {
2156
2171
  # read JSON file from command line
2157
2172
  my $dat = $2;
@@ -2183,7 +2198,7 @@ sub GetImageInfo($$)
2183
2198
 
2184
2199
  my $lineCount = 0;
2185
2200
  my ($fp, $outfile, $append);
2186
- if ($textOut and ($verbose or $et->Options('PrintCSV')) and not $tagOut) {
2201
+ if ($textOut and ($verbose or $et->Options('PrintCSV')) and not ($tagOut or defined $diff)) {
2187
2202
  ($fp, $outfile, $append) = OpenOutputFile($orig);
2188
2203
  $fp or EFile($file), ++$countBad, return;
2189
2204
  # delete file if we exit prematurely (unless appending)
@@ -2228,7 +2243,7 @@ sub GetImageInfo($$)
2228
2243
  require Image::ExifTool::HTML;
2229
2244
  my $f = Image::ExifTool::HTML::EscapeHTML($file);
2230
2245
  print "<!-- $f -->\n";
2231
- } elsif (not ($json or $xml)) {
2246
+ } elsif (not ($json or $xml or defined $diff)) {
2232
2247
  $o = \*STDOUT if ($multiFile and not $quiet) or $progress;
2233
2248
  }
2234
2249
  }
@@ -2257,10 +2272,37 @@ sub GetImageInfo($$)
2257
2272
  } else {
2258
2273
  @foundTags = @tags;
2259
2274
  }
2275
+ if (defined $diff) {
2276
+ $file2 = FilenameSPrintf($diff, $orig);
2277
+ if ($file eq $file2) {
2278
+ Warn "Error: Diffing file with itself - $file2\n";
2279
+ EFile($file);
2280
+ ++$countBad;
2281
+ return;
2282
+ }
2283
+ if ($et->Exists($file2)) {
2284
+ $showGroup = 1 unless defined $showGroup;
2285
+ $allGroup = 1 unless defined $allGroup;
2286
+ $et->Options(Duplicates => 1, Sort => "Group$showGroup", Verbose => 0);
2287
+ $et2 = Image::ExifTool->new;
2288
+ $et2->Options(%{$$et{OPTIONS}});
2289
+ @found2 = @foundTags;
2290
+ $info2 = $et2->ImageInfo($file2, \@found2);
2291
+ } else {
2292
+ $info2 = { Error => "Diff file not found" };
2293
+ }
2294
+ if ($$info2{Error}) {
2295
+ Warn "Error: $$info2{Error} - $file2\n";
2296
+ EFile($file);
2297
+ ++$countBad;
2298
+ return;
2299
+ }
2300
+ }
2260
2301
  # extract the information
2261
2302
  $info = $et->ImageInfo(Infile($pipe), \@foundTags);
2262
2303
  $et->Options(Duplicates => $oldDups);
2263
2304
  }
2305
+
2264
2306
  # all done now if we already wrote output text file (eg. verbose option)
2265
2307
  if ($fp) {
2266
2308
  if (defined $outfile) {
@@ -2274,7 +2316,7 @@ sub GetImageInfo($$)
2274
2316
  }
2275
2317
  }
2276
2318
  if ($info->{Error}) {
2277
- Warn "Error: $info->{Error} - $file\n";
2319
+ Warn "Error: $$info{Error} - $file\n";
2278
2320
  EFile($file);
2279
2321
  ++$countBad;
2280
2322
  return;
@@ -2298,6 +2340,105 @@ sub GetImageInfo($$)
2298
2340
  $tmpText = $outfile unless $append;
2299
2341
  }
2300
2342
 
2343
+ # print differences if requested
2344
+ if (defined $diff) {
2345
+ my (%done2, $wasDiff, @diffs, @groupTags2);
2346
+ my $v = $verbose || 0;
2347
+ print $fp "======== diff < $file > $file2\n";
2348
+ my ($g2, $same) = (0, 0); # start with $g2 false, but not equal to '' to avoid infinite loop
2349
+ for (;;) {
2350
+ my $tag = shift @foundTags;
2351
+ my ($g, $tag2);
2352
+ if (defined $tag) {
2353
+ $g = $et->GetGroup($tag, $showGroup);
2354
+ } else {
2355
+ for (;;) {
2356
+ $tag2 = shift @found2;
2357
+ defined $tag2 or $g = '', last;
2358
+ $done2{$tag2} or $g = $et2->GetGroup($tag2, $showGroup), last;
2359
+ }
2360
+ }
2361
+ if ($g ne $g2) {
2362
+ my $t2;
2363
+ # add any outstanding tags from diff file not yet handled in previous group ($g2)
2364
+ foreach $t2 (@groupTags2) {
2365
+ next if $done2{$t2};
2366
+ my $val2 = $et2->GetValue($t2);
2367
+ next unless defined $val2;
2368
+ my $name = $outFormat < 1 ? $et2->GetDescription($t2) : GetTagName($t2);
2369
+ my $len = LengthUTF8($name);
2370
+ my $pad = $outFormat < 2 ? ' ' x ($len < 32 ? 32 - $len : 0) : '';
2371
+ if ($allGroup) {
2372
+ my $grp = "[$g2]";
2373
+ $grp .= ' ' x (15 - length($grp)) if length($grp) < 15 and $outFormat < 2;
2374
+ push @diffs, sprintf "> %s %s%s: %s\n", $grp, $name, $pad, Printable($val2);
2375
+ } else {
2376
+ push @diffs, sprintf "> %s%s: %s\n", $name, $pad, Printable($val2);
2377
+ }
2378
+ $done2{$t2} = 1;
2379
+ }
2380
+ my $str = '';
2381
+ ($v > 1 or $same) and $str = " ($same same tag" . ($same==1 ? '' : 's') . ')';
2382
+ if (not $allGroup) {
2383
+ print $fp "---- $g2 ----$str\n" if $g2 and ($str or @diffs);
2384
+ } elsif ($str and $g2) {
2385
+ printf $fp " %-13s%s\n", $g2, $str;
2386
+ }
2387
+ # print all differences for this group
2388
+ @diffs and print($fp @diffs), $wasDiff = 1, @diffs = ();
2389
+ last unless $g;
2390
+ ($g2, $same) = ($g, 0);
2391
+ # build list of all tags in the new group of the diff file
2392
+ @groupTags2 = ();
2393
+ foreach $t2 (@found2) {
2394
+ $done2{$t2} or $g ne $et2->GetGroup($t2, $showGroup) or push @groupTags2, $t2;
2395
+ }
2396
+ }
2397
+ next unless defined $tag;
2398
+ my $val = $et->GetValue($tag);
2399
+ next unless defined $val; # (just in case)
2400
+ my $name = GetTagName($tag);
2401
+ # get matching tag key from diff file
2402
+ my @tags2 = grep /^$name( |$)/, @groupTags2;
2403
+ $name = $et->GetDescription($tag) if $outFormat < 1;
2404
+ my ($val2, $t2);
2405
+ foreach $t2 (@tags2) {
2406
+ next if $done2{$t2};
2407
+ $tag2 = $t2;
2408
+ $val2 = $et2->GetValue($t2);
2409
+ last;
2410
+ }
2411
+ if (defined $val2 and IsEqual($val, $val2)) {
2412
+ ++$same;
2413
+ } else {
2414
+ my $len = LengthUTF8($name);
2415
+ my $pad = $outFormat < 2 ? ' ' x ($len < 32 ? 32 - $len : 0) : '';
2416
+ if ($allGroup) {
2417
+ my $grp = "[$g]";
2418
+ $grp .= ' ' x (15 - length($grp)) if length($grp) < 15 and $outFormat < 2;
2419
+ push @diffs, sprintf "< %s %s%s: %s\n", $grp, $name, $pad, Printable($val);
2420
+ if (defined $val2) {
2421
+ $v < 3 and $grp = ' ' x length($grp), $name = ' ' x $len;
2422
+ push @diffs, sprintf "> %s %s%s: %s\n", $grp, $name, $pad, Printable($val2);
2423
+ }
2424
+ } else {
2425
+ push @diffs, sprintf "< %s%s: %s\n", $name, $pad, Printable($val);
2426
+ $v < 3 and $name = ' ' x $len;
2427
+ push @diffs, sprintf "> %s%s %s\n", $name, $pad, Printable($val2) if defined $val2;
2428
+ }
2429
+ }
2430
+ $done2{$tag2} = 1 if defined $tag2;
2431
+ }
2432
+ print $fp "(no metadata differences)\n" unless $wasDiff;
2433
+ undef $tmpText;
2434
+ if (defined $outfile) {
2435
+ ++$created{$outfile};
2436
+ close($fp);
2437
+ undef $tmpText;
2438
+ }
2439
+ ++$count;
2440
+ return;
2441
+ }
2301
2442
  # restore state of comma flag for this file if appending
2302
2443
  $comma = $outComma{$outfile} if $append and ($textOverwrite & 0x02);
2303
2444
 
@@ -2766,21 +2907,7 @@ TAG: foreach $tag (@foundTags) {
2766
2907
  # pad description to a constant length
2767
2908
  # (get actual character length when using alternate languages
2768
2909
  # because these descriptions may contain UTF8-encoded characters)
2769
- my $padLen = $wid;
2770
- if (not $fixLen) {
2771
- $padLen -= length $desc;
2772
- } elsif ($fixLen == 1) {
2773
- $padLen -= length Encode::decode_utf8($desc);
2774
- } else {
2775
- my $gcstr = eval { Unicode::GCString->new(Encode::decode_utf8($desc)) };
2776
- if ($gcstr) {
2777
- $padLen -= $gcstr->columns;
2778
- } else {
2779
- $padLen -= length Encode::decode_utf8($desc);
2780
- Warning($et, 'Unicode::GCString problem. Columns may be misaligned');
2781
- $fixLen = 1;
2782
- }
2783
- }
2910
+ my $padLen = $wid - LengthUTF8($desc);
2784
2911
  $padLen = 0 if $padLen < 0;
2785
2912
  $buff .= $desc . (' ' x $padLen) . ": $val\n";
2786
2913
  } elsif ($outFormat == 2) {
@@ -3011,7 +3138,7 @@ sub SetImageInfo($$$)
3011
3138
  }
3012
3139
  $found = 1;
3013
3140
  $verbose and print $vout "Setting new values from $csv database\n";
3014
- foreach $tag (sort keys %$csvInfo) {
3141
+ foreach $tag (OrderedKeys($csvInfo)) {
3015
3142
  next if $tag =~ /\b(SourceFile|Directory|FileName)$/i; # don't write these
3016
3143
  my ($rtn, $wrn) = $et->SetNewValue($tag, $$csvInfo{$tag},
3017
3144
  Protected => 1, AddValue => $csvAdd,
@@ -3427,8 +3554,7 @@ sub FormatXML($$$)
3427
3554
  } elsif (ref $val eq 'HASH') {
3428
3555
  $gt = " rdf:parseType='Resource'>";
3429
3556
  my $val2 = '';
3430
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
3431
- foreach (@keys) {
3557
+ foreach (OrderedKeys($val)) {
3432
3558
  # (some variable-namespace XML structure fields may have a different group)
3433
3559
  my ($ns, $tg) = ($grp, $_);
3434
3560
  if (/^(.*?):(.*)/) {
@@ -3520,8 +3646,7 @@ sub FormatJSON($$$;$)
3520
3646
  } elsif (ref $val eq 'HASH') {
3521
3647
  my ($bra, $ket, $sep) = $json == 1 ? ('{','}',':') : ('Array(',')',' =>');
3522
3648
  print $fp $bra;
3523
- my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
3524
- foreach (@keys) {
3649
+ foreach (OrderedKeys($val)) {
3525
3650
  print $fp ',' if $comma;
3526
3651
  my $key = EscapeJSON($_, 1);
3527
3652
  print $fp qq(\n$ind $key$sep );
@@ -3678,6 +3803,52 @@ sub IsEqual($$)
3678
3803
  return 1;
3679
3804
  }
3680
3805
 
3806
+ #------------------------------------------------------------------------------
3807
+ # Get the printable rendition of a value
3808
+ # Inputs: 0) value (may be a reference)
3809
+ # Returns: de-referenced value
3810
+ sub Printable($)
3811
+ {
3812
+ my $val = shift;
3813
+ if (ref $val) {
3814
+ if ($structOpt) {
3815
+ require Image::ExifTool::XMP;
3816
+ $val = Image::ExifTool::XMP::SerializeStruct($mt, $val);
3817
+ } elsif (ref $val eq 'ARRAY') {
3818
+ $val = join($listSep, @$val);
3819
+ } elsif (ref $val eq 'SCALAR') {
3820
+ $val = '(Binary data '.length($$val).' bytes)';
3821
+ }
3822
+ }
3823
+ $val =~ tr/\0-\x1f\x7f/./; # translate unprintable characters
3824
+ return $val;
3825
+ }
3826
+
3827
+ #------------------------------------------------------------------------------
3828
+ # Get character length of a UTF-8 string
3829
+ # Inputs: 0) string
3830
+ # Returns: number of characters (not bytes) in the UTF-8 string
3831
+ sub LengthUTF8($)
3832
+ {
3833
+ my $str = shift;
3834
+ my $len;
3835
+ if (not $fixLen) {
3836
+ $len = length $str;
3837
+ } elsif ($fixLen == 1) {
3838
+ $len = length Encode::decode_utf8($str);
3839
+ } else {
3840
+ my $gcstr = eval { Unicode::GCString->new(Encode::decode_utf8($str)) };
3841
+ if ($gcstr) {
3842
+ $len = $gcstr->columns;
3843
+ } else {
3844
+ $len = length Encode::decode_utf8($str);
3845
+ Warning($mt, 'Unicode::GCString problem. Columns may be misaligned');
3846
+ $fixLen = 1;
3847
+ }
3848
+ }
3849
+ return $len;
3850
+ }
3851
+
3681
3852
  #------------------------------------------------------------------------------
3682
3853
  # Add tag list for copying tags from specified file
3683
3854
  # Inputs: 0) set tags file name (or FMT), 1) options for SetNewValuesFromFile()
@@ -4867,6 +5038,7 @@ L<Other options|/Other options>
4867
5038
 
4868
5039
  L<Special features|/Special features>
4869
5040
 
5041
+ -diff FILE2 Compare metadata with another file
4870
5042
  -geotag TRKFILE Geotag images from specified GPS log
4871
5043
  -globalTimeShift SHIFT Shift all formatted date/time values
4872
5044
  -use MODULE Add features from plug-in module
@@ -5662,7 +5834,7 @@ with this command:
5662
5834
 
5663
5835
  produces output like this:
5664
5836
 
5665
- -- Generated by ExifTool 12.97 --
5837
+ -- Generated by ExifTool 12.99 --
5666
5838
  File: a.jpg - 2003:10:31 15:44:19
5667
5839
  (f/5.6, 1/60s, ISO 100)
5668
5840
  File: b.jpg - 2006:05:23 11:57:38
@@ -6204,9 +6376,10 @@ B<-fileNUM> option is used to read an alternate file and the corresponding
6204
6376
  family 8 group name is specified for the tag. See the B<-fileNUM> option
6205
6377
  details for more information.
6206
6378
 
6207
- 5) The B<-a> option has no effect on the evaluation of the expression, and
6208
- the values of duplicate tags are accessible only by specifying a group name
6209
- (such as a family 4 instance number, eg. C<$Copy1:TAG>, C<$Copy2:TAG>, etc).
6379
+ 5) The B<-a> (Duplicates) option is implied when B<-if> is used without a
6380
+ fast I<NUM>, and the values of duplicate tags are accessible by specifying a
6381
+ group name in the expression (such as a family 4 instance number, eg.
6382
+ C<$Copy1:TAG>, C<$Copy2:TAG>, etc).
6210
6383
 
6211
6384
  6) A special "OK" UserParam is available to test the success of the previous
6212
6385
  command when B<-execute> was used, and may be used like any other tag in the
@@ -6472,9 +6645,9 @@ B<-f> adds 'flags' and 'struct' attributes if applicable. The flags are
6472
6645
  formatted as a comma-separated list of the following possible values:
6473
6646
  Avoid, Binary, List, Mandatory, Permanent, Protected, Unknown and Unsafe
6474
6647
  (see the L<Tag Name documentation|Image::ExifTool::TagNames>). For XMP List
6475
- tags, the list type (Alt, Bag or Seq) is added to the flags, and flattened
6476
- structure tags are indicated by a Flattened flag with 'struct' giving the ID
6477
- of the parent structure.
6648
+ tags, the list type (Alt, Bag or Seq) is also given, and flattened structure
6649
+ tags are indicated by a Flattened flag with 'struct' giving the ID of the
6650
+ parent structure.
6478
6651
 
6479
6652
  Note that none of the B<-list> options require an input I<FILE>.
6480
6653
 
@@ -6496,6 +6669,23 @@ names, even if they begin with a dash (C<->).
6496
6669
 
6497
6670
  =over 5
6498
6671
 
6672
+ =item B<-diff> I<FILE2>
6673
+
6674
+ Compare metadata in I<FILE> with I<FILE2>. The I<FILE2> name may include
6675
+ filename formatting codes (see the B<-w> option). All extracted tags from
6676
+ the files are compared, but the extracted tags may be controlled by adding
6677
+ B<-TAG> or B<--TAG> options. For example, below is a command to compare all
6678
+ the same-named files in two different directories, ignoring the System tags:
6679
+
6680
+ exiftool DIR1 -diff DIR2/%f.%e --system:all
6681
+
6682
+ The B<-g> and B<-G> options may be used to organize the output by the
6683
+ specified family of groups, with B<-G1> being the default. The B<-a> option
6684
+ is implied. Adding B<-v> includes a count of the number of tags that are
6685
+ the same in each group. The following text formatting options are valid
6686
+ when B<-diff> is used: B<-c>, B<-charset>, B<-d>, B<-E>, B<-L>, B<-lang>,
6687
+ B<-n>, B<-s>, B<-sep>, B<-struct> and B<-w>.
6688
+
6499
6689
  =item B<-geotag> I<TRKFILE>
6500
6690
 
6501
6691
  Geotag images from the specified GPS track log file. Using the B<-geotag>
@@ -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
  },