exiftool-vendored.pl 12.97.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/Changes +48 -2
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +2 -2
- package/bin/arg_files/exif2xmp.args +4 -0
- package/bin/arg_files/xmp2exif.args +4 -0
- package/bin/config_files/example.config +2 -1
- package/bin/exiftool +255 -54
- package/bin/lib/File/RandomAccess.pm +5 -2
- package/bin/lib/Image/ExifTool/APP12.pm +3 -2
- package/bin/lib/Image/ExifTool/Canon.pm +2 -1
- package/bin/lib/Image/ExifTool/Exif.pm +1 -1
- package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/lib/Image/ExifTool/Geotag.pm +4 -3
- package/bin/lib/Image/ExifTool/Import.pm +7 -3
- package/bin/lib/Image/ExifTool/InDesign.pm +4 -3
- package/bin/lib/Image/ExifTool/JSON.pm +3 -4
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +2 -1
- package/bin/lib/Image/ExifTool/Lytro.pm +2 -2
- package/bin/lib/Image/ExifTool/M2TS.pm +10 -2
- package/bin/lib/Image/ExifTool/PhaseOne.pm +2 -1
- package/bin/lib/Image/ExifTool/QuickTime.pm +17 -6
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +88 -9
- package/bin/lib/Image/ExifTool/Sony.pm +6 -1
- package/bin/lib/Image/ExifTool/TagLookup.pm +14 -9
- package/bin/lib/Image/ExifTool/TagNames.pod +40 -23
- package/bin/lib/Image/ExifTool/WritePDF.pl +47 -21
- package/bin/lib/Image/ExifTool/WriteXMP.pl +16 -4
- package/bin/lib/Image/ExifTool/Writer.pl +16 -6
- package/bin/lib/Image/ExifTool/XMP.pm +19 -4
- package/bin/lib/Image/ExifTool/XMPStruct.pl +15 -7
- package/bin/lib/Image/ExifTool.pm +37 -12
- package/bin/lib/Image/ExifTool.pod +31 -8
- package/bin/perl-Image-ExifTool.spec +1 -1
- package/bin/pp_build_exe.args +4 -4
- package/bin/windows_exiftool.txt +32 -10
- package/package.json +3 -3
package/bin/Changes
CHANGED
|
@@ -4,9 +4,55 @@ ExifTool Version History
|
|
|
4
4
|
|
|
5
5
|
RSS feed: https://exiftool.org/rss.xml
|
|
6
6
|
|
|
7
|
-
Note: The most recent production release is Version
|
|
7
|
+
Note: The most recent production release is Version 13.00. (Other versions are
|
|
8
8
|
considered development releases, and are not uploaded to MetaCPAN.)
|
|
9
9
|
|
|
10
|
+
Oct. 29, 2024 - Version 13.00 (production release)
|
|
11
|
+
|
|
12
|
+
- Added support for reading GPS from Autel Evo II drone videos
|
|
13
|
+
- Added a new PhaseOne RawFormat value
|
|
14
|
+
- Updated XMP-exifEX tags, exif2xmp.args and xmp2exif.args according to the
|
|
15
|
+
2024 EXIF for XMP specification
|
|
16
|
+
- Updated Geolocation databases from current geonames.org files
|
|
17
|
+
- Updated the MIME types for a couple of font formats
|
|
18
|
+
- Enhanced -diff option to work with -ec (C-style escape of special chars)
|
|
19
|
+
- Changed name of EXIF Title tag to ImageTitle to correspond with specifiation
|
|
20
|
+
- Reverted a geotag warning message to remove debugging information that was
|
|
21
|
+
added in version 12.67 and moved this information into a -v3 verbose message
|
|
22
|
+
- Patched Perl bug which gave "Can't spawn" warning in Windows if control-C
|
|
23
|
+
was pressed while displaying the exiftool application help
|
|
24
|
+
- Fixed API StructFormat JSONQ setting to properly quote values in structures
|
|
25
|
+
- Fixed incorrect AudioStreamType for M2TS videos containing a PGS stream
|
|
26
|
+
- Fixed -diff option so "same tags" messages are only shown when -v is added
|
|
27
|
+
(as per the documentation)
|
|
28
|
+
|
|
29
|
+
Oct. 18, 2024 - Version 12.99
|
|
30
|
+
|
|
31
|
+
- Added -diff option to compare the metadata in two files
|
|
32
|
+
- Added a new Canon lens (thanks Norbert Wasser)
|
|
33
|
+
- Decode GPS from 70mai A810 dashcam videos
|
|
34
|
+
- Decode a new QuickTime tag
|
|
35
|
+
- Patched to recognize C2PA APP11 JUMBF header with incorrect byte order
|
|
36
|
+
written by buggy Microsoft software
|
|
37
|
+
- Patched to maintain order of entries in a JSON object when reading
|
|
38
|
+
- Patched to maintain order of CSV columns when setting tags from a CSV file
|
|
39
|
+
- Patched to maintain order of XMP lang-alt entries when writing/copying
|
|
40
|
+
- Fixed typo in an APP12 tag name
|
|
41
|
+
- API Changes:
|
|
42
|
+
- Structured values returned as HASH references with the Struct option may
|
|
43
|
+
contain a new "_ordered_keys_" entry used to preserve the order of the
|
|
44
|
+
entries
|
|
45
|
+
- Added the OrderedKeys method to return the ordered or sorted keys from a
|
|
46
|
+
returned structure value
|
|
47
|
+
|
|
48
|
+
Oct. 8, 2024 - Version 12.98
|
|
49
|
+
|
|
50
|
+
- Added write support for PDF files with huge offsets
|
|
51
|
+
- Added a number of new Sony LensType values (thanks Jos Roost)
|
|
52
|
+
- Require -v4 or higher to output "JPG RST" lines
|
|
53
|
+
- Patched problem with -fast option when reading HEIC file via a pipe
|
|
54
|
+
- Patched to avoid hang when reading some corrupted XMP
|
|
55
|
+
|
|
10
56
|
Sept. 25, 2024 - Version 12.97
|
|
11
57
|
|
|
12
58
|
- Added ability to ignore up to 4095 bytes of garbage at the end of an INDD
|
|
@@ -143,7 +189,7 @@ June 7, 2024 - Version 12.86
|
|
|
143
189
|
- Patched some Olympus WB_RBLevels tags to allow 4 values to be written as per
|
|
144
190
|
some newer models
|
|
145
191
|
- Fixed issue when writing IPTC date tags with a date/time value containing
|
|
146
|
-
subseconds with 4 or more digits
|
|
192
|
+
subseconds with 4 or more digits
|
|
147
193
|
|
|
148
194
|
May 21, 2024 - Version 12.85
|
|
149
195
|
|
package/bin/META.json
CHANGED
package/bin/META.yml
CHANGED
package/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-
|
|
113
|
-
cd Image-ExifTool-
|
|
112
|
+
gzip -dc Image-ExifTool-13.00.tar.gz | tar -xf -
|
|
113
|
+
cd Image-ExifTool-13.00
|
|
114
114
|
./exiftool t/images/ExifTool.jpg
|
|
115
115
|
|
|
116
116
|
Note: These commands extract meta information from one of the test images.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# 2015/01/12 - PH Avoid copying to non-standard namespaces
|
|
14
14
|
# 2018/05/07 - PH Added support for GPSDestXxxRef tags
|
|
15
15
|
# 2022/03/31 - PH IPTC Photometadata Mapping Guidelines 2202.1 update
|
|
16
|
+
# 2024/10/24 - PH Additions for the 2024 EXIF for XMP spec
|
|
16
17
|
#
|
|
17
18
|
# References: http://www.metadataworkinggroup.org/specs/
|
|
18
19
|
# https://iptc.org/std/photometadata/documentation/mappingguidelines/
|
|
@@ -50,4 +51,7 @@
|
|
|
50
51
|
-XMP:GPSDestLatitude < Composite:GPSDestLatitude
|
|
51
52
|
-XMP:GPSDestLongitude < Composite:GPSDestLongitude
|
|
52
53
|
-XMP:GPSDateTime < Composite:GPSDateTime
|
|
54
|
+
# new for the 2024 EXIF for XMP specification
|
|
55
|
+
-XMP-exifEX:PhotographicSensitivity < EXIF:ISO
|
|
56
|
+
-XMP-exif:DateTimeDigitized < EXIF:CreateDate
|
|
53
57
|
# end
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
# 2022/03/31 - PH IPTC Photometadata Mapping Guidelines 2202.1 update
|
|
18
18
|
# 2023/01/30 - PH Also write Composite:SubSecDateTimeOriginal from
|
|
19
19
|
# XMP-exif:DateTimeOriginal
|
|
20
|
+
# 2024/10/24 - PH Additions for the 2024 EXIF for XMP spec
|
|
20
21
|
#
|
|
21
22
|
# References: http://www.metadataworkinggroup.org/specs/
|
|
22
23
|
# https://iptc.org/std/photometadata/documentation/mappingguidelines/
|
|
@@ -36,6 +37,9 @@
|
|
|
36
37
|
-EXIF:all < XMP-tiff:all
|
|
37
38
|
-EXIF:ImageDescription < XMP-dc:Description
|
|
38
39
|
-EXIF:DateTimeOriginal < XMP-photoshop:DateCreated
|
|
40
|
+
# new for the 2024 EXIF for XMP specification
|
|
41
|
+
-EXIF:ISO < XMP-exifEX:PhotographicSensitivity
|
|
42
|
+
-EXIF:CreateDate < XMP-exif:DateTimeDigitized
|
|
39
43
|
# the following SubSec tags also write/delete the corresponding EXIF
|
|
40
44
|
# SubSecTime and OffsetTime tags as appropriate
|
|
41
45
|
-Composite:SubSecDateTimeOriginal < XMP-exif:DateTimeOriginal
|
|
@@ -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 => {
|
package/bin/exiftool
CHANGED
|
@@ -11,7 +11,7 @@ use strict;
|
|
|
11
11
|
use warnings;
|
|
12
12
|
require 5.004;
|
|
13
13
|
|
|
14
|
-
my $version = '
|
|
14
|
+
my $version = '13.00';
|
|
15
15
|
|
|
16
16
|
# add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
|
|
17
17
|
my $exePath;
|
|
@@ -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 and ($same or $v > 1) 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
|
+
$grp = ' ' x length($grp), $name = ' ' x $len if $v < 3;
|
|
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
|
+
$name = ' ' x $len if $v < 3;
|
|
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 (/^(.*?):(.*)/) {
|
|
@@ -3512,7 +3638,7 @@ sub FormatJSON($$$;$)
|
|
|
3512
3638
|
print $fp $bra;
|
|
3513
3639
|
foreach (@$val) {
|
|
3514
3640
|
print $fp ',' if $comma;
|
|
3515
|
-
FormatJSON($fp, $_, $ind);
|
|
3641
|
+
FormatJSON($fp, $_, $ind, $quote);
|
|
3516
3642
|
$comma = 1,
|
|
3517
3643
|
}
|
|
3518
3644
|
print $fp $ket,
|
|
@@ -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 );
|
|
@@ -3529,7 +3654,7 @@ sub FormatJSON($$$;$)
|
|
|
3529
3654
|
if ($showTagID and $_ eq 'id' and $showTagID eq 'H' and $$val{$_} =~ /^\d+\.\d+$/) {
|
|
3530
3655
|
print $fp qq{"$$val{$_}"};
|
|
3531
3656
|
} else {
|
|
3532
|
-
FormatJSON($fp, $$val{$_}, "$ind ");
|
|
3657
|
+
FormatJSON($fp, $$val{$_}, "$ind ", $quote);
|
|
3533
3658
|
}
|
|
3534
3659
|
$comma = 1,
|
|
3535
3660
|
}
|
|
@@ -3678,6 +3803,59 @@ 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
|
+
if ($escapeC) {
|
|
3824
|
+
$val =~ s/([\0-\x1f\\\x7f])/$escC{$1} || sprintf('\x%.2x', ord $1)/eg;
|
|
3825
|
+
} else {
|
|
3826
|
+
# translate unprintable chars in value and remove trailing spaces
|
|
3827
|
+
$val =~ tr/\x01-\x1f\x7f/./;
|
|
3828
|
+
$val =~ s/\x00//g;
|
|
3829
|
+
$val =~ s/\s+$//;
|
|
3830
|
+
}
|
|
3831
|
+
return $val;
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
#------------------------------------------------------------------------------
|
|
3835
|
+
# Get character length of a UTF-8 string
|
|
3836
|
+
# Inputs: 0) string
|
|
3837
|
+
# Returns: number of characters (not bytes) in the UTF-8 string
|
|
3838
|
+
sub LengthUTF8($)
|
|
3839
|
+
{
|
|
3840
|
+
my $str = shift;
|
|
3841
|
+
my $len;
|
|
3842
|
+
if (not $fixLen) {
|
|
3843
|
+
$len = length $str;
|
|
3844
|
+
} elsif ($fixLen == 1) {
|
|
3845
|
+
$len = length Encode::decode_utf8($str);
|
|
3846
|
+
} else {
|
|
3847
|
+
my $gcstr = eval { Unicode::GCString->new(Encode::decode_utf8($str)) };
|
|
3848
|
+
if ($gcstr) {
|
|
3849
|
+
$len = $gcstr->columns;
|
|
3850
|
+
} else {
|
|
3851
|
+
$len = length Encode::decode_utf8($str);
|
|
3852
|
+
Warning($mt, 'Unicode::GCString problem. Columns may be misaligned');
|
|
3853
|
+
$fixLen = 1;
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
return $len;
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3681
3859
|
#------------------------------------------------------------------------------
|
|
3682
3860
|
# Add tag list for copying tags from specified file
|
|
3683
3861
|
# Inputs: 0) set tags file name (or FMT), 1) options for SetNewValuesFromFile()
|
|
@@ -4867,6 +5045,7 @@ L<Other options|/Other options>
|
|
|
4867
5045
|
|
|
4868
5046
|
L<Special features|/Special features>
|
|
4869
5047
|
|
|
5048
|
+
-diff FILE2 Compare metadata with another file
|
|
4870
5049
|
-geotag TRKFILE Geotag images from specified GPS log
|
|
4871
5050
|
-globalTimeShift SHIFT Shift all formatted date/time values
|
|
4872
5051
|
-use MODULE Add features from plug-in module
|
|
@@ -4958,13 +5137,13 @@ may be used to to indicate any XMP namespace (eg. C<--xmp-all:dabs>).
|
|
|
4958
5137
|
Write a new value for the specified tag (eg. C<-comment=wow>), or delete the
|
|
4959
5138
|
tag if no I<VALUE> is given (eg. C<-comment=>). C<+=> and C<-=> are used to
|
|
4960
5139
|
add or remove existing entries from a list, or to shift date/time values
|
|
4961
|
-
(see L<Image::ExifTool::Shift.pl|Image::ExifTool::Shift.pl> and
|
|
4962
|
-
for more details). C<+=> may also be used to increment numerical
|
|
4963
|
-
decrement if I<VALUE> is negative), and C<-=> may be used to
|
|
4964
|
-
delete or replace a tag (see L</WRITING EXAMPLES> for
|
|
4965
|
-
used to write an empty string instead of deleting the
|
|
4966
|
-
is given, but otherwise it is equivalent to C<=>.
|
|
4967
|
-
be quoted on the Windows command line.)
|
|
5140
|
+
(see L<Image::ExifTool::Shift.pl|Image::ExifTool::Shift.pl> and notes 6 and
|
|
5141
|
+
7 below for more details). C<+=> may also be used to increment numerical
|
|
5142
|
+
values (or decrement if I<VALUE> is negative), and C<-=> may be used to
|
|
5143
|
+
conditionally delete or replace a tag (see L</WRITING EXAMPLES> for
|
|
5144
|
+
examples). C<^=> is used to write an empty string instead of deleting the
|
|
5145
|
+
tag when no I<VALUE> is given, but otherwise it is equivalent to C<=>.
|
|
5146
|
+
(Note that the caret must be quoted on the Windows command line.)
|
|
4968
5147
|
|
|
4969
5148
|
I<TAG> may contain one or more leading family 0, 1, 2 or 7 group names,
|
|
4970
5149
|
prefixed by optional family numbers, and separated colons. If no group name
|
|
@@ -5039,6 +5218,10 @@ tag, overriding any other values previously assigned to the tag on the same
|
|
|
5039
5218
|
command line. To shift a date/time value and copy it to another tag in the
|
|
5040
5219
|
same operation, use the B<-globalTimeShift> option.
|
|
5041
5220
|
|
|
5221
|
+
7) The C<+=> operator may not be used to shift a List-type date/time tag
|
|
5222
|
+
(eg. XMP-dc:Date) because C<+=> is used to add elements to the list.
|
|
5223
|
+
Instead, the B<-globalTimeShift> option should be used.
|
|
5224
|
+
|
|
5042
5225
|
Special feature: Integer values may be specified in hexadecimal with a
|
|
5043
5226
|
leading C<0x>, and simple rational values may be specified as fractions.
|
|
5044
5227
|
|
|
@@ -5662,7 +5845,7 @@ with this command:
|
|
|
5662
5845
|
|
|
5663
5846
|
produces output like this:
|
|
5664
5847
|
|
|
5665
|
-
-- Generated by ExifTool
|
|
5848
|
+
-- Generated by ExifTool 13.00 --
|
|
5666
5849
|
File: a.jpg - 2003:10:31 15:44:19
|
|
5667
5850
|
(f/5.6, 1/60s, ISO 100)
|
|
5668
5851
|
File: b.jpg - 2006:05:23 11:57:38
|
|
@@ -6204,9 +6387,10 @@ B<-fileNUM> option is used to read an alternate file and the corresponding
|
|
|
6204
6387
|
family 8 group name is specified for the tag. See the B<-fileNUM> option
|
|
6205
6388
|
details for more information.
|
|
6206
6389
|
|
|
6207
|
-
5) The B<-a> option
|
|
6208
|
-
the values of duplicate tags are accessible
|
|
6209
|
-
(such as a family 4 instance number, eg.
|
|
6390
|
+
5) The B<-a> (Duplicates) option is implied when B<-if> is used without a
|
|
6391
|
+
fast I<NUM>, and the values of duplicate tags are accessible by specifying a
|
|
6392
|
+
group name in the expression (such as a family 4 instance number, eg.
|
|
6393
|
+
C<$Copy1:TAG>, C<$Copy2:TAG>, etc).
|
|
6210
6394
|
|
|
6211
6395
|
6) A special "OK" UserParam is available to test the success of the previous
|
|
6212
6396
|
command when B<-execute> was used, and may be used like any other tag in the
|
|
@@ -6472,9 +6656,9 @@ B<-f> adds 'flags' and 'struct' attributes if applicable. The flags are
|
|
|
6472
6656
|
formatted as a comma-separated list of the following possible values:
|
|
6473
6657
|
Avoid, Binary, List, Mandatory, Permanent, Protected, Unknown and Unsafe
|
|
6474
6658
|
(see the L<Tag Name documentation|Image::ExifTool::TagNames>). For XMP List
|
|
6475
|
-
tags, the list type (Alt, Bag or Seq) is
|
|
6476
|
-
|
|
6477
|
-
|
|
6659
|
+
tags, the list type (Alt, Bag or Seq) is also given, and flattened structure
|
|
6660
|
+
tags are indicated by a Flattened flag with 'struct' giving the ID of the
|
|
6661
|
+
parent structure.
|
|
6478
6662
|
|
|
6479
6663
|
Note that none of the B<-list> options require an input I<FILE>.
|
|
6480
6664
|
|
|
@@ -6496,6 +6680,23 @@ names, even if they begin with a dash (C<->).
|
|
|
6496
6680
|
|
|
6497
6681
|
=over 5
|
|
6498
6682
|
|
|
6683
|
+
=item B<-diff> I<FILE2>
|
|
6684
|
+
|
|
6685
|
+
Compare metadata in I<FILE> with I<FILE2>. The I<FILE2> name may include
|
|
6686
|
+
filename formatting codes (see the B<-w> option). All extracted tags from
|
|
6687
|
+
the files are compared, but the extracted tags may be controlled by adding
|
|
6688
|
+
B<-TAG> or B<--TAG> options. For example, below is a command to compare all
|
|
6689
|
+
the same-named files in two different directories, ignoring the System tags:
|
|
6690
|
+
|
|
6691
|
+
exiftool DIR1 -diff DIR2/%f.%e --system:all
|
|
6692
|
+
|
|
6693
|
+
The B<-g> and B<-G> options may be used to organize the output by the
|
|
6694
|
+
specified family of groups, with B<-G1> being the default. The B<-a> option
|
|
6695
|
+
is implied. Adding B<-v> includes a count of the number of tags that are
|
|
6696
|
+
the same in each group. The following text formatting options are valid
|
|
6697
|
+
when B<-diff> is used: B<-c>, B<-charset>, B<-d>, B<-E>, B<-ec>, B<-ex>,
|
|
6698
|
+
B<-L>, B<-lang>, B<-n>, B<-s>, B<-sep>, B<-struct> and B<-w>.
|
|
6699
|
+
|
|
6499
6700
|
=item B<-geotag> I<TRKFILE>
|
|
6500
6701
|
|
|
6501
6702
|
Geotag images from the specified GPS track log file. Using the B<-geotag>
|