exiftool_vendored 12.98.0 → 12.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|