exiftool_vendored 13.02.0 → 13.03.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 +23 -3
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +53 -24
- data/bin/lib/Image/ExifTool/Apple.pm +2 -2
- data/bin/lib/Image/ExifTool/Exif.pm +8 -1
- data/bin/lib/Image/ExifTool/GIF.pm +143 -92
- data/bin/lib/Image/ExifTool/JPEG.pm +9 -1
- data/bin/lib/Image/ExifTool/Matroska.pm +10 -2
- data/bin/lib/Image/ExifTool/PDF.pm +29 -2
- data/bin/lib/Image/ExifTool/PNG.pm +14 -3
- data/bin/lib/Image/ExifTool/PPM.pm +11 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +6 -1
- data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +5594 -5583
- data/bin/lib/Image/ExifTool/TagNames.pod +43 -4
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +13 -4
- data/bin/lib/Image/ExifTool/Writer.pl +16 -11
- data/bin/lib/Image/ExifTool/XMP.pm +7 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +60 -0
- data/bin/lib/Image/ExifTool.pm +94 -67
- data/bin/lib/Image/ExifTool.pod +16 -3
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -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 28175 tags, with 17499 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
|
@@ -147,8 +147,10 @@ L<https://www.w3.org/Graphics/JPEG/jfif3.pdf> for the JPEG specification.
|
|
147
147
|
DJI-DBG DJI Info
|
148
148
|
'APP8' SPIFF JPEG SPIFF
|
149
149
|
InfiRayIsothermal InfiRay Isothermal
|
150
|
+
SEAL XMP SEAL
|
150
151
|
'APP9' MediaJukebox JPEG MediaJukebox
|
151
152
|
InfiRaySensor InfiRay Sensor
|
153
|
+
SEAL XMP SEAL
|
152
154
|
'APP10' Comment no
|
153
155
|
'APP11' JPEG-HDR JPEG HDR
|
154
156
|
JUMBF Jpeg2000
|
@@ -1053,6 +1055,7 @@ for the official EXIF 2.32 specification.
|
|
1053
1055
|
0xcd49 JXLDistance IFD0 float
|
1054
1056
|
0xcd4a JXLEffort IFD0 int32u
|
1055
1057
|
0xcd4b JXLDecodeSpeed IFD0 int32u
|
1058
|
+
0xcea1 SEAL IFD0 XMP SEAL
|
1056
1059
|
0xea1c Padding ExifIFD undef!
|
1057
1060
|
0xea1d OffsetSchema ExifIFD int32s!
|
1058
1061
|
0xfde8 OwnerName ExifIFD string/
|
@@ -1427,6 +1430,7 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification.
|
|
1427
1430
|
pur XMP pur
|
1428
1431
|
rdf XMP rdf
|
1429
1432
|
sdc Nikon sdc
|
1433
|
+
seal XMP seal
|
1430
1434
|
swf XMP swf
|
1431
1435
|
tiff XMP tiff
|
1432
1436
|
x XMP x
|
@@ -6152,6 +6156,37 @@ These tags belong to the ExifTool XMP-rdf family 1 group.
|
|
6152
6156
|
-------- --------
|
6153
6157
|
About string!
|
6154
6158
|
|
6159
|
+
=head3 XMP seal Tags
|
6160
|
+
|
6161
|
+
SEAL embedded in XMP.
|
6162
|
+
|
6163
|
+
These tags belong to the ExifTool XMP-seal family 1 group.
|
6164
|
+
|
6165
|
+
Tag Name Writable
|
6166
|
+
-------- --------
|
6167
|
+
Seal XMP SEAL
|
6168
|
+
|
6169
|
+
=head3 XMP SEAL Tags
|
6170
|
+
|
6171
|
+
These tags are used in SEAL content authentification, which is actually XML
|
6172
|
+
format, not XMP. ExifTool has read/delete support for SEAL information in
|
6173
|
+
JPG, TIFF, XMP, PNG, WEBP, HEIC, PPM, MOV and MP4 files, and read-only
|
6174
|
+
support in PDF, MKV and WAV. Use C<-seal:all=> on the command line to
|
6175
|
+
delete SEAL information in supported formats.
|
6176
|
+
|
6177
|
+
Tag ID Tag Name Writable
|
6178
|
+
------ -------- --------
|
6179
|
+
'b' ByteRange no
|
6180
|
+
'copyright' Copyright no
|
6181
|
+
'd' Domain no
|
6182
|
+
'da' DigestAlgorithm no
|
6183
|
+
'info' SEALComment no
|
6184
|
+
'ka' KeyAlgorithm no
|
6185
|
+
'kv' KeyVersion no
|
6186
|
+
's' Signature no
|
6187
|
+
'seal' SEALVersion no
|
6188
|
+
'sf' SignatureFormat no
|
6189
|
+
|
6155
6190
|
=head3 XMP swf Tags
|
6156
6191
|
|
6157
6192
|
Adobe SWF namespace tags.
|
@@ -28129,6 +28164,7 @@ check if speed is more of a concern.
|
|
28129
28164
|
'sPLT' SuggestedPalette no
|
28130
28165
|
'sRGB' SRGBRendering yes!
|
28131
28166
|
'sTER' StereoImage PNG StereoImage
|
28167
|
+
'seAl' SEAL XMP SEAL
|
28132
28168
|
'tEXt' TextualData PNG TextualData
|
28133
28169
|
'tIME' ModifyDate yes
|
28134
28170
|
'tRNS' Transparency no
|
@@ -29232,7 +29268,7 @@ C2PA JUMBF metadata extracted from "/C2PA_Manifest" file.
|
|
29232
29268
|
|
29233
29269
|
Tag ID Tag Name Writable
|
29234
29270
|
------ -------- --------
|
29235
|
-
'_stream'
|
29271
|
+
'_stream' PhotoshopStream Photoshop
|
29236
29272
|
|
29237
29273
|
=head3 PDF Illustrator Tags
|
29238
29274
|
|
@@ -29255,7 +29291,7 @@ C2PA JUMBF metadata extracted from "/C2PA_Manifest" file.
|
|
29255
29291
|
|
29256
29292
|
Tag ID Tag Name Writable
|
29257
29293
|
------ -------- --------
|
29258
|
-
'_stream'
|
29294
|
+
'_stream' AIStream PostScript
|
29259
29295
|
|
29260
29296
|
=head3 PDF Resources Tags
|
29261
29297
|
|
@@ -29284,7 +29320,7 @@ C2PA JUMBF metadata extracted from "/C2PA_Manifest" file.
|
|
29284
29320
|
|
29285
29321
|
Tag ID Tag Name Writable
|
29286
29322
|
------ -------- --------
|
29287
|
-
'_stream'
|
29323
|
+
'_stream' ICC_Profile ICC_Profile
|
29288
29324
|
|
29289
29325
|
=head3 PDF Properties Tags
|
29290
29326
|
|
@@ -29852,6 +29888,7 @@ for the official QuickTime specification.
|
|
29852
29888
|
'GPS ' GPSDataList2? no
|
29853
29889
|
'IDIT' DateTimeOriginal string
|
29854
29890
|
'PICT' PreviewPICT no
|
29891
|
+
'SEAL' SEAL XMP SEAL
|
29855
29892
|
'_htc' HTCInfo QuickTime HTCInfo
|
29856
29893
|
'ardt' ARDroneFile no
|
29857
29894
|
'cust' CustomInfo no
|
@@ -31651,6 +31688,7 @@ metadata to WEBP images, but can't yet write to other RIFF-based formats.
|
|
31651
31688
|
'LIST_hydt' PentaxData Pentax AVI
|
31652
31689
|
'LIST_ncdt' NikonData Nikon AVI
|
31653
31690
|
'LIST_pntx' PentaxData2 Pentax AVI
|
31691
|
+
'SEAL' SEAL XMP SEAL
|
31654
31692
|
'SGLT' BikeBroAccel QuickTime Stream
|
31655
31693
|
'SLLT' BikeBroGPS QuickTime Stream
|
31656
31694
|
'VP8 ' VP8Bitstream RIFF VP8
|
@@ -33258,6 +33296,7 @@ Matroska specification.
|
|
33258
33296
|
0xb538667 SignatureSlot Matroska
|
33259
33297
|
0xc53bb6b Cues Matroska
|
33260
33298
|
0xf43b675 Cluster Matroska
|
33299
|
+
0x5345414c SEAL XMP SEAL
|
33261
33300
|
|
33262
33301
|
=head3 Matroska Projection Tags
|
33263
33302
|
|
@@ -34,6 +34,11 @@ my %webpMap = (
|
|
34
34
|
MakerNotes => 'ExifIFD',
|
35
35
|
);
|
36
36
|
|
37
|
+
my %deletableGroup = (
|
38
|
+
"XMP\0" => 'XMP', # delete incorrectly written "XMP\0" tag with XMP group
|
39
|
+
SEAL => 'SEAL', # delete SEAL tag with SEAL group
|
40
|
+
);
|
41
|
+
|
37
42
|
#------------------------------------------------------------------------------
|
38
43
|
# Write RIFF file (currently WebP-type only)
|
39
44
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref
|
@@ -46,6 +51,7 @@ sub WriteRIFF($$)
|
|
46
51
|
my $outfile = $$dirInfo{OutFile};
|
47
52
|
my $outsize = 0;
|
48
53
|
my $raf = $$dirInfo{RAF};
|
54
|
+
my $verbose = $et->Options('Verbose');
|
49
55
|
my ($buff, $err, $pass, %has, %dirDat, $imageWidth, $imageHeight);
|
50
56
|
|
51
57
|
# do this in 2 passes so we can set the size of the containing RIFF chunk
|
@@ -65,6 +71,7 @@ sub WriteRIFF($$)
|
|
65
71
|
SetByteOrder('II');
|
66
72
|
|
67
73
|
# determine which directories we must write for this file type
|
74
|
+
$et->Options(Verbose => 0) if $pass; # (avoid duplicate Verbose options here)
|
68
75
|
$et->InitWriteDirs(\%webpMap);
|
69
76
|
my $addDirs = $$et{ADD_DIRS};
|
70
77
|
my $editDirs = $$et{EDIT_DIRS};
|
@@ -73,6 +80,7 @@ sub WriteRIFF($$)
|
|
73
80
|
|
74
81
|
# write header
|
75
82
|
if ($pass) {
|
83
|
+
$et->Options(Verbose => $verbose);
|
76
84
|
my $needsVP8X = ($has{ANIM} or $has{'XMP '} or $has{EXIF} or
|
77
85
|
$has{ALPH} or $has{ICCP});
|
78
86
|
if ($has{VP8X} and not $needsVP8X and $$et{CHANGED}) {
|
@@ -146,13 +154,14 @@ sub WriteRIFF($$)
|
|
146
154
|
# RIFF chunks are padded to an even number of bytes
|
147
155
|
my $len2 = $len + ($len & 0x01);
|
148
156
|
# handle incorrect "XMP\0" chunk ID written by Google software
|
149
|
-
if ($tag
|
150
|
-
if ($$et{DEL_GROUP}{
|
151
|
-
# just ignore this chunk if deleting
|
157
|
+
if ($deletableGroup{$tag}) {
|
158
|
+
if ($$et{DEL_GROUP}{$deletableGroup{$tag}}) {
|
159
|
+
# just ignore this chunk if deleting the associated group
|
152
160
|
$raf->Seek($len2, 1) or $et->Error('Seek error'), last;
|
161
|
+
$et->VPrint(0, " Deleting $deletableGroup{$tag}\n") if $pass;
|
153
162
|
++$$et{CHANGED};
|
154
163
|
next;
|
155
|
-
}
|
164
|
+
} elsif ($tag eq "XMP\0") {
|
156
165
|
$et->Warn('Incorrect XMP tag ID',1) if $pass;
|
157
166
|
}
|
158
167
|
}
|
@@ -43,6 +43,7 @@ my %tiffMap = (
|
|
43
43
|
PrintIM => 'IFD0',
|
44
44
|
IPTC => 'IFD0',
|
45
45
|
Photoshop => 'IFD0',
|
46
|
+
SEAL => 'IFD0',
|
46
47
|
InteropIFD => 'ExifIFD',
|
47
48
|
MakerNotes => 'ExifIFD',
|
48
49
|
CanonVRD => 'MakerNotes', # (so VRDOffset will get updated)
|
@@ -74,6 +75,7 @@ my %jpegMap = (
|
|
74
75
|
Meta => 'APP3',
|
75
76
|
MetaIFD => 'Meta',
|
76
77
|
RMETA => 'APP5',
|
78
|
+
SEAL => ['APP8','APP9'], # (note: add 'IFD0' if this is a possibility)
|
77
79
|
Ducky => 'APP12',
|
78
80
|
Photoshop => 'APP13',
|
79
81
|
Adobe => 'APP14',
|
@@ -140,7 +142,7 @@ my @delGroups = qw(
|
|
140
142
|
GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC ItemList JFIF
|
141
143
|
Jpeg2000 JUMBF Keys MakerNotes Meta MetaIFD Microsoft MIE MPF Nextbase NikonApp
|
142
144
|
NikonCapture PDF PDF-update PhotoMechanic Photoshop PNG PNG-pHYs PrintIM
|
143
|
-
QuickTime RMETA RSRC SubIFD Trailer UserData XML XML-* XMP XMP-*
|
145
|
+
QuickTime RMETA RSRC SEAL SubIFD Trailer UserData XML XML-* XMP XMP-*
|
144
146
|
);
|
145
147
|
# family 2 group names that we can delete
|
146
148
|
my @delGroup2 = qw(
|
@@ -152,6 +154,7 @@ my %delMore = (
|
|
152
154
|
QuickTime => [ qw(ItemList UserData Keys) ],
|
153
155
|
XMP => [ 'XMP-*' ],
|
154
156
|
XML => [ 'XML-*' ],
|
157
|
+
SEAL => [ 'XMP-SEAL' ],
|
155
158
|
);
|
156
159
|
|
157
160
|
# family 0 groups where directories should never be deleted
|
@@ -1311,7 +1314,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1311
1314
|
LimitLongValues => 10000000, # (10 MB)
|
1312
1315
|
List => 1,
|
1313
1316
|
MakerNotes => $$options{FastScan} && $$options{FastScan} > 1 ? undef : 1,
|
1314
|
-
RequestAll => $$options{RequestAll} || 1, # (
|
1317
|
+
RequestAll => $$options{RequestAll} || 1, # (must request all because reqTags doesn't cover wildcards)
|
1315
1318
|
StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1,
|
1316
1319
|
Struct => $structOpt,
|
1317
1320
|
);
|
@@ -1324,11 +1327,8 @@ sub SetNewValuesFromFile($$;@)
|
|
1324
1327
|
$$srcExifTool{ALT_EXIFTOOL} = $$self{ALT_EXIFTOOL};
|
1325
1328
|
foreach $tag (@setTags) {
|
1326
1329
|
next if ref $tag;
|
1327
|
-
|
1328
|
-
|
1329
|
-
push @exclude, $1;
|
1330
|
-
next;
|
1331
|
-
}
|
1330
|
+
# avoid extracting tags that are excluded
|
1331
|
+
$tag =~ /^-(.*)/ and push(@exclude, $1), next;
|
1332
1332
|
# add specified tags to list of requested tags
|
1333
1333
|
$_ = $tag;
|
1334
1334
|
if (/(.+?)\s*(>|<)\s*(.+)/) {
|
@@ -2983,7 +2983,7 @@ Conv: for (;;) {
|
|
2983
2983
|
$err2 = eval $$tagInfo{WriteCheck};
|
2984
2984
|
$@ and warn($@), $err2 = 'Error evaluating WriteCheck';
|
2985
2985
|
}
|
2986
|
-
unless ($err2) {
|
2986
|
+
unless (defined $err2) {
|
2987
2987
|
my $table = $$tagInfo{Table};
|
2988
2988
|
if ($table and $$table{CHECK_PROC} and not $$tagInfo{RawConvInv}) {
|
2989
2989
|
my $checkProc = $$table{CHECK_PROC};
|
@@ -6621,6 +6621,11 @@ sub WriteJPEG($$)
|
|
6621
6621
|
$segType = 'Ricoh RMETA';
|
6622
6622
|
$$delGroup{RMETA} and $del = 1;
|
6623
6623
|
}
|
6624
|
+
} elsif ($marker == 0xe8 or $marker == 0xe9) { # APP8/9 (SEAL)
|
6625
|
+
if ($$segDataPt =~ /^SEAL\0/) {
|
6626
|
+
$segType = 'SEAL';
|
6627
|
+
$$delGroup{SEAL} and $del = 1;
|
6628
|
+
}
|
6624
6629
|
} elsif ($marker == 0xeb) { # APP10 (JUMBF)
|
6625
6630
|
if ($$segDataPt =~ /^JP/) {
|
6626
6631
|
$segType = 'JUMBF';
|
@@ -6987,7 +6992,7 @@ sub SetFileTime($$;$$$$)
|
|
6987
6992
|
# get Win32 handle, needed for SetFileTime
|
6988
6993
|
my $win32Handle = eval { Win32API::File::GetOsFHandle($file) };
|
6989
6994
|
unless ($win32Handle) {
|
6990
|
-
$self->Warn('Win32API::File
|
6995
|
+
$self->Warn('Win32API::File GetOsFHandle returned invalid handle');
|
6991
6996
|
return 0;
|
6992
6997
|
}
|
6993
6998
|
# convert Unix seconds to FILETIME structs
|
@@ -7005,13 +7010,13 @@ sub SetFileTime($$;$$$$)
|
|
7005
7010
|
return 0 if defined $k32SetFileTime;
|
7006
7011
|
$k32SetFileTime = Win32::API->new('KERNEL32', 'SetFileTime', 'NPPP', 'I');
|
7007
7012
|
unless ($k32SetFileTime) {
|
7008
|
-
$self->Warn('Error
|
7013
|
+
$self->Warn('Error loading Win32::API SetFileTime');
|
7009
7014
|
$k32SetFileTime = 0;
|
7010
7015
|
return 0;
|
7011
7016
|
}
|
7012
7017
|
}
|
7013
7018
|
unless ($k32SetFileTime->Call($win32Handle, $ctime, $atime, $mtime)) {
|
7014
|
-
$self->Warn('Win32::API
|
7019
|
+
$self->Warn('Win32::API SetFileTime returned ' . Win32::GetLastError());
|
7015
7020
|
return 0;
|
7016
7021
|
}
|
7017
7022
|
return 1;
|
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
|
|
50
50
|
use Image::ExifTool::GPS;
|
51
51
|
require Exporter;
|
52
52
|
|
53
|
-
$VERSION = '3.
|
53
|
+
$VERSION = '3.69';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -203,6 +203,7 @@ my %xmpNS = (
|
|
203
203
|
hdr_metadata => 'http://ns.adobe.com/hdr-metadata/1.0/',
|
204
204
|
hdrgm => 'http://ns.adobe.com/hdr-gain-map/1.0/',
|
205
205
|
xmpDSA => 'http://leica-camera.com/digital-shift-assistant/1.0/',
|
206
|
+
seal => 'http://ns.seal/2024/1.0/',
|
206
207
|
# Note: Google uses a prefix of 'Container', but this conflicts with the
|
207
208
|
# Device Container namespace, also by Google. So call this one GContainer
|
208
209
|
GContainer=> 'http://ns.google.com/photos/1.0/container/',
|
@@ -933,6 +934,10 @@ my %sRangeMask = (
|
|
933
934
|
Name => 'xmpDSA',
|
934
935
|
SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::DSA' },
|
935
936
|
},
|
937
|
+
seal => {
|
938
|
+
Name => 'seal',
|
939
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::seal' },
|
940
|
+
},
|
936
941
|
GContainer => {
|
937
942
|
Name => 'GContainer',
|
938
943
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::GContainer' },
|
@@ -4142,7 +4147,7 @@ sub ParseXMPElement($$$;$$$$)
|
|
4142
4147
|
|
4143
4148
|
#------------------------------------------------------------------------------
|
4144
4149
|
# Process XMP data
|
4145
|
-
# Inputs: 0) ExifTool
|
4150
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
4146
4151
|
# Returns: 1 on success
|
4147
4152
|
# Notes: The following flavours of XMP files are currently recognized:
|
4148
4153
|
# - standard XMP with xpacket, x:xmpmeta and rdf:RDF elements
|
@@ -25,6 +25,7 @@ use strict;
|
|
25
25
|
use Image::ExifTool qw(:Utils);
|
26
26
|
use Image::ExifTool::XMP;
|
27
27
|
|
28
|
+
sub ProcessSEAL($$;$);
|
28
29
|
sub Init_crd($);
|
29
30
|
|
30
31
|
#------------------------------------------------------------------------------
|
@@ -2290,6 +2291,65 @@ my %sACDSeeRegionStruct = (
|
|
2290
2291
|
},
|
2291
2292
|
);
|
2292
2293
|
|
2294
|
+
%Image::ExifTool::XMP::seal = (
|
2295
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-seal', 2 => 'Image' },
|
2296
|
+
NAMESPACE => 'seal',
|
2297
|
+
WRITABLE => 'string',
|
2298
|
+
NOTES => 'SEAL embedded in XMP.',
|
2299
|
+
seal => {
|
2300
|
+
Name => 'Seal',
|
2301
|
+
Binary => 1,
|
2302
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
|
2303
|
+
},
|
2304
|
+
);
|
2305
|
+
|
2306
|
+
%Image::ExifTool::XMP::SEAL = (
|
2307
|
+
GROUPS => { 0 => 'XML', 1 => 'SEAL', 2 => 'Document' },
|
2308
|
+
PROCESS_PROC => \&ProcessSEAL,
|
2309
|
+
NOTES => q{
|
2310
|
+
These tags are used in SEAL content authentification, which is actually XML
|
2311
|
+
format, not XMP. ExifTool has read/delete support for SEAL information in
|
2312
|
+
JPG, TIFF, XMP, PNG, WEBP, HEIC, PPM, MOV and MP4 files, and read-only
|
2313
|
+
support in PDF, MKV and WAV. Use C<-seal:all=> on the command line to
|
2314
|
+
delete SEAL information in supported formats.
|
2315
|
+
},
|
2316
|
+
seal=> 'SEALVersion',
|
2317
|
+
kv => 'KeyVersion',
|
2318
|
+
ka => 'KeyAlgorithm',
|
2319
|
+
da => 'DigestAlgorithm',
|
2320
|
+
sf => 'SignatureFormat',
|
2321
|
+
d => 'Domain',
|
2322
|
+
b => 'ByteRange',
|
2323
|
+
's' => 'Signature',
|
2324
|
+
info=> 'SEALComment',
|
2325
|
+
copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
2326
|
+
);
|
2327
|
+
|
2328
|
+
#------------------------------------------------------------------------------
|
2329
|
+
# We found a SEAL property name/value
|
2330
|
+
# Inputs: 0) ExifTool ref, 1) tag table ref, 2) xmp property list ref
|
2331
|
+
# 3) property value, 4) attribute hash ref
|
2332
|
+
# Returns: 1 if valid tag was found
|
2333
|
+
sub FoundSEAL($$$$;$)
|
2334
|
+
{
|
2335
|
+
my ($et, $tagTablePtr, $props, $val, $attrs) = @_;
|
2336
|
+
# remove 'seal' container property from name
|
2337
|
+
my @sealProps = @$props;
|
2338
|
+
shift @sealProps if @sealProps and $sealProps[0] eq 'seal';
|
2339
|
+
return FoundXMP($et, $tagTablePtr, \@sealProps, $val, $attrs);
|
2340
|
+
}
|
2341
|
+
|
2342
|
+
#------------------------------------------------------------------------------
|
2343
|
+
# Process SEAL XML
|
2344
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
2345
|
+
# Returns: 1 on success
|
2346
|
+
sub ProcessSEAL($$;$)
|
2347
|
+
{
|
2348
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
2349
|
+
$$dirInfo{XMPParseOpts}{FoundProc} = \&FoundSEAL;
|
2350
|
+
return ProcessXMP($et, $dirInfo, $tagTablePtr);
|
2351
|
+
}
|
2352
|
+
|
2293
2353
|
#------------------------------------------------------------------------------
|
2294
2354
|
# Generate crd tags
|
2295
2355
|
# Inputs: 0) tag table ref
|
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 = '13.
|
32
|
+
$VERSION = '13.03';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -4660,74 +4660,56 @@ sub EncodeFileName($$;$)
|
|
4660
4660
|
# References:
|
4661
4661
|
# - https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
|
4662
4662
|
# - https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
|
4663
|
+
# GetFullPathName supported by Windows XP and later. It handles:
|
4664
|
+
# full path names EG: c:\foto\sub\abc.jpg
|
4665
|
+
# relative EG: .\abc.jpg, ..\abc.jpg
|
4666
|
+
# full UNC paths EG: \\server\share\abc.jpg
|
4667
|
+
# relative UNC paths EG: .\abc.jpg, ..\abc.jpg
|
4668
|
+
# Dos device paths EG: \\.\c:\fotoabc.jpg
|
4669
|
+
# relative path on other drives EG: z:abc.jpg (working dir on z: z:\foto called from c:\foto)
|
4670
|
+
# Wide chars EG: Chars that need UTF8.
|
4671
|
+
my $k32GetFullPathName;
|
4663
4672
|
sub WindowsLongPath($$)
|
4664
4673
|
{
|
4665
4674
|
my ($self, $path) = @_;
|
4666
4675
|
my $debug = $$self{OPTIONS}{Debug};
|
4667
4676
|
my $out = $$self{OPTIONS}{TextOut};
|
4668
|
-
my @fullParts;
|
4669
|
-
my $prefixLen = 0;
|
4670
4677
|
|
4671
4678
|
$debug and print $out "WindowsLongPath input : $path\n";
|
4672
|
-
$path =~ tr(/)(\\); # convert slashes to backslashes
|
4673
|
-
my @pathParts = split /\\/, $path;
|
4674
4679
|
|
4675
|
-
|
4676
|
-
$path =~
|
4677
|
-
|
4678
|
-
|
4679
|
-
$
|
4680
|
-
|
4681
|
-
|
4682
|
-
|
4683
|
-
|
4684
|
-
|
4685
|
-
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
|
4690
|
-
|
4691
|
-
my $drive;
|
4692
|
-
$drive = $1 if $pathParts[0] =~ s/^([a-z]:)//;
|
4693
|
-
my $cwd = Cwd::getdcwd($drive); # ($drive is undef for current working drive)
|
4694
|
-
$debug and print $out "WindowsLongPath getcwd: $cwd\n";
|
4695
|
-
@fullParts = split /[\\\/]/, $cwd;
|
4696
|
-
# UNC path starts with "\\", so first 2 elements are empty
|
4697
|
-
# --> shift and put UNC in first element.
|
4698
|
-
if (@fullParts > 1 and $fullParts[0] eq '' and $fullParts[1] eq '') {
|
4699
|
-
shift @fullParts;
|
4700
|
-
$fullParts[0] = 'UNC';
|
4701
|
-
unshift @fullParts, '', '', '?';
|
4702
|
-
$prefixLen = (@fullParts > 6 ? 6 : @fullParts);
|
4703
|
-
} else {
|
4704
|
-
$prefixLen = 1; # drive designator only
|
4680
|
+
for (;;) { # (cheap goto)
|
4681
|
+
$path =~ tr(/)(\\); # convert slashes to backslashes
|
4682
|
+
last if $path =~ /^\\\\\?\\/; # already a device path in the format we want
|
4683
|
+
|
4684
|
+
unless ($k32GetFullPathName) { # need to import (once) GetFullPathNameW
|
4685
|
+
last if defined $k32GetFullPathName;
|
4686
|
+
unless (eval { require Win32::API }) {
|
4687
|
+
$self->WarnOnce('Install Win32::API to use WindowsLongPath option');
|
4688
|
+
last;
|
4689
|
+
}
|
4690
|
+
$k32GetFullPathName = Win32::API->new('KERNEL32', 'GetFullPathNameW', 'PNPP', 'I');
|
4691
|
+
unless ($k32GetFullPathName) {
|
4692
|
+
$k32GetFullPathName = 0;
|
4693
|
+
$self->Warn('Error loading Win32::API GetFullPathNameW');
|
4694
|
+
last;
|
4695
|
+
}
|
4705
4696
|
}
|
4706
|
-
|
4707
|
-
|
4708
|
-
|
4709
|
-
|
4710
|
-
$
|
4711
|
-
|
4712
|
-
|
4713
|
-
|
4714
|
-
|
4715
|
-
if ($
|
4716
|
-
|
4717
|
-
} elsif ($part eq '') {
|
4718
|
-
# only allow double slashes at start of path name (max 2)
|
4719
|
-
push @fullParts, $part if not @fullParts or (@fullParts == 1 and $fullParts[0] eq '');
|
4720
|
-
} elsif ($part eq '..') {
|
4721
|
-
# step up one directory, but not into the prefix
|
4722
|
-
pop @fullParts if @fullParts > $prefixLen;
|
4697
|
+
my $enc = $$self{OPTIONS}{CharsetFileName};
|
4698
|
+
my $encPath = $self->Encode($path, 'UTF16', 'II', $enc); # need to encode to UTF16
|
4699
|
+
my $lenReq = $k32GetFullPathName->Call($encPath,0,0,0) + 1; # first pass gets length required, +1 for safety (null?)
|
4700
|
+
my $fullPath = "\0" x $lenReq x 2; # create buffer to hold full path
|
4701
|
+
$k32GetFullPathName->Call($encPath, $lenReq, $fullPath, 0); # fullPath is UTF16 now
|
4702
|
+
$path = $self->Decode($fullPath, 'UTF16', 'II', $enc);
|
4703
|
+
|
4704
|
+
last if length($path) <= 247;
|
4705
|
+
|
4706
|
+
if ($path =~ /^\\\\/) {
|
4707
|
+
$path = '\\\\?\\UNC' . substr($path, 1);
|
4723
4708
|
} else {
|
4724
|
-
|
4709
|
+
$path = '\\\\?\\' . $path;
|
4725
4710
|
}
|
4711
|
+
last;
|
4726
4712
|
}
|
4727
|
-
$path = join '\\', @fullParts;
|
4728
|
-
# add device path prefix ("\\?\") if path length near the limit (the most
|
4729
|
-
# conservative limit I can find is 247, which is the limit on the directory name)
|
4730
|
-
$path = '\\\\?\\' . $path unless $prefixLen > 1 or length($path) <= 247;
|
4731
4713
|
$debug and print $out "WindowsLongPath return: $path\n";
|
4732
4714
|
return $path;
|
4733
4715
|
}
|
@@ -4861,16 +4843,16 @@ sub CreateDirectory($$)
|
|
4861
4843
|
my $d2 = $dir; # (must make a copy in case EncodeFileName recodes it)
|
4862
4844
|
if ($self->EncodeFileName($d2)) {
|
4863
4845
|
# handle Windows Unicode directory names
|
4864
|
-
unless (eval { require Win32::API }) {
|
4865
|
-
$err = 'Install Win32::API to create directories with Unicode names';
|
4866
|
-
last;
|
4867
|
-
}
|
4868
4846
|
unless (defined $k32CreateDir) {
|
4847
|
+
unless (eval { require Win32::API }) {
|
4848
|
+
$err = 'Install Win32::API to create directories with Unicode names';
|
4849
|
+
last;
|
4850
|
+
}
|
4869
4851
|
$k32CreateDir = Win32::API->new('KERNEL32', 'CreateDirectoryW', 'PP', 'I');
|
4870
4852
|
unless ($k32CreateDir) {
|
4871
4853
|
$k32CreateDir = 0;
|
4872
4854
|
# give this error once, then just "Error creating" for subsequent attempts
|
4873
|
-
return 'Error
|
4855
|
+
return 'Error loading Win32::API CreateDirectoryW';
|
4874
4856
|
}
|
4875
4857
|
}
|
4876
4858
|
$success = $k32CreateDir->Call($d2, 0) if $k32CreateDir;
|
@@ -4928,13 +4910,13 @@ sub GetFileTime($$)
|
|
4928
4910
|
return () if defined $k32GetFileTime;
|
4929
4911
|
$k32GetFileTime = Win32::API->new('KERNEL32', 'GetFileTime', 'NPPP', 'I');
|
4930
4912
|
unless ($k32GetFileTime) {
|
4931
|
-
$self->Warn('Error
|
4913
|
+
$self->Warn('Error loading Win32::API GetFileTime');
|
4932
4914
|
$k32GetFileTime = 0;
|
4933
4915
|
return ();
|
4934
4916
|
}
|
4935
4917
|
}
|
4936
4918
|
unless ($k32GetFileTime->Call($win32Handle, $ctime, $atime, $mtime)) {
|
4937
|
-
$self->Warn("Win32::API
|
4919
|
+
$self->Warn("Win32::API GetFileTime returned " . Win32::GetLastError());
|
4938
4920
|
return ();
|
4939
4921
|
}
|
4940
4922
|
# convert FILETIME structs to Unix seconds
|
@@ -5085,7 +5067,7 @@ sub IsSameID($$)
|
|
5085
5067
|
|
5086
5068
|
#------------------------------------------------------------------------------
|
5087
5069
|
# Get list of tags in specified group
|
5088
|
-
# Inputs: 0) ExifTool ref, 1) group spec, 2) tag key or reference to list of tag keys
|
5070
|
+
# Inputs: 0) ExifTool ref, 1) group spec (case insensitive), 2) tag key or reference to list of tag keys
|
5089
5071
|
# Returns: list of matching tags in list context, or first match in scalar context
|
5090
5072
|
# Notes: Group spec may contain multiple groups separated by colons, each
|
5091
5073
|
# possibly with a leading family number
|
@@ -6450,9 +6432,45 @@ sub ConvertDateTime($$)
|
|
6450
6432
|
my $fmt = $$self{OPTIONS}{DateFormat};
|
6451
6433
|
my $shift = $$self{OPTIONS}{GlobalTimeShift};
|
6452
6434
|
if ($shift) {
|
6453
|
-
my $dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
6454
6435
|
my $offset = $$self{GLOBAL_TIME_OFFSET};
|
6455
|
-
$
|
6436
|
+
my ($g, $t, $dir, @matches);
|
6437
|
+
if ($shift =~ s/^((\d?[A-Z][-\w]*\w:)*)([A-Z][-\w]*\w)([-+])//i) {
|
6438
|
+
($g, $t, $dir) = ($1, $3, ($4 eq '-' ? -1 : 1));
|
6439
|
+
} else {
|
6440
|
+
$dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
6441
|
+
}
|
6442
|
+
unless ($offset) {
|
6443
|
+
$offset = $$self{GLOBAL_TIME_OFFSET} = { };
|
6444
|
+
# (see forum16692 for a discussion about why this code was added)
|
6445
|
+
if ($t) {
|
6446
|
+
# determine initial shift from specified tag
|
6447
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
6448
|
+
if ($g and @matches) {
|
6449
|
+
$g =~ s/:$//;
|
6450
|
+
@matches = $self->GroupMatches($g, \@matches);
|
6451
|
+
}
|
6452
|
+
}
|
6453
|
+
if (not @matches and $$self{TAGS_FROM_FILE} and $$self{OPTIONS}{RequestTags}) {
|
6454
|
+
# determine initial shift from first requested date/time tag
|
6455
|
+
my @reqDate = grep /date/i, @{$$self{OPTIONS}{RequestTags}};
|
6456
|
+
while (@reqDate) {
|
6457
|
+
$t = shift @reqDate;
|
6458
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
6459
|
+
my $ti = $$self{TAG_INFO};
|
6460
|
+
for (; @matches; shift @matches) {
|
6461
|
+
# select the first tag that calls this routine in its PrintConv
|
6462
|
+
next unless $$ti{$matches[0]}{PrintConv};
|
6463
|
+
next unless $$ti{$matches[0]}{PrintConv} =~ /ConvertDateTime/;
|
6464
|
+
undef @reqDate;
|
6465
|
+
last;
|
6466
|
+
}
|
6467
|
+
}
|
6468
|
+
}
|
6469
|
+
if (@matches) {
|
6470
|
+
my $val = $self->GetValue($matches[0], 'ValueConv');
|
6471
|
+
ShiftTime($val, $shift, $dir, $offset) if defined $val;
|
6472
|
+
}
|
6473
|
+
}
|
6456
6474
|
ShiftTime($date, $shift, $dir, $offset);
|
6457
6475
|
}
|
6458
6476
|
# only convert date if a format was specified and the date is recognizable
|
@@ -7952,6 +7970,10 @@ sub ProcessJPEG($$;$)
|
|
7952
7970
|
SetByteOrder('II');
|
7953
7971
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Isothermal');
|
7954
7972
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
7973
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
7974
|
+
$dumpType = 'SEAL';
|
7975
|
+
DirStart(\%dirInfo, 5);
|
7976
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
7955
7977
|
}
|
7956
7978
|
} elsif ($marker == 0xe9) { # APP9 (InfiRay, Media Jukebox)
|
7957
7979
|
if ($$segDataPt =~ /^Media Jukebox\0/ and $length > 22) {
|
@@ -7967,6 +7989,10 @@ sub ProcessJPEG($$;$)
|
|
7967
7989
|
SetByteOrder('II');
|
7968
7990
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Sensor');
|
7969
7991
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
7992
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
7993
|
+
$dumpType = 'SEAL';
|
7994
|
+
DirStart(\%dirInfo, 5);
|
7995
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
7970
7996
|
}
|
7971
7997
|
} elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments)
|
7972
7998
|
if ($$segDataPt =~ /^UNICODE\0/) {
|
@@ -9102,6 +9128,7 @@ sub HandleTag($$$$;%)
|
|
9102
9128
|
Base => $parms{Base},
|
9103
9129
|
Multi => $$subdir{Multi},
|
9104
9130
|
TagInfo => $tagInfo,
|
9131
|
+
IgnoreProp => $$subdir{IgnoreProp},
|
9105
9132
|
RAF => $parms{RAF},
|
9106
9133
|
);
|
9107
9134
|
my $oldOrder = GetByteOrder();
|