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.
- package/bin/exiftool_files/exiftool.pl +221 -41
- package/bin/exiftool_files/lib/File/RandomAccess.pm +5 -2
- package/bin/exiftool_files/lib/Image/ExifTool/APP12.pm +3 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +4 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Import.pm +7 -3
- package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +4 -3
- package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +3 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Lytro.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +10 -2
- package/bin/exiftool_files/lib/Image/ExifTool/PhaseOne.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +17 -6
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +88 -9
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +6 -1
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +14 -9
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +40 -23
- package/bin/exiftool_files/lib/Image/ExifTool/WritePDF.pl +47 -21
- package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +16 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +16 -6
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +19 -4
- package/bin/exiftool_files/lib/Image/ExifTool/XMPStruct.pl +15 -7
- package/bin/exiftool_files/lib/Image/ExifTool.pm +37 -12
- package/bin/exiftool_files/lib/Image/ExifTool.pod +31 -8
- package/bin/exiftool_files/readme_windows.txt +8 -13
- package/bin/exiftool_files/windows_exiftool.txt +32 -10
- 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 = '
|
|
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
|
|
1502
|
-
|
|
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
|
|
1758
|
-
|
|
1759
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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 => '
|
|
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
|
|
Binary file
|
|
@@ -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.
|
|
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'
|
|
1131
|
-
$et->VPrint(2, ' Nearest fix: ', PrintFixTime($tn),
|
|
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.
|
|
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.
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
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.
|
|
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.
|
|
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 (
|
|
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;
|