exiftool_vendored 12.98.0 → 12.99.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +19 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/config_files/example.config +2 -1
- data/bin/exiftool +228 -39
- data/bin/lib/Image/ExifTool/APP12.pm +3 -2
- data/bin/lib/Image/ExifTool/Canon.pm +2 -1
- data/bin/lib/Image/ExifTool/Import.pm +7 -3
- data/bin/lib/Image/ExifTool/JSON.pm +3 -4
- data/bin/lib/Image/ExifTool/Lytro.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +11 -1
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +19 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +3 -1
- data/bin/lib/Image/ExifTool/TagNames.pod +5 -3
- data/bin/lib/Image/ExifTool/WriteXMP.pl +16 -4
- data/bin/lib/Image/ExifTool/Writer.pl +16 -6
- data/bin/lib/Image/ExifTool/XMPStruct.pl +15 -7
- data/bin/lib/Image/ExifTool.pm +24 -2
- data/bin/lib/Image/ExifTool.pod +31 -8
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 857ae11921e86ed35a6ca857a912acf876501c139db5e5646b08ebab6a30d02c
|
4
|
+
data.tar.gz: 27bb568a8097d27f5519718fc010df5acddc3976d465bb872492f4bb29f03e7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a60c7457c7f88cff4e5f7c78c95463f9f04961ccb67e318518c0b5d86fb9782f043dc422155e33e7309f6e1db3567545d5aab6a597c764f40ec642dde0973c10
|
7
|
+
data.tar.gz: e97a2b5852aa0fd3b8debe38ff11abe65c3850a681526cb40aa65e03dafabcdc0560371b544218918a32221a314b08c5fd0041184a5dcfe7b8f76ad26f9ea537
|
data/bin/Changes
CHANGED
@@ -7,6 +7,25 @@ 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
|
+
|
10
29
|
Oct. 8, 2024 - Version 12.98
|
11
30
|
|
12
31
|
- Added write support for PDF files with huge offsets
|
data/bin/META.json
CHANGED
data/bin/META.yml
CHANGED
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.
|
113
|
-
cd Image-ExifTool-12.
|
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
|
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.
|
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
|
1505
|
-
|
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
|
1761
|
-
|
1762
|
-
|
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
|
-
|
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
|
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:
|
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 (
|
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
|
-
|
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
|
-
|
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.
|
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
|
@@ -6497,6 +6669,23 @@ names, even if they begin with a dash (C<->).
|
|
6497
6669
|
|
6498
6670
|
=over 5
|
6499
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
|
+
|
6500
6689
|
=item B<-geotag> I<TRKFILE>
|
6501
6690
|
|
6502
6691
|
Geotag images from the specified GPS track log file. Using the B<-geotag>
|
@@ -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
|
},
|
@@ -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 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 '*';
|
@@ -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;
|
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
48
48
|
use Image::ExifTool::Exif;
|
49
49
|
use Image::ExifTool::GPS;
|
50
50
|
|
51
|
-
$VERSION = '3.
|
51
|
+
$VERSION = '3.04';
|
52
52
|
|
53
53
|
sub ProcessMOV($$;$);
|
54
54
|
sub ProcessKeys($$$);
|
@@ -901,6 +901,7 @@ my %userDefined = (
|
|
901
901
|
Writable => 1,
|
902
902
|
},
|
903
903
|
# '35AX'? - seen "AT" (Yada RoadCam Pro 4K dashcam)
|
904
|
+
cust => 'CustomInfo', # 70mai A810
|
904
905
|
);
|
905
906
|
|
906
907
|
# stuff seen in 'skip' atom (70mai Pro Plus+ MP4 videos)
|
@@ -3351,6 +3352,7 @@ my %userDefined = (
|
|
3351
3352
|
PrintConv => '"Track $val"',
|
3352
3353
|
},
|
3353
3354
|
# cdep (Structural Dependency QT tag?)
|
3355
|
+
# fall - ? int32u, seen: 2
|
3354
3356
|
);
|
3355
3357
|
|
3356
3358
|
# track aperture mode dimensions atoms
|
@@ -6744,6 +6746,13 @@ my %userDefined = (
|
|
6744
6746
|
Avoid => 1,
|
6745
6747
|
%iso8601Date,
|
6746
6748
|
},
|
6749
|
+
# (mdta)com.apple.quicktime.scene-illuminance
|
6750
|
+
'scene-illuminance' => {
|
6751
|
+
Name => 'SceneIlluminance',
|
6752
|
+
Notes => 'milli-lux',
|
6753
|
+
ValueConv => 'unpack("N", $val)',
|
6754
|
+
Writable => 0, # (don't make this writable because it is found in timed metadata)
|
6755
|
+
},
|
6747
6756
|
#
|
6748
6757
|
# seen in Apple ProRes RAW file
|
6749
6758
|
#
|
@@ -7393,6 +7402,7 @@ my %userDefined = (
|
|
7393
7402
|
# alac - 28 bytes
|
7394
7403
|
# adrm - AAX DRM atom? 148 bytes
|
7395
7404
|
# aabd - AAX unknown 17kB (contains 'aavd' strings)
|
7405
|
+
# dapa - ? 203 bytes
|
7396
7406
|
);
|
7397
7407
|
|
7398
7408
|
# AMR decode config box (ref 3)
|
@@ -109,7 +109,7 @@ my %insvLimit = (
|
|
109
109
|
The tags below are extracted from timed metadata in QuickTime and other
|
110
110
|
formats of video files when the ExtractEmbedded option is used. Although
|
111
111
|
most of these tags are combined into the single table below, ExifTool
|
112
|
-
currently reads
|
112
|
+
currently reads 78 different formats of timed GPS metadata from video files.
|
113
113
|
},
|
114
114
|
VARS => { NO_ID => 1 },
|
115
115
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
@@ -2163,9 +2163,26 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2163
2163
|
push(@xtra, $1 => $2), next;
|
2164
2164
|
}
|
2165
2165
|
|
2166
|
+
} elsif ($$dataPt =~ m/^.{30}A.{20}VV/) {
|
2167
|
+
|
2168
|
+
$debug and $et->FoundTag(GPSType => 17);
|
2169
|
+
# 70mai A810 dashcam (note: no timestamps in the samples I have)
|
2170
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 ed 01 00 00 [..@.freeGPS ....]
|
2171
|
+
# 0010: 03 00 ed 01 00 00 00 0f 00 00 70 08 00 00 41 66 [..........p...Af]
|
2172
|
+
# 0020: 13 7d 1e 3c 11 dc 03 5d 01 00 00 01 00 00 00 23 [.}.<...].......#]
|
2173
|
+
# 0030: 00 00 00 56 56 00 00 00 00 00 00 00 00 00 00 00 [...VV...........]
|
2174
|
+
# 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
2175
|
+
SetByteOrder('II');
|
2176
|
+
SetGPSDateTime($et, $tagTbl, $$dirInfo{SampleTime});
|
2177
|
+
$lat = Get32s($dataPt, 31) / 1e5;
|
2178
|
+
$lon = Get32s($dataPt, 35) / 1e5;
|
2179
|
+
$spd = Get32s($dataPt, 43); # (seems to be km/h but not confirmed)
|
2180
|
+
# offset 475 - int16u=N string[N] - some sort of settings?:
|
2181
|
+
# eg. "\x15\x00{pA:V,rA:V,sF:0,tF:2}"
|
2182
|
+
|
2166
2183
|
} else {
|
2167
2184
|
|
2168
|
-
$debug and $et->FoundTag(GPSType =>
|
2185
|
+
$debug and $et->FoundTag(GPSType => 18);
|
2169
2186
|
# (look for binary GPS as stored by Nextbase 512G, ref PH)
|
2170
2187
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
|
2171
2188
|
# 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
|
@@ -8686,7 +8686,6 @@ my %tagExists = (
|
|
8686
8686
|
'cont' => 1,
|
8687
8687
|
'contactnames' => 1,
|
8688
8688
|
'containerversion' => 1,
|
8689
|
-
'contake' => 1,
|
8690
8689
|
'contentbranding' => 1,
|
8691
8690
|
'contentdescribes' => 1,
|
8692
8691
|
'contentdescription' => 1,
|
@@ -8709,6 +8708,7 @@ my %tagExists = (
|
|
8709
8708
|
'contrastadjustment' => 1,
|
8710
8709
|
'contrastinfo' => 1,
|
8711
8710
|
'controller' => 1,
|
8711
|
+
'conttake' => 1,
|
8712
8712
|
'convergenceangle' => 1,
|
8713
8713
|
'convergencebaseimage' => 1,
|
8714
8714
|
'convergencedistance' => 1,
|
@@ -8820,6 +8820,7 @@ my %tagExists = (
|
|
8820
8820
|
'customfunctionsd30' => 1,
|
8821
8821
|
'customfunctionsd60' => 1,
|
8822
8822
|
'customfunctionsunknown' => 1,
|
8823
|
+
'custominfo' => 1,
|
8823
8824
|
'customsettingsd3' => 1,
|
8824
8825
|
'customsettingsd300' => 1,
|
8825
8826
|
'customsettingsd300s' => 1,
|
@@ -12014,6 +12015,7 @@ my %tagExists = (
|
|
12014
12015
|
'scenebalancealgorithmrevision' => 1,
|
12015
12016
|
'sceneclassification' => 1,
|
12016
12017
|
'scenecolorimetryestimates' => 1,
|
12018
|
+
'sceneilluminance' => 1,
|
12017
12019
|
'scheduleitemid' => 1,
|
12018
12020
|
'schemeinfo' => 1,
|
12019
12021
|
'schemetype' => 1,
|
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
|
|
12
12
|
=head1 TAG TABLES
|
13
13
|
|
14
14
|
The tables listed below give the names of all tags recognized by ExifTool.
|
15
|
-
They contain a total of
|
15
|
+
They contain a total of 28150 tags, with 17488 unique tag names.
|
16
16
|
|
17
17
|
B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
|
18
18
|
table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
|
@@ -26163,7 +26163,7 @@ from any tags found in this segment.
|
|
26163
26163
|
------ -------- --------
|
26164
26164
|
'Aperture' Aperture no
|
26165
26165
|
'ColorMode' ColorMode no
|
26166
|
-
'
|
26166
|
+
'ContTake' ContTake no
|
26167
26167
|
'ExpBias' ExposureCompensation no
|
26168
26168
|
'FNumber' FNumber no
|
26169
26169
|
'FWare' FirmwareVersion no
|
@@ -29846,6 +29846,7 @@ for the official QuickTime specification.
|
|
29846
29846
|
'PICT' PreviewPICT no
|
29847
29847
|
'_htc' HTCInfo QuickTime HTCInfo
|
29848
29848
|
'ardt' ARDroneFile no
|
29849
|
+
'cust' CustomInfo no
|
29849
29850
|
'frea' Kodak_frea Kodak frea
|
29850
29851
|
'free' KodakFree Kodak Free
|
29851
29852
|
Pittasoft QuickTime Pittasoft
|
@@ -29897,7 +29898,7 @@ for the official QuickTime specification.
|
|
29897
29898
|
The tags below are extracted from timed metadata in QuickTime and other
|
29898
29899
|
formats of video files when the ExtractEmbedded option is used. Although
|
29899
29900
|
most of these tags are combined into the single table below, ExifTool
|
29900
|
-
currently reads
|
29901
|
+
currently reads 78 different formats of timed GPS metadata from video files.
|
29901
29902
|
|
29902
29903
|
Tag Name Writable
|
29903
29904
|
-------- --------
|
@@ -30163,6 +30164,7 @@ changed via the config file.
|
|
30163
30164
|
'producer' Producer yes
|
30164
30165
|
'publisher' Publisher yes
|
30165
30166
|
'rating.user' UserRating yes
|
30167
|
+
'scene-illuminance' SceneIlluminance no
|
30166
30168
|
'software' Software yes
|
30167
30169
|
'still-image-time' StillImageTime no
|
30168
30170
|
'title' Title yes
|
@@ -925,19 +925,31 @@ sub WriteXMP($$;$)
|
|
925
925
|
# get hash of all information we want to change
|
926
926
|
# (sorted by tag name so alternate languages come last, but with structures
|
927
927
|
# first so flattened tags may be used to override individual structure elements)
|
928
|
-
my (@tagInfoList, $delLangPath, %delLangPaths, %delAllLang, $firstNewPath);
|
928
|
+
my (@tagInfoList, @structList, $delLangPath, %delLangPaths, %delAllLang, $firstNewPath, @langTags);
|
929
929
|
my $writeGroup = $$dirInfo{WriteGroup};
|
930
930
|
foreach $tagInfo (sort ByTagName $et->GetNewTagInfoList()) {
|
931
931
|
next unless $et->GetGroup($tagInfo, 0) eq 'XMP';
|
932
932
|
next if $$tagInfo{Name} eq 'XMP'; # (ignore full XMP block if we didn't write it already)
|
933
933
|
next if $writeGroup and $writeGroup ne $$et{NEW_VALUE}{$tagInfo}{WriteGroup};
|
934
|
-
if ($$tagInfo{
|
935
|
-
|
934
|
+
if ($$tagInfo{LangCode}) {
|
935
|
+
push @langTags, $tagInfo
|
936
|
+
} elsif ($$tagInfo{Struct}) {
|
937
|
+
push @structList, $tagInfo;
|
936
938
|
} else {
|
937
939
|
push @tagInfoList, $tagInfo;
|
938
940
|
}
|
939
941
|
}
|
940
|
-
|
942
|
+
if (@langTags) {
|
943
|
+
# keep original order in which lang-alt entries were added
|
944
|
+
foreach $tagInfo (sort { $$et{NEW_VALUE}{$a}{Order} <=> $$et{NEW_VALUE}{$b}{Order} } @langTags) {
|
945
|
+
if ($$tagInfo{Struct}) {
|
946
|
+
push @structList, $tagInfo;
|
947
|
+
} else {
|
948
|
+
push @tagInfoList, $tagInfo;
|
949
|
+
}
|
950
|
+
}
|
951
|
+
}
|
952
|
+
foreach $tagInfo (@structList, @tagInfoList) {
|
941
953
|
my @delPaths; # list of deleted paths
|
942
954
|
my $tag = $$tagInfo{TagID};
|
943
955
|
my $path = GetPropertyPath($tagInfo);
|
@@ -295,10 +295,11 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
|
|
295
295
|
# CreateGroups - hash of all family 0 group names where tag may be created
|
296
296
|
# WriteGroup - group name where information is being written (correct case)
|
297
297
|
# WantGroup - group name as specified in call to function (case insensitive)
|
298
|
-
# Next - pointer to next new value hash (if more than one)
|
298
|
+
# Next - pointer to next new value hash (if more than one for this tag)
|
299
299
|
# NoReplace - set if value was created with Replace=0
|
300
300
|
# AddBefore - number of list items added by a subsequent Replace=0 call
|
301
|
-
# IsNVH -
|
301
|
+
# IsNVH - flag indicating this is a new value hash
|
302
|
+
# Order - counter to indicate the order that new value hashes were created
|
302
303
|
# Shift - shift value
|
303
304
|
# Save - counter used by SaveNewValues()/RestoreNewValues()
|
304
305
|
# MAKER_NOTE_FIXUP - pointer to fixup if necessary for a maker note value
|
@@ -317,7 +318,7 @@ sub SetNewValue($;$$%)
|
|
317
318
|
|
318
319
|
unless (defined $tag) {
|
319
320
|
delete $$self{NEW_VALUE};
|
320
|
-
$$self{SAVE_COUNT} = 0;
|
321
|
+
$$self{SAVE_COUNT} = $$self{NV_COUNT} = 0;
|
321
322
|
$$self{DEL_GROUP} = { };
|
322
323
|
return 1;
|
323
324
|
}
|
@@ -1389,8 +1390,16 @@ sub SetNewValuesFromFile($$;@)
|
|
1389
1390
|
return $info if $$info{Error} and $$info{Error} eq 'Error opening file';
|
1390
1391
|
delete $$srcExifTool{VALUE}{Error}; # delete so we can check this later
|
1391
1392
|
|
1392
|
-
# sort tags in
|
1393
|
-
my @tags
|
1393
|
+
# sort tags in file order with priority tags last
|
1394
|
+
my (@tags, @prio);
|
1395
|
+
foreach (sort { $$srcExifTool{FILE_ORDER}{$a} <=> $$srcExifTool{FILE_ORDER}{$b} } keys %$info) {
|
1396
|
+
if (/ /) {
|
1397
|
+
push @tags, $_;
|
1398
|
+
} else {
|
1399
|
+
push @prio, $_;
|
1400
|
+
}
|
1401
|
+
}
|
1402
|
+
push @tags, @prio;
|
1394
1403
|
#
|
1395
1404
|
# simply transfer all tags from source image if no tags specified
|
1396
1405
|
#
|
@@ -3896,6 +3905,7 @@ sub GetNewValueHash($$;$$$$)
|
|
3896
3905
|
TagInfo => $tagInfo,
|
3897
3906
|
WriteGroup => $writeGroup,
|
3898
3907
|
IsNVH => 1, # set flag so we can recognize a new value hash
|
3908
|
+
Order => $$self{NV_COUNT}++,
|
3899
3909
|
};
|
3900
3910
|
# add entry to our NEW_VALUE hash
|
3901
3911
|
if ($$self{NEW_VALUE}{$tagInfo}) {
|
@@ -4023,7 +4033,7 @@ sub RemoveNewValuesForGroup($$)
|
|
4023
4033
|
#------------------------------------------------------------------------------
|
4024
4034
|
# Get list of tagInfo hashes for all new data
|
4025
4035
|
# Inputs: 0) ExifTool object reference, 1) optional tag table pointer
|
4026
|
-
# Returns: list of tagInfo hashes
|
4036
|
+
# Returns: list of tagInfo hashes in no particular order
|
4027
4037
|
sub GetNewTagInfoList($;$)
|
4028
4038
|
{
|
4029
4039
|
my ($self, $tagTablePtr) = @_;
|
@@ -39,8 +39,7 @@ sub SerializeStruct($$;$)
|
|
39
39
|
|
40
40
|
if (ref $obj eq 'HASH') {
|
41
41
|
# support hashes with ordered keys
|
42
|
-
|
43
|
-
foreach $key (@keys) {
|
42
|
+
foreach $key (Image::ExifTool::OrderedKeys($obj)) {
|
44
43
|
my $hdr = $sfmt ? EscapeJSON($key) . ':' : $key . '=';
|
45
44
|
push @vals, $hdr . SerializeStruct($et, $$obj{$key}, '}');
|
46
45
|
}
|
@@ -218,7 +217,7 @@ sub DumpStruct($;$)
|
|
218
217
|
$indent or $indent = '';
|
219
218
|
if (ref $obj eq 'HASH') {
|
220
219
|
print "{\n";
|
221
|
-
foreach (
|
220
|
+
foreach (Image::ExifTool::OrderedKeys($obj)) {
|
222
221
|
print "$indent $_ = ";
|
223
222
|
DumpStruct($$obj{$_}, "$indent ");
|
224
223
|
}
|
@@ -253,8 +252,10 @@ sub CheckStruct($$$)
|
|
253
252
|
ref $struct eq 'HASH' or return wantarray ? (undef, "Expecting $strName structure") : undef;
|
254
253
|
|
255
254
|
my ($key, $err, $warn, %copy, $rtnVal, $val);
|
255
|
+
# copy the ordered keys if they exist
|
256
|
+
$copy{_ordered_keys_} = [ ] if $$struct{_ordered_keys_};
|
256
257
|
Key:
|
257
|
-
foreach $key (
|
258
|
+
foreach $key (Image::ExifTool::OrderedKeys($struct)) {
|
258
259
|
my $tag = $key;
|
259
260
|
# allow trailing '#' to disable print conversion on a per-field basis
|
260
261
|
my ($type, $fieldInfo);
|
@@ -377,6 +378,7 @@ Key:
|
|
377
378
|
$copy{$tag} = \@copy;
|
378
379
|
} elsif ($$fieldInfo{Struct}) {
|
379
380
|
$warn = "Improperly formed structure in $strName $tag";
|
381
|
+
next;
|
380
382
|
} else {
|
381
383
|
$et->Sanitize(\$$struct{$key});
|
382
384
|
($val,$err) = $et->ConvInv($$struct{$key},$fieldInfo,$tag,$strName,$type,'');
|
@@ -387,6 +389,7 @@ Key:
|
|
387
389
|
# turn this into a list if necessary
|
388
390
|
$copy{$tag} = $$fieldInfo{List} ? [ $val ] : $val;
|
389
391
|
}
|
392
|
+
push @{$copy{_ordered_keys_}}, $tag if $copy{_ordered_keys_}; # save ordered keys
|
390
393
|
}
|
391
394
|
if (%copy or not $warn) {
|
392
395
|
$rtnVal = \%copy;
|
@@ -562,7 +565,7 @@ sub AddNewStruct($$$$$$)
|
|
562
565
|
# after all valid structure fields, which is necessary when serializing the XMP later)
|
563
566
|
%$struct or $$struct{'~dummy~'} = '';
|
564
567
|
|
565
|
-
foreach $tag (
|
568
|
+
foreach $tag (Image::ExifTool::OrderedKeys($struct)) {
|
566
569
|
my $fieldInfo = $$strTable{$tag};
|
567
570
|
unless ($fieldInfo) {
|
568
571
|
next unless $tag eq '~dummy~'; # check for dummy field
|
@@ -652,7 +655,8 @@ sub ConvertStruct($$$$;$)
|
|
652
655
|
my (%struct, $key);
|
653
656
|
my $table = $$tagInfo{Table};
|
654
657
|
$parentID = $$tagInfo{TagID} unless $parentID;
|
655
|
-
|
658
|
+
$struct{_ordered_keys_} = [ ] if $$value{_ordered_keys_};
|
659
|
+
foreach $key (Image::ExifTool::OrderedKeys($value)) {
|
656
660
|
my $tagID = $parentID . ucfirst($key);
|
657
661
|
my $flatInfo = $$table{$tagID};
|
658
662
|
unless ($flatInfo) {
|
@@ -669,7 +673,11 @@ sub ConvertStruct($$$$;$)
|
|
669
673
|
} else {
|
670
674
|
$v = $et->GetValue($flatInfo, $type, $v);
|
671
675
|
}
|
672
|
-
|
676
|
+
if (defined $v) {
|
677
|
+
$struct{$key} = $v; # save the converted value
|
678
|
+
# maintain ordered keys if necessary
|
679
|
+
push @{$struct{_ordered_keys_}}, $key if $struct{_ordered_keys_};
|
680
|
+
}
|
673
681
|
}
|
674
682
|
return \%struct;
|
675
683
|
} elsif (ref $value eq 'ARRAY') {
|
data/bin/lib/Image/ExifTool.pm
CHANGED
@@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
|
|
29
29
|
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
30
30
|
%static_vars $advFmtSelf);
|
31
31
|
|
32
|
-
$VERSION = '12.
|
32
|
+
$VERSION = '12.99';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -37,7 +37,7 @@ $RELEASE = '';
|
|
37
37
|
Public => [qw(
|
38
38
|
ImageInfo AvailableOptions GetTagName GetShortcuts GetAllTags
|
39
39
|
GetWritableTags GetAllGroups GetDeleteGroups GetFileType CanWrite
|
40
|
-
CanCreate AddUserDefinedTags
|
40
|
+
CanCreate AddUserDefinedTags OrderedKeys
|
41
41
|
)],
|
42
42
|
# exports not part of the public API, but used by ExifTool modules:
|
43
43
|
DataAccess => [qw(
|
@@ -2292,6 +2292,7 @@ sub new
|
|
2292
2292
|
$$self{PATH} = [ ]; # (this too)
|
2293
2293
|
$$self{DEL_GROUP} = { }; # lookup for groups to delete when writing
|
2294
2294
|
$$self{SAVE_COUNT} = 0; # count calls to SaveNewValues()
|
2295
|
+
$$self{NV_COUNT} = 0; # count of NEW_VALUE entries
|
2295
2296
|
$$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
|
2296
2297
|
$$self{FILES_WRITTEN} = 0; # count of files successfully written
|
2297
2298
|
$$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
|
@@ -2517,6 +2518,8 @@ sub Options($$;@)
|
|
2517
2518
|
# set Compact and XMPShorthand options, preserving backward compatibility
|
2518
2519
|
my ($p, %compact);
|
2519
2520
|
foreach $p ('Compact','XMPShorthand') {
|
2521
|
+
# (allow setting from a HASH (undocumented)
|
2522
|
+
ref $newVal eq 'HASH' and %compact = %{$newVal}, next;
|
2520
2523
|
my $val = $param eq $p ? $newVal : $$options{Compact}{$p};
|
2521
2524
|
if (defined $val) {
|
2522
2525
|
my @v = ($val =~ /\w+/g);
|
@@ -4195,6 +4198,16 @@ sub CanCreate($)
|
|
4195
4198
|
return 0;
|
4196
4199
|
}
|
4197
4200
|
|
4201
|
+
#------------------------------------------------------------------------------
|
4202
|
+
# Return list of ordered keys if available, otherwise just sort alphabetically
|
4203
|
+
# Inputs: 0) hash ref
|
4204
|
+
# Returns: List of ordered/sorted keys
|
4205
|
+
sub OrderedKeys($)
|
4206
|
+
{
|
4207
|
+
my $hash = shift;
|
4208
|
+
return $$hash{_ordered_keys_} ? @{$$hash{_ordered_keys_}} : sort keys %$hash;
|
4209
|
+
}
|
4210
|
+
|
4198
4211
|
#==============================================================================
|
4199
4212
|
# Functions below this are not part of the public API
|
4200
4213
|
|
@@ -7904,8 +7917,17 @@ sub ProcessJPEG($$;$)
|
|
7904
7917
|
my $seq = Get32u($segDataPt, 4);
|
7905
7918
|
my $len = Get32u($segDataPt, 8);
|
7906
7919
|
my $type = substr($$segDataPt, 12, 4);
|
7920
|
+
# a Microsoft bug writes $len and $type incorrectly as little-endian
|
7921
|
+
if ($type eq 'bmuj') {
|
7922
|
+
$self->WarnOnce('Wrong byte order in C2PA APP11 JUMBF header');
|
7923
|
+
$type = 'jumb';
|
7924
|
+
$len = unpack('x8V', $$segDataPt);
|
7925
|
+
# fix the header
|
7926
|
+
substr($$segDataPt, 8, 8) = Set32u($len) . $type;
|
7927
|
+
}
|
7907
7928
|
my $hdrLen;
|
7908
7929
|
if ($len == 1 and length($$segDataPt) >= 24) {
|
7930
|
+
# (haven't seen this with the Microsoft bug)
|
7909
7931
|
$len = Get64u($$segDataPt, 16);
|
7910
7932
|
$hdrLen = 16;
|
7911
7933
|
} else {
|
data/bin/lib/Image/ExifTool.pod
CHANGED
@@ -332,13 +332,14 @@ L</ImageInfo>:
|
|
332
332
|
|
333
333
|
Values of the returned hash are usually simple scalars, but a scalar
|
334
334
|
reference is used to indicate binary data and an array reference may be used
|
335
|
-
to indicate a list. Also, a hash reference may be returned if the
|
336
|
-
option is used
|
337
|
-
|
338
|
-
enabled
|
339
|
-
|
340
|
-
|
341
|
-
|
335
|
+
to indicate a list. Also, a hash reference may be returned if the
|
336
|
+
L</Struct> option is used (see the L</OrderedKeys> option to obtain the hash
|
337
|
+
keys). Lists of values are joined by commas into a single string only if
|
338
|
+
the PrintConv option is enabled and the ListJoin option is enabled (which
|
339
|
+
are the defaults). Note that binary values are not necessarily extracted
|
340
|
+
unless specifically requested, or the Binary option is enabled and the tag
|
341
|
+
is not specifically excluded. If not extracted the value is a reference to
|
342
|
+
a string of the form "Binary data ##### bytes".
|
342
343
|
|
343
344
|
The code below gives an example of how to handle these return values, as
|
344
345
|
well as illustrating the use of other ExifTool functions:
|
@@ -1089,7 +1090,9 @@ values in standard format).
|
|
1089
1090
|
|
1090
1091
|
Flag to return XMP structures as hash references instead of flattening into
|
1091
1092
|
individual tags. Has no effect when writing since both flattened and
|
1092
|
-
structured tags may always be written.
|
1093
|
+
structured tags may always be written. A special "_ordered_keys_" element
|
1094
|
+
containing a list of ordered keys may exist if the structure elements are
|
1095
|
+
ordered (see the L<OrderedKeys> method). Possible values are:
|
1093
1096
|
|
1094
1097
|
undef - (default) Same as 0 for reading, 2 for copying
|
1095
1098
|
0 - Read/copy flattened tags
|
@@ -2749,6 +2752,26 @@ details on the elements of the tag information hash.
|
|
2749
2752
|
|
2750
2753
|
=back
|
2751
2754
|
|
2755
|
+
=head2 OrderedKeys [static]
|
2756
|
+
|
2757
|
+
Return a list of ordered keys from a tag value that is a HASH reference
|
2758
|
+
when the Struct option is used.
|
2759
|
+
|
2760
|
+
use Image::ExifTool ':Public';
|
2761
|
+
my @keys = OrderedKeys($structRef);
|
2762
|
+
|
2763
|
+
=over 4
|
2764
|
+
|
2765
|
+
=item Inputs:
|
2766
|
+
|
2767
|
+
0) Structure HASH reference
|
2768
|
+
|
2769
|
+
=item Return Value:
|
2770
|
+
|
2771
|
+
List of ordered keys, or sorted alphabetically if not ordered.
|
2772
|
+
|
2773
|
+
=back
|
2774
|
+
|
2752
2775
|
=head1 CHARACTER ENCODINGS
|
2753
2776
|
|
2754
2777
|
Certain meta information formats allow coded character sets other than plain
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exiftool_vendored
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 12.
|
4
|
+
version: 12.99.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew McEachen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-10-
|
12
|
+
date: 2024-10-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: exiftool
|