exiftool_vendored 12.97.0 → 12.99.0

Sign up to get free protection for your applications and to get access to all the features.
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
  },