exiftool-vendored.pl 12.84.0 → 12.89.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 +94 -3
- package/bin/MANIFEST +1 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +16 -16
- package/bin/README +47 -46
- package/bin/build_geolocation +96 -20
- package/bin/config_files/example.config +5 -0
- package/bin/config_files/onone.config +28 -0
- package/bin/exiftool +67 -57
- package/bin/lib/Image/ExifTool/AIFF.pm +8 -4
- package/bin/lib/Image/ExifTool/ASF.pm +4 -1
- package/bin/lib/Image/ExifTool/Apple.pm +2 -1
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +14 -8
- package/bin/lib/Image/ExifTool/Canon.pm +100 -7
- package/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
- package/bin/lib/Image/ExifTool/CanonVRD.pm +5 -2
- package/bin/lib/Image/ExifTool/DPX.pm +3 -3
- package/bin/lib/Image/ExifTool/FujiFilm.pm +46 -4
- package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/lib/Image/ExifTool/Geolocation.pm +18 -8
- package/bin/lib/Image/ExifTool/ID3.pm +36 -8
- package/bin/lib/Image/ExifTool/InDesign.pm +8 -4
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +0 -1
- package/bin/lib/Image/ExifTool/Lang/de.pm +2 -2
- package/bin/lib/Image/ExifTool/Matroska.pm +66 -10
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +21 -2
- package/bin/lib/Image/ExifTool/Olympus.pm +27 -17
- package/bin/lib/Image/ExifTool/Panasonic.pm +1 -0
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
- package/bin/lib/Image/ExifTool/Pentax.pm +139 -22
- package/bin/lib/Image/ExifTool/QuickTime.pm +70 -16
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +24 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +20 -10
- package/bin/lib/Image/ExifTool/Samsung.pm +29 -1
- package/bin/lib/Image/ExifTool/Sony.pm +21 -11
- package/bin/lib/Image/ExifTool/TagLookup.pm +6806 -6782
- package/bin/lib/Image/ExifTool/TagNames.pod +124 -34
- package/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +86 -16
- package/bin/lib/Image/ExifTool/Writer.pl +8 -6
- package/bin/lib/Image/ExifTool/XMP.pm +10 -8
- package/bin/lib/Image/ExifTool/XMP2.pl +51 -30
- package/bin/lib/Image/ExifTool/ZIP.pm +8 -4
- package/bin/lib/Image/ExifTool.pm +78 -45
- package/bin/lib/Image/ExifTool.pod +66 -50
- package/bin/perl-Image-ExifTool.spec +45 -45
- package/bin/pp_build_exe.args +4 -4
- package/package.json +3 -3
|
@@ -101,8 +101,22 @@ my %sPose = (
|
|
|
101
101
|
my %sEarthPose = (
|
|
102
102
|
STRUCT_NAME => 'EarthPose',
|
|
103
103
|
NAMESPACE => { EarthPose => 'http://ns.google.com/photos/dd/1.0/earthpose/' },
|
|
104
|
-
Latitude => {
|
|
105
|
-
|
|
104
|
+
Latitude => {
|
|
105
|
+
Writable => 'real',
|
|
106
|
+
Groups => { 2 => 'Location' },
|
|
107
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
108
|
+
ValueConvInv => '$val',
|
|
109
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
|
110
|
+
PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")',
|
|
111
|
+
},
|
|
112
|
+
Longitude => {
|
|
113
|
+
Writable => 'real',
|
|
114
|
+
Groups => { 2 => 'Location' },
|
|
115
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
116
|
+
ValueConvInv => '$val',
|
|
117
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
|
118
|
+
PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")',
|
|
119
|
+
},
|
|
106
120
|
Altitude => {
|
|
107
121
|
Writable => 'real',
|
|
108
122
|
Groups => { 2 => 'Location' },
|
|
@@ -1921,6 +1935,7 @@ my %sACDSeeRegionStruct = (
|
|
|
1921
1935
|
SpecialTypeID => { List => 'Bag' },
|
|
1922
1936
|
PortraitNote => { },
|
|
1923
1937
|
DisableAutoCreation => { List => 'Bag' },
|
|
1938
|
+
DisableSuggestedAction => { List => 'Bag' }, #forum16147
|
|
1924
1939
|
hdrp_makernote => {
|
|
1925
1940
|
Name => 'HDRPMakerNote',
|
|
1926
1941
|
# decoded data starts with the following bytes, but nothing yet is known about its contents:
|
|
@@ -2109,35 +2124,41 @@ my %sACDSeeRegionStruct = (
|
|
|
2109
2124
|
);
|
|
2110
2125
|
|
|
2111
2126
|
# Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
|
|
2112
|
-
# NOTE:
|
|
2127
|
+
# NOTE: The namespace prefix used by ExifTool is 'GContainer' instead of 'Container'
|
|
2128
|
+
# dueo to a conflict with Google's depth-map Device 'Container' namespace!
|
|
2113
2129
|
# (see ../pics/GooglePixel8Pro.jpg sample image)
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
#
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2130
|
+
%Image::ExifTool::XMP::GContainer = (
|
|
2131
|
+
%xmpTableDefaults,
|
|
2132
|
+
GROUPS => { 1 => 'XMP-GContainer', 2 => 'Image' },
|
|
2133
|
+
NAMESPACE => 'GContainer',
|
|
2134
|
+
NOTES => q{
|
|
2135
|
+
Google Container namespace. ExifTool uses the prefix 'GContainer' instead
|
|
2136
|
+
of 'Container' to avoid a conflict with the Google Device Container
|
|
2137
|
+
namespace.
|
|
2138
|
+
},
|
|
2139
|
+
Directory => {
|
|
2140
|
+
Name => 'ContainerDirectory',
|
|
2141
|
+
FlatName => 'Directory',
|
|
2142
|
+
List => 'Seq',
|
|
2143
|
+
Struct => {
|
|
2144
|
+
STRUCT_NAME => 'Directory',
|
|
2145
|
+
Item => {
|
|
2146
|
+
Namespace => 'GContainer',
|
|
2147
|
+
Struct => {
|
|
2148
|
+
STRUCT_NAME => 'Item',
|
|
2149
|
+
# (use 'GItem' to avoid conflict with Google Device Container Item)
|
|
2150
|
+
NAMESPACE => { GItem => 'http://ns.google.com/photos/1.0/container/item/'},
|
|
2151
|
+
Mime => { },
|
|
2152
|
+
Semantic => { },
|
|
2153
|
+
Length => { Writable => 'integer' },
|
|
2154
|
+
Label => { },
|
|
2155
|
+
Padding => { Writable => 'integer' },
|
|
2156
|
+
URI => { },
|
|
2157
|
+
},
|
|
2158
|
+
},
|
|
2159
|
+
},
|
|
2160
|
+
},
|
|
2161
|
+
);
|
|
2141
2162
|
|
|
2142
2163
|
# Getty Images namespace (ref PH)
|
|
2143
2164
|
%Image::ExifTool::XMP::GettyImages = (
|
|
@@ -20,7 +20,7 @@ use strict;
|
|
|
20
20
|
use vars qw($VERSION $warnString);
|
|
21
21
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
22
22
|
|
|
23
|
-
$VERSION = '1.
|
|
23
|
+
$VERSION = '1.32';
|
|
24
24
|
|
|
25
25
|
sub WarnProc($) { $warnString = $_[0]; }
|
|
26
26
|
|
|
@@ -325,9 +325,13 @@ sub ProcessRAR($$)
|
|
|
325
325
|
last if $size < 0;
|
|
326
326
|
next unless $size; # ignore blocks with no data
|
|
327
327
|
# don't try to read very large blocks unless LargeFileSupport is enabled
|
|
328
|
-
if ($size >= 0x80000000
|
|
329
|
-
$et->
|
|
330
|
-
|
|
328
|
+
if ($size >= 0x80000000) {
|
|
329
|
+
if (not $et->Options('LargeFileSupport')) {
|
|
330
|
+
$et->Warn('Large block encountered. Aborting.');
|
|
331
|
+
last;
|
|
332
|
+
} elsif ($et->Options('LargeFileSupport') eq '2') {
|
|
333
|
+
$et->WarnOnce('Processing large block (LargeFileSupport is 2)');
|
|
334
|
+
}
|
|
331
335
|
}
|
|
332
336
|
# process the block
|
|
333
337
|
if ($type == 0x74) { # file block
|
|
@@ -27,9 +27,9 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
|
|
|
27
27
|
%noWriteFile %magicNumber @langs $defaultLang %langName %charsetName
|
|
28
28
|
%mimeType $swapBytes $swapWords $currentByteOrder %unpackStd
|
|
29
29
|
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
|
30
|
-
%static_vars);
|
|
30
|
+
%static_vars $advFmtSelf);
|
|
31
31
|
|
|
32
|
-
$VERSION = '12.
|
|
32
|
+
$VERSION = '12.89';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -145,17 +145,18 @@ sub ReadValue($$$;$$$);
|
|
|
145
145
|
SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions
|
|
146
146
|
WPG ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
|
147
147
|
PCX PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
|
|
148
|
-
Photoshop::Layers Photoshop::ImageData FujiFilm::
|
|
149
|
-
FujiFilm::MRAW Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD
|
|
150
|
-
ID3::Lyrics3 FLAC AAC Ogg Vorbis APE APE::NewHeader
|
|
151
|
-
MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime
|
|
152
|
-
QuickTime::Stream QuickTime::Tags360Fly Matroska
|
|
153
|
-
Flash Flash::FLV Real::Media Real::Audio
|
|
154
|
-
WTV DICOM FITS XISF MIE JSON HTML XMP::SVG
|
|
155
|
-
|
|
156
|
-
EXE::AR EXE::CHM LNK Font VCard Text
|
|
157
|
-
Rawzor ZIP ZIP::GZIP ZIP::RAR ZIP::RAR5
|
|
158
|
-
FLIR::FPF MacOS MacOS::MDItem
|
|
148
|
+
Photoshop::Layers Photoshop::ImageData FujiFilm::RAFHeader FujiFilm::RAF
|
|
149
|
+
FujiFilm::IFD FujiFilm::MRAW Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD
|
|
150
|
+
Sony::PMP ITC ID3 ID3::Lyrics3 FLAC AAC Ogg Vorbis APE APE::NewHeader
|
|
151
|
+
APE::OldHeader Audible MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime
|
|
152
|
+
QuickTime::ImageFile QuickTime::Stream QuickTime::Tags360Fly Matroska
|
|
153
|
+
Matroska::StdTag MOI MXF DV Flash Flash::FLV Real::Media Real::Audio
|
|
154
|
+
Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS XISF MIE JSON HTML XMP::SVG
|
|
155
|
+
Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString
|
|
156
|
+
EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard Text
|
|
157
|
+
VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR ZIP::RAR5
|
|
158
|
+
RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
|
|
159
|
+
FlashPix::DocTable
|
|
159
160
|
);
|
|
160
161
|
|
|
161
162
|
# alphabetical list of current Lang modules
|
|
@@ -198,7 +199,7 @@ $defaultLang = 'en'; # default language
|
|
|
198
199
|
RAR 7Z BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font
|
|
199
200
|
JUMBF RSRC M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard
|
|
200
201
|
LRI R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD
|
|
201
|
-
ICO TXT AAC);
|
|
202
|
+
NKA ICO TXT AAC);
|
|
202
203
|
|
|
203
204
|
# file types that we can write (edit)
|
|
204
205
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
|
@@ -210,7 +211,7 @@ my %writeTypes; # lookup for writable file types (hash filled if required)
|
|
|
210
211
|
# (See here for 3FR reason: https://exiftool.org/forum/index.php?msg=17570)
|
|
211
212
|
%noWriteFile = (
|
|
212
213
|
TIFF => [ qw(3FR DCR K25 KDC SRF) ],
|
|
213
|
-
XMP => [ qw(SVG INX) ],
|
|
214
|
+
XMP => [ qw(SVG INX NXD) ],
|
|
214
215
|
JP2 => [ qw(J2C JPC) ],
|
|
215
216
|
MOV => [ qw(INSV) ],
|
|
216
217
|
);
|
|
@@ -426,10 +427,12 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
426
427
|
# NDPI => ['TIFF', 'Hamamatsu NanoZoomer Digital Pathology Image'],
|
|
427
428
|
NEF => ['TIFF', 'Nikon (RAW) Electronic Format'],
|
|
428
429
|
NEWER => 'COS',
|
|
430
|
+
NKA => ['NKA', 'Nikon NX Studio Adjustments'],
|
|
429
431
|
NKSC => ['XMP', 'Nikon Sidecar'],
|
|
430
432
|
NMBTEMPLATE => ['ZIP','Apple Numbers Template'],
|
|
431
433
|
NRW => ['TIFF', 'Nikon RAW (2)'],
|
|
432
434
|
NUMBERS => ['ZIP','Apple Numbers spreadsheet'],
|
|
435
|
+
NXD => ['XMP', 'Nikon NX-D Settings'],
|
|
433
436
|
O => ['EXE', 'Relocatable Object'],
|
|
434
437
|
ODB => ['ZIP', 'Open Document Database'],
|
|
435
438
|
ODC => ['ZIP', 'Open Document Chart'],
|
|
@@ -869,6 +872,7 @@ my %moduleName = (
|
|
|
869
872
|
MKV => 'Matroska',
|
|
870
873
|
MP3 => 'ID3',
|
|
871
874
|
MRW => 'MinoltaRaw',
|
|
875
|
+
NKA => 'Nikon',
|
|
872
876
|
OGG => 'Ogg',
|
|
873
877
|
ORF => 'Olympus',
|
|
874
878
|
PDB => 'Palm',
|
|
@@ -972,6 +976,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
972
976
|
MRC => '.{64}[\x01\x02\x03]\0\0\0[\x01\x02\x03]\0\0\0[\x01\x02\x03]\0\0\0.{132}MAP[\0 ](\x44\x44|\x44\x41|\x11\x11)\0\0',
|
|
973
977
|
MRW => '\0MR[MI]',
|
|
974
978
|
MXF => '\x06\x0e\x2b\x34\x02\x05\x01\x01\x0d\x01\x02', # (not tested if extension recognized)
|
|
979
|
+
NKA => 'NIKONADJ',
|
|
975
980
|
OGG => '(OggS|ID3)',
|
|
976
981
|
ORF => '(II|MM)',
|
|
977
982
|
# PCD => signature is at byte 2048
|
|
@@ -1123,7 +1128,7 @@ my @availableOptions = (
|
|
|
1123
1128
|
[ 'IgnoreTags', undef, 'list of tags to ignore when extracting' ],
|
|
1124
1129
|
[ 'ImageHashType', 'MD5', 'image hash algorithm' ],
|
|
1125
1130
|
[ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
|
|
1126
|
-
[ 'LargeFileSupport',
|
|
1131
|
+
[ 'LargeFileSupport', 1, 'flag indicating support of 64-bit file offsets' ],
|
|
1127
1132
|
[ 'LimitLongValues', 60, 'length limit for long values' ],
|
|
1128
1133
|
[ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]' ],
|
|
1129
1134
|
[ 'ListItem', undef, 'used to return a specific item from lists' ],
|
|
@@ -1269,6 +1274,7 @@ my %systemTagsNotes = (
|
|
|
1269
1274
|
},
|
|
1270
1275
|
Writable => 1,
|
|
1271
1276
|
WritePseudo => 1,
|
|
1277
|
+
Priority => 2,
|
|
1272
1278
|
DelCheck => q{"Can't delete"},
|
|
1273
1279
|
Protected => 1,
|
|
1274
1280
|
RawConv => '$self->ConvertFileName($val)',
|
|
@@ -1281,6 +1287,7 @@ my %systemTagsNotes = (
|
|
|
1281
1287
|
WritePseudo => 1,
|
|
1282
1288
|
DelCheck => q{"Can't delete"},
|
|
1283
1289
|
Protected => 1,
|
|
1290
|
+
Priority => 2,
|
|
1284
1291
|
Notes => q{
|
|
1285
1292
|
may be written with a full path name to set FileName and Directory in one
|
|
1286
1293
|
operation. This is such a powerful feature that a TestName tag is provided
|
|
@@ -1293,6 +1300,7 @@ my %systemTagsNotes = (
|
|
|
1293
1300
|
},
|
|
1294
1301
|
BaseName => {
|
|
1295
1302
|
Groups => { 1 => 'System', 2 => 'Other' },
|
|
1303
|
+
Priority => 2,
|
|
1296
1304
|
Notes => q{
|
|
1297
1305
|
file name without extension. Not generated unless specifically requested or
|
|
1298
1306
|
the API L<RequestAll|../ExifTool.html#RequestAll> option is set
|
|
@@ -1362,6 +1370,7 @@ my %systemTagsNotes = (
|
|
|
1362
1370
|
},
|
|
1363
1371
|
FileType => {
|
|
1364
1372
|
Groups => { 2 => 'Other' },
|
|
1373
|
+
Priority => 2,
|
|
1365
1374
|
Notes => q{
|
|
1366
1375
|
a short description of the file type. For many file types this is the just
|
|
1367
1376
|
the uppercase file extension
|
|
@@ -1807,6 +1816,7 @@ my %systemTagsNotes = (
|
|
|
1807
1816
|
PrintConv => 'sprintf("%.3g s", $val)',
|
|
1808
1817
|
},
|
|
1809
1818
|
RAFVersion => { Notes => 'RAF file version number' },
|
|
1819
|
+
RAFCompression => { PrintConv => { 0 => 'Uncompressed', 2 => 'Compressed' } }, # 1 maybe lossy?
|
|
1810
1820
|
JPEGDigest => {
|
|
1811
1821
|
Notes => q{
|
|
1812
1822
|
an MD5 digest of the JPEG quantization tables is combined with the component
|
|
@@ -2031,6 +2041,8 @@ my %systemTagsNotes = (
|
|
|
2031
2041
|
my $lat = 1;
|
|
2032
2042
|
foreach (@args) {
|
|
2033
2043
|
next unless /^[-+]?\d/;
|
|
2044
|
+
my @reals = /\.\d+/g;
|
|
2045
|
+
next if @reals > 1; # (allow floating "lat lon" format)
|
|
2034
2046
|
require Image::ExifTool::GPS;
|
|
2035
2047
|
$_ = Image::ExifTool::GPS::ToDegrees($_, 1, $lat ? 'lat' : 'lon');
|
|
2036
2048
|
$lat ^= 1;
|
|
@@ -2050,7 +2062,8 @@ my %systemTagsNotes = (
|
|
|
2050
2062
|
GeolocationCountry => { %geoInfo, Notes => 'geolocation country name', ValueConv => '$self->Decode($val,"UTF8")' },
|
|
2051
2063
|
GeolocationCountryCode=>{%geoInfo, Notes => 'geolocation country code' },
|
|
2052
2064
|
GeolocationTimeZone => { %geoInfo, Notes => 'geolocation time zone ID' },
|
|
2053
|
-
GeolocationFeatureCode=>{%geoInfo, Notes => 'feature code, see L<http://www.geonames.org/export/codes.html#P>' },
|
|
2065
|
+
GeolocationFeatureCode=>{%geoInfo, Notes => 'geolocation feature code, see L<http://www.geonames.org/export/codes.html#P>' },
|
|
2066
|
+
GeolocationFeatureType=>{%geoInfo, Notes => 'geolocation feature type' },
|
|
2054
2067
|
GeolocationPopulation=>{ %geoInfo, Notes => 'city population rounded to 2 significant digits' },
|
|
2055
2068
|
GeolocationDistance => { %geoInfo, Notes => 'distance in km from current GPS to city', PrintConv => '"$val km"' },
|
|
2056
2069
|
GeolocationPosition => { %geoInfo, Notes => 'approximate GPS coordinates of city',
|
|
@@ -2796,6 +2809,7 @@ sub ExtractInfo($;@)
|
|
|
2796
2809
|
# (note that Windows directories will still show the
|
|
2797
2810
|
# daylight savings time bug -- should fix this sometime)
|
|
2798
2811
|
@stat = stat $$raf{FILE_PT};
|
|
2812
|
+
$stat[7] = undef if -p $$raf{FILE_PT}; # (pipe buffer size isn't useful)
|
|
2799
2813
|
}
|
|
2800
2814
|
my $fileSize = $stat[7];
|
|
2801
2815
|
$self->FoundTag('FileSize', $stat[7]) if defined $stat[7];
|
|
@@ -4144,7 +4158,8 @@ sub GetFileType(;$$)
|
|
|
4144
4158
|
#------------------------------------------------------------------------------
|
|
4145
4159
|
# Return true if we can write the specified file type
|
|
4146
4160
|
# Inputs: 0) file name or ext
|
|
4147
|
-
# Returns: true if writable, 0 if not writable,
|
|
4161
|
+
# Returns: true if writable, 0 if not writable, '' if not writable due to extension,
|
|
4162
|
+
# undef if unrecognized
|
|
4148
4163
|
sub CanWrite($)
|
|
4149
4164
|
{
|
|
4150
4165
|
local $_;
|
|
@@ -4153,7 +4168,7 @@ sub CanWrite($)
|
|
|
4153
4168
|
if ($noWriteFile{$type}) {
|
|
4154
4169
|
# can't write TIFF files with certain extensions (various RAW formats)
|
|
4155
4170
|
my $ext = GetFileExtension($file) || uc($file);
|
|
4156
|
-
return grep(/^$ext$/, @{$noWriteFile{$type}}) ?
|
|
4171
|
+
return grep(/^$ext$/, @{$noWriteFile{$type}}) ? '' : 1 if $ext;
|
|
4157
4172
|
}
|
|
4158
4173
|
if ($onlyWriteFile{$type}) {
|
|
4159
4174
|
my $ext = GetFileExtension($file) || uc($file);
|
|
@@ -4387,6 +4402,7 @@ sub DoneExtract($)
|
|
|
4387
4402
|
$self->FoundTag(GeolocationCountry => $geo[4]) if $geo[4];
|
|
4388
4403
|
$self->FoundTag(GeolocationTimeZone => $geo[5]) if $geo[5];
|
|
4389
4404
|
$self->FoundTag(GeolocationFeatureCode => $geo[6]);
|
|
4405
|
+
$self->FoundTag(GeolocationFeatureType => $geo[10]) if $geo[10];
|
|
4390
4406
|
$self->FoundTag(GeolocationPopulation => $geo[7]);
|
|
4391
4407
|
$self->FoundTag(GeolocationPosition => "$geo[8] $geo[9]");
|
|
4392
4408
|
if ($dist) {
|
|
@@ -6849,11 +6865,12 @@ sub DirStart($$;$)
|
|
|
6849
6865
|
#------------------------------------------------------------------------------
|
|
6850
6866
|
# Extract metadata from a jpg image
|
|
6851
6867
|
# Inputs: 0) ExifTool object reference, 1) dirInfo ref with RAF set
|
|
6868
|
+
# 2) tag table ref to process JPEG-like metadata
|
|
6852
6869
|
# Returns: 1 on success, 0 if this wasn't a valid JPEG file
|
|
6853
|
-
sub ProcessJPEG(
|
|
6870
|
+
sub ProcessJPEG($$;$)
|
|
6854
6871
|
{
|
|
6855
6872
|
local $_;
|
|
6856
|
-
my ($self, $dirInfo) = @_;
|
|
6873
|
+
my ($self, $dirInfo, $optionalTagTable) = @_;
|
|
6857
6874
|
my $options = $$self{OPTIONS};
|
|
6858
6875
|
my $verbose = $$options{Verbose};
|
|
6859
6876
|
my $out = $$options{TextOut};
|
|
@@ -6861,20 +6878,29 @@ sub ProcessJPEG($$)
|
|
|
6861
6878
|
my $raf = $$dirInfo{RAF};
|
|
6862
6879
|
my $req = $$self{REQ_TAG_LOOKUP};
|
|
6863
6880
|
my $htmlDump = $$self{HTML_DUMP};
|
|
6864
|
-
my %dumpParms = ( Out => $out );
|
|
6865
|
-
my ($ch, $s, $length, $hash, $hashsize);
|
|
6881
|
+
my %dumpParms = ( Out => $out, Prefix => $$self{INDENT} );
|
|
6882
|
+
my ($ch, $s, $length, $hash, $hashsize, $indent);
|
|
6866
6883
|
my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
|
|
6867
6884
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
|
6868
6885
|
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
|
6869
6886
|
|
|
6887
|
+
($indent = $$self{INDENT}) =~ s/ $//;
|
|
6888
|
+
unless ($raf) {
|
|
6889
|
+
$raf = File::RandomAccess->new($$dirInfo{DataPt});
|
|
6890
|
+
$self->VerboseDir('JPEG', undef, length(${$$dirInfo{DataPt}}));
|
|
6891
|
+
}
|
|
6870
6892
|
# get pointer to hash object if it exists and we are the top-level JPEG or JP2
|
|
6871
6893
|
if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
|
|
6872
6894
|
$hash = $$self{ImageDataHash};
|
|
6873
6895
|
$hashsize = 0;
|
|
6874
6896
|
}
|
|
6875
|
-
|
|
6876
6897
|
# check to be sure this is a valid JPG (or J2C, or EXV) file
|
|
6877
|
-
|
|
6898
|
+
if ($raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/) {
|
|
6899
|
+
undef $optionalTagTable;
|
|
6900
|
+
} else {
|
|
6901
|
+
return 0 unless $optionalTagTable and $s =~ /^\xff[\xe0-\xef]/;
|
|
6902
|
+
$raf->Seek(-2, 1) or $self->Error('Seek error'), return 1;
|
|
6903
|
+
}
|
|
6878
6904
|
if ($s eq "\xff\x01") {
|
|
6879
6905
|
return 0 unless $raf->Read($s, 5) == 5 and $s eq 'Exiv2';
|
|
6880
6906
|
$$self{FILE_TYPE} = 'EXV';
|
|
@@ -6892,7 +6918,7 @@ sub ProcessJPEG($$)
|
|
|
6892
6918
|
$$raf{NoBuffer} = 1 if $self->Options('FastScan'); # disable buffering in FastScan mode
|
|
6893
6919
|
|
|
6894
6920
|
$dumpParms{MaxLen} = 128 if $verbose < 4;
|
|
6895
|
-
if ($htmlDump) {
|
|
6921
|
+
if ($htmlDump and not $optionalTagTable) {
|
|
6896
6922
|
$dumpEnd = $raf->Tell();
|
|
6897
6923
|
my ($n, $t, $m) = $s eq 'Exiv2' ? (7,'EXV','TEM') : (2,'JPEG','SOI');
|
|
6898
6924
|
my $pos = $dumpEnd - $n;
|
|
@@ -6911,6 +6937,7 @@ sub ProcessJPEG($$)
|
|
|
6911
6937
|
Marker: for (;;) {
|
|
6912
6938
|
# set marker and data pointer for current segment
|
|
6913
6939
|
my $marker = $nextMarker;
|
|
6940
|
+
last if $marker and $marker < 0;
|
|
6914
6941
|
my $segDataPt = $nextSegDataPt;
|
|
6915
6942
|
my $segPos = $nextSegPos;
|
|
6916
6943
|
my $skipped;
|
|
@@ -6919,12 +6946,17 @@ sub ProcessJPEG($$)
|
|
|
6919
6946
|
#
|
|
6920
6947
|
# read ahead to the next segment unless we have reached EOI, SOS or SOD
|
|
6921
6948
|
#
|
|
6922
|
-
|
|
6949
|
+
until ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $hash) or
|
|
6923
6950
|
$marker==0x93))
|
|
6924
6951
|
{
|
|
6925
6952
|
# read up to next marker (JPEG markers begin with 0xff)
|
|
6926
6953
|
my $buff;
|
|
6927
|
-
$raf->ReadLine($buff)
|
|
6954
|
+
unless ($raf->ReadLine($buff)) {
|
|
6955
|
+
last Marker unless $optionalTagTable;
|
|
6956
|
+
$nextMarker = -1;
|
|
6957
|
+
$success = 1;
|
|
6958
|
+
last;
|
|
6959
|
+
}
|
|
6928
6960
|
$skipped = length($buff) - 1;
|
|
6929
6961
|
# JPEG markers can be padded with unlimited 0xff's
|
|
6930
6962
|
for (;;) {
|
|
@@ -6936,21 +6968,21 @@ sub ProcessJPEG($$)
|
|
|
6936
6968
|
# read segment data if it exists
|
|
6937
6969
|
if (not defined $markerLenBytes{$nextMarker}) {
|
|
6938
6970
|
# read record length word
|
|
6939
|
-
last unless $raf->Read($s, 2) == 2;
|
|
6971
|
+
last Marker unless $raf->Read($s, 2) == 2;
|
|
6940
6972
|
my $len = unpack('n',$s); # get data length
|
|
6941
|
-
last unless defined($len) and $len >= 2;
|
|
6973
|
+
last Marker unless defined($len) and $len >= 2;
|
|
6942
6974
|
$nextSegPos = $raf->Tell();
|
|
6943
6975
|
$len -= 2; # subtract size of length word
|
|
6944
|
-
last unless $raf->Read($buff, $len) == $len;
|
|
6976
|
+
last Marker unless $raf->Read($buff, $len) == $len;
|
|
6945
6977
|
$nextSegDataPt = \$buff; # set pointer to our next data
|
|
6946
6978
|
} elsif ($markerLenBytes{$nextMarker} == 4) {
|
|
6947
6979
|
# handle J2C extensions with 4-byte length word
|
|
6948
|
-
last unless $raf->Read($s, 4) == 4;
|
|
6980
|
+
last Marker unless $raf->Read($s, 4) == 4;
|
|
6949
6981
|
my $len = unpack('N',$s); # get data length
|
|
6950
|
-
last unless defined($len) and $len >= 4;
|
|
6982
|
+
last Marker unless defined($len) and $len >= 4;
|
|
6951
6983
|
$nextSegPos = $raf->Tell();
|
|
6952
6984
|
$len -= 4; # subtract size of length word
|
|
6953
|
-
last unless $raf->Seek($len, 1);
|
|
6985
|
+
last Marker unless $raf->Seek($len, 1);
|
|
6954
6986
|
} elsif ($hash and defined $marker and ($marker == 0x00 or $marker == 0xda or
|
|
6955
6987
|
($marker >= 0xd0 and $marker <= 0xd7)))
|
|
6956
6988
|
{
|
|
@@ -6966,7 +6998,8 @@ sub ProcessJPEG($$)
|
|
|
6966
6998
|
$hashsize += $skipped + 2;
|
|
6967
6999
|
}
|
|
6968
7000
|
# read second segment too if this was the first
|
|
6969
|
-
next unless defined $marker;
|
|
7001
|
+
next Marker unless defined $marker;
|
|
7002
|
+
last;
|
|
6970
7003
|
}
|
|
6971
7004
|
# set some useful variables for the current segment
|
|
6972
7005
|
my $markerName = JpegMarkerName($marker);
|
|
@@ -6986,7 +7019,7 @@ sub ProcessJPEG($$)
|
|
|
6986
7019
|
if (($marker & 0xf0) == 0xc0 and ($marker == 0xc0 or $marker & 0x03)) {
|
|
6987
7020
|
$length = length $$segDataPt;
|
|
6988
7021
|
if ($verbose) {
|
|
6989
|
-
print $out "JPEG $markerName ($length bytes):\n";
|
|
7022
|
+
print $out "${indent}JPEG $markerName ($length bytes):\n";
|
|
6990
7023
|
HexDump($segDataPt, undef, %dumpParms, Addr=>$segPos) if $verbose>2;
|
|
6991
7024
|
} elsif ($htmlDump) {
|
|
6992
7025
|
$self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
|
|
@@ -7029,7 +7062,7 @@ sub ProcessJPEG($$)
|
|
|
7029
7062
|
next;
|
|
7030
7063
|
} elsif ($marker == 0xd9) { # EOI
|
|
7031
7064
|
pop @$path;
|
|
7032
|
-
$verbose and print $out "JPEG EOI\n";
|
|
7065
|
+
$verbose and print $out "${indent}JPEG EOI\n";
|
|
7033
7066
|
my $pos = $raf->Tell();
|
|
7034
7067
|
$$self{TrailerStart} = $pos unless $$self{DOC_NUM};
|
|
7035
7068
|
if ($htmlDump and $dumpEnd) {
|
|
@@ -7090,7 +7123,7 @@ sub ProcessJPEG($$)
|
|
|
7090
7123
|
# adjust PreviewImageStart to this location
|
|
7091
7124
|
my $actual = $pos + pos($buff) - 4;
|
|
7092
7125
|
if ($start and $start ne $actual and $verbose > 1) {
|
|
7093
|
-
print $out "(Fixed PreviewImage location: $start -> $actual)\n";
|
|
7126
|
+
print $out "${indent}(Fixed PreviewImage location: $start -> $actual)\n";
|
|
7094
7127
|
}
|
|
7095
7128
|
# update preview image offsets
|
|
7096
7129
|
if ($start) {
|
|
@@ -7144,7 +7177,7 @@ sub ProcessJPEG($$)
|
|
|
7144
7177
|
pop @$path;
|
|
7145
7178
|
$foundSOS = 1;
|
|
7146
7179
|
# all done with meta information unless we have a trailer
|
|
7147
|
-
$verbose and print $out "JPEG SOS\n";
|
|
7180
|
+
$verbose and print $out "${indent}JPEG SOS\n";
|
|
7148
7181
|
unless ($fast) {
|
|
7149
7182
|
$trailInfo = IdentifyTrailer($raf);
|
|
7150
7183
|
# process trailer now unless we are doing verbose dump
|
|
@@ -7184,7 +7217,7 @@ sub ProcessJPEG($$)
|
|
|
7184
7217
|
last; # all done parsing file
|
|
7185
7218
|
} elsif ($marker == 0x93) {
|
|
7186
7219
|
pop @$path;
|
|
7187
|
-
$verbose and print $out "JPEG SOD\n";
|
|
7220
|
+
$verbose and print $out "${indent}JPEG SOD\n";
|
|
7188
7221
|
$success = 1;
|
|
7189
7222
|
if ($hash and $$self{FILE_TYPE} eq 'JP2') {
|
|
7190
7223
|
my $pos = $raf->Tell();
|
|
@@ -7195,7 +7228,7 @@ sub ProcessJPEG($$)
|
|
|
7195
7228
|
last; # all done parsing file
|
|
7196
7229
|
} elsif (defined $markerLenBytes{$marker}) {
|
|
7197
7230
|
# handle other stand-alone markers and segments we skipped over
|
|
7198
|
-
$verbose and $marker and print $out "JPEG $markerName\n";
|
|
7231
|
+
$verbose and $marker and print $out "${indent}JPEG $markerName\n";
|
|
7199
7232
|
next;
|
|
7200
7233
|
} elsif ($marker == 0xdb and length($$segDataPt) and # DQT
|
|
7201
7234
|
# save the DQT data only if JPEGDigest has been requested
|
|
@@ -7215,7 +7248,7 @@ sub ProcessJPEG($$)
|
|
|
7215
7248
|
$length = length $$segDataPt;
|
|
7216
7249
|
$appBytes += $length + 4 if ($marker & 0xf0) == 0xe0; # total size of APP segments
|
|
7217
7250
|
if ($verbose) {
|
|
7218
|
-
print $out "JPEG $markerName ($length bytes):\n";
|
|
7251
|
+
print $out "${indent}JPEG $markerName ($length bytes):\n";
|
|
7219
7252
|
if ($verbose > 2) {
|
|
7220
7253
|
my %extraParms = ( Addr => $segPos );
|
|
7221
7254
|
$extraParms{MaxLen} = 128 if $verbose == 4;
|
|
@@ -7373,7 +7406,7 @@ sub ProcessJPEG($$)
|
|
|
7373
7406
|
# some software erroneously writes zeros for the chunk counts)
|
|
7374
7407
|
my $chunkNum = Get8u($segDataPt, 6);
|
|
7375
7408
|
my $chunksTot = Get8u($segDataPt, 7) + 1; # (note the "+ 1"!)
|
|
7376
|
-
$verbose and printf $out "
|
|
7409
|
+
$verbose and printf $out "${indent}FLIR chunk %d of %d\n",
|
|
7377
7410
|
$chunkNum + 1, $chunksTot;
|
|
7378
7411
|
if (defined $flirTotal) {
|
|
7379
7412
|
# abort parsing FLIR if the total chunk count is inconsistent
|
|
@@ -7438,7 +7471,7 @@ sub ProcessJPEG($$)
|
|
|
7438
7471
|
# some software erroneously writes zeros for the chunk counts)
|
|
7439
7472
|
my $chunkNum = Get8u($segDataPt, 12);
|
|
7440
7473
|
my $chunksTot = Get8u($segDataPt, 13);
|
|
7441
|
-
$verbose and print $out "
|
|
7474
|
+
$verbose and print $out "${indent}ICC_Profile chunk $chunkNum of $chunksTot\n";
|
|
7442
7475
|
if (defined $iccChunksTotal) {
|
|
7443
7476
|
# abort parsing ICC_Profile if the total chunk count is inconsistent
|
|
7444
7477
|
undef $iccChunkCount if $chunksTot != $iccChunksTotal;
|
|
@@ -7991,7 +8024,7 @@ sub ProcessJPEG($$)
|
|
|
7991
8024
|
}
|
|
7992
8025
|
}
|
|
7993
8026
|
# print verbose hash message if necessary
|
|
7994
|
-
print $out "
|
|
8027
|
+
print $out "${indent}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
|
|
7995
8028
|
# calculate JPEGDigest if requested
|
|
7996
8029
|
if (@dqt) {
|
|
7997
8030
|
require Image::ExifTool::JPEGDigest;
|