exiftool-vendored.pl 12.56.0 → 12.62.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 +115 -5
- package/bin/LICENSE +674 -0
- package/bin/MANIFEST +11 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +45 -44
- package/bin/config_files/example.config +1 -0
- package/bin/config_files/rotate_regions.config +1 -1
- package/bin/exiftool +262 -160
- package/bin/lib/Image/ExifTool/AIFF.pm +2 -2
- package/bin/lib/Image/ExifTool/APE.pm +2 -2
- package/bin/lib/Image/ExifTool/BMP.pm +0 -1
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +23 -19
- package/bin/lib/Image/ExifTool/Canon.pm +26 -6
- package/bin/lib/Image/ExifTool/CanonRaw.pm +5 -1
- package/bin/lib/Image/ExifTool/DJI.pm +28 -2
- package/bin/lib/Image/ExifTool/Exif.pm +77 -19
- package/bin/lib/Image/ExifTool/FlashPix.pm +33 -10
- package/bin/lib/Image/ExifTool/FujiFilm.pm +7 -3
- package/bin/lib/Image/ExifTool/GPS.pm +7 -2
- package/bin/lib/Image/ExifTool/Geotag.pm +30 -7
- package/bin/lib/Image/ExifTool/JPEG.pm +14 -2
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +36 -11
- package/bin/lib/Image/ExifTool/LIF.pm +10 -2
- package/bin/lib/Image/ExifTool/LNK.pm +5 -4
- package/bin/lib/Image/ExifTool/MIE.pm +3 -3
- package/bin/lib/Image/ExifTool/MPEG.pm +2 -2
- package/bin/lib/Image/ExifTool/MakerNotes.pm +3 -2
- package/bin/lib/Image/ExifTool/Minolta.pm +6 -7
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -1
- package/bin/lib/Image/ExifTool/Nikon.pm +1005 -909
- package/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
- package/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
- package/bin/lib/Image/ExifTool/Olympus.pm +88 -6
- package/bin/lib/Image/ExifTool/PDF.pm +17 -8
- package/bin/lib/Image/ExifTool/PNG.pm +10 -2
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
- package/bin/lib/Image/ExifTool/Pentax.pm +8 -5
- package/bin/lib/Image/ExifTool/PhaseOne.pm +14 -1
- package/bin/lib/Image/ExifTool/Photoshop.pm +38 -7
- package/bin/lib/Image/ExifTool/QuickTime.pm +48 -14
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +91 -27
- package/bin/lib/Image/ExifTool/README +19 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +34 -13
- package/bin/lib/Image/ExifTool/Rawzor.pm +2 -2
- package/bin/lib/Image/ExifTool/Ricoh.pm +2 -1
- package/bin/lib/Image/ExifTool/Sigma.pm +5 -4
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +9 -3
- package/bin/lib/Image/ExifTool/Sony.pm +39 -10
- package/bin/lib/Image/ExifTool/TagLookup.pm +4687 -4628
- package/bin/lib/Image/ExifTool/TagNames.pod +338 -117
- package/bin/lib/Image/ExifTool/Validate.pm +5 -5
- package/bin/lib/Image/ExifTool/WPG.pm +296 -0
- package/bin/lib/Image/ExifTool/WriteExif.pl +42 -0
- package/bin/lib/Image/ExifTool/WritePDF.pl +7 -8
- package/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
- package/bin/lib/Image/ExifTool/Writer.pl +162 -40
- package/bin/lib/Image/ExifTool/XMP.pm +35 -8
- package/bin/lib/Image/ExifTool/XMP2.pl +2 -1
- package/bin/lib/Image/ExifTool/ZIP.pm +159 -41
- package/bin/lib/Image/ExifTool.pm +286 -65
- package/bin/lib/Image/ExifTool.pod +95 -51
- package/bin/perl-Image-ExifTool.spec +44 -43
- package/bin/pp_build_exe.args +5 -4
- package/package.json +3 -3
|
@@ -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);
|
|
31
31
|
|
|
32
|
-
$VERSION = '12.
|
|
32
|
+
$VERSION = '12.62';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -75,6 +75,7 @@ sub GetAllGroups($;$);
|
|
|
75
75
|
sub GetNewGroups($);
|
|
76
76
|
sub GetDeleteGroups();
|
|
77
77
|
sub AddUserDefinedTags($%);
|
|
78
|
+
sub SetAlternateFile($$$);
|
|
78
79
|
# non-public routines below
|
|
79
80
|
sub InsertTagValues($$$;$$$);
|
|
80
81
|
sub IsWritable($);
|
|
@@ -113,6 +114,7 @@ sub WriteTIFF($$$);
|
|
|
113
114
|
sub PackUTF8(@);
|
|
114
115
|
sub UnpackUTF8($);
|
|
115
116
|
sub SetPreferredByteOrder($;$);
|
|
117
|
+
sub ImageDataMD5($$$;$$);
|
|
116
118
|
sub CopyBlock($$$);
|
|
117
119
|
sub CopyFileAttrs($$$);
|
|
118
120
|
sub TimeNow(;$$);
|
|
@@ -140,8 +142,8 @@ sub ReadValue($$$;$$$);
|
|
|
140
142
|
@loadAllTables = qw(
|
|
141
143
|
PhotoMechanic Exif GeoTiff CanonRaw KyoceraRaw Lytro MinoltaRaw PanasonicRaw
|
|
142
144
|
SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions
|
|
143
|
-
ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
|
144
|
-
PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
|
|
145
|
+
WPG ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
|
146
|
+
PCX PGF PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header
|
|
145
147
|
Photoshop::Layers Photoshop::ImageData FujiFilm::RAF FujiFilm::IFD
|
|
146
148
|
Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD Sony::PMP ITC ID3 ID3::Lyrics3
|
|
147
149
|
FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible MPC MPEG::Audio
|
|
@@ -150,8 +152,9 @@ sub ReadValue($$$;$$$);
|
|
|
150
152
|
Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE
|
|
151
153
|
JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion
|
|
152
154
|
EXE::PEString EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard
|
|
153
|
-
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR
|
|
154
|
-
OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
|
|
155
|
+
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR
|
|
156
|
+
ZIP::RAR5 RTF OOXML iWork ISO FLIR::AFF FLIR::FPF MacOS MacOS::MDItem
|
|
157
|
+
FlashPix::DocTable
|
|
155
158
|
);
|
|
156
159
|
|
|
157
160
|
# alphabetical list of current Lang modules
|
|
@@ -188,12 +191,12 @@ $defaultLang = 'en'; # default language
|
|
|
188
191
|
# 3) PLIST must be in this list for the binary PLIST format, although it may
|
|
189
192
|
# cause a file to be checked twice for XML
|
|
190
193
|
@fileTypes = qw(JPEG EXV CRW DR4 TIFF GIF MRW RAF X3F JP2 PNG MIE MIFF PS PDF
|
|
191
|
-
PSD XMP BMP BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV
|
|
192
|
-
FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
|
193
|
-
HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR
|
|
194
|
-
CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC
|
|
195
|
-
MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA
|
|
196
|
-
PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD ICO TXT);
|
|
194
|
+
PSD XMP BMP WPG BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV
|
|
195
|
+
OGG FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
|
196
|
+
LFP HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR
|
|
197
|
+
BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC
|
|
198
|
+
M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA
|
|
199
|
+
PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD ICO TXT);
|
|
197
200
|
|
|
198
201
|
# file types that we can write (edit)
|
|
199
202
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
|
@@ -552,6 +555,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
552
555
|
XMP => ['XMP', 'Extensible Metadata Platform'],
|
|
553
556
|
WOFF => ['Font', 'Web Open Font Format'],
|
|
554
557
|
WOFF2=> ['Font', 'Web Open Font Format2'],
|
|
558
|
+
WPG => ['WPG', 'WordPerfect Graphics'],
|
|
555
559
|
WTV => ['WTV', 'Windows recorded TV show'],
|
|
556
560
|
ZIP => ['ZIP', 'ZIP archive'],
|
|
557
561
|
);
|
|
@@ -787,6 +791,7 @@ my %fileDescription = (
|
|
|
787
791
|
WMA => 'audio/x-ms-wma',
|
|
788
792
|
WMF => 'application/x-wmf',
|
|
789
793
|
WMV => 'video/x-ms-wmv',
|
|
794
|
+
WPG => 'image/x-wpg',
|
|
790
795
|
WTV => 'video/x-ms-wtv',
|
|
791
796
|
X3F => 'image/x-sigma-x3f',
|
|
792
797
|
XCF => 'image/x-xcf',
|
|
@@ -968,7 +973,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
968
973
|
QTIF => '.{4}(idsc|idat|iicc)',
|
|
969
974
|
R3D => '\0\0..RED(1|2)',
|
|
970
975
|
RAF => 'FUJIFILM',
|
|
971
|
-
RAR => 'Rar!\x1a\x07\0',
|
|
976
|
+
RAR => 'Rar!\x1a\x07\x01?\0',
|
|
972
977
|
RAW => '(.{25}ARECOYK|II|MM)',
|
|
973
978
|
Real => '(\.RMF|\.ra\xfd|pnm://|rtsp://|http://)',
|
|
974
979
|
RIFF => '(RIFF|LA0[234]|OFR |LPAC|wvpk|RF64)', # RIFF plus other variants
|
|
@@ -982,6 +987,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
982
987
|
VCard=> '(?i)BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n',
|
|
983
988
|
VRD => 'CANON OPTIONAL DATA\0',
|
|
984
989
|
WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)',
|
|
990
|
+
WPG => '\xff\x57\x50\x43',
|
|
985
991
|
WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d',
|
|
986
992
|
X3F => 'FOVb',
|
|
987
993
|
XCF => 'gimp xcf ',
|
|
@@ -1821,6 +1827,17 @@ my %systemTagsNotes = (
|
|
|
1821
1827
|
if specifically requested
|
|
1822
1828
|
},
|
|
1823
1829
|
},
|
|
1830
|
+
ImageDataMD5 => {
|
|
1831
|
+
Notes => q{
|
|
1832
|
+
MD5 of image data. Generated only if specifically requested for JPEG, TIFF,
|
|
1833
|
+
PNG, CRW, CR3, MRW, RAF, X3F, IIQ, JP2, JXL, HEIC and AVIF images, MOV/MP4
|
|
1834
|
+
videos, and some RIFF-based files such as AVI, WAV and WEBP. The MD5
|
|
1835
|
+
includes the main image data, plus JpgFromRaw/OtherImage for some formats,
|
|
1836
|
+
but does not include ThumbnailImage or PreviewImage. Includes video and
|
|
1837
|
+
audio data for MOV/MP4. The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool>
|
|
1838
|
+
provides a place to store these values in the file.
|
|
1839
|
+
},
|
|
1840
|
+
},
|
|
1824
1841
|
);
|
|
1825
1842
|
|
|
1826
1843
|
# tags defined by UserParam option (added at runtime)
|
|
@@ -2043,7 +2060,9 @@ sub new
|
|
|
2043
2060
|
$$self{DEL_GROUP} = { }; # lookup for groups to delete when writing
|
|
2044
2061
|
$$self{SAVE_COUNT} = 0; # count calls to SaveNewValues()
|
|
2045
2062
|
$$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
|
|
2063
|
+
$$self{FILES_WRITTEN} = 0; # count of files successfully written
|
|
2046
2064
|
$$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
|
|
2065
|
+
$$self{ALT_EXIFTOOL} = { }; # alternate exiftool objects
|
|
2047
2066
|
|
|
2048
2067
|
# initialize our new groups for writing
|
|
2049
2068
|
$self->SetNewGroups(@defaultWriteGroups);
|
|
@@ -2110,8 +2129,10 @@ sub Options($$;@)
|
|
|
2110
2129
|
|
|
2111
2130
|
while (@_) {
|
|
2112
2131
|
my $param = shift;
|
|
2132
|
+
my $plus;
|
|
2113
2133
|
# fix parameter case if necessary
|
|
2114
2134
|
unless (exists $$options{$param}) {
|
|
2135
|
+
$plus = $param =~ s/\+$//;
|
|
2115
2136
|
my ($fixed) = grep /^$param$/i, keys %$options;
|
|
2116
2137
|
if ($fixed) {
|
|
2117
2138
|
$param = $fixed;
|
|
@@ -2276,6 +2297,23 @@ sub Options($$;@)
|
|
|
2276
2297
|
$compact{$p} = $val; # preserve most recent setting
|
|
2277
2298
|
}
|
|
2278
2299
|
$$options{Compact} = $$options{XMPShorthand} = \%compact;
|
|
2300
|
+
} elsif ($param eq 'NoWarning') {
|
|
2301
|
+
# validate regular expression
|
|
2302
|
+
undef $evalWarning;
|
|
2303
|
+
if (defined $newVal) {
|
|
2304
|
+
local $SIG{'__WARN__'} = \&SetWarning;
|
|
2305
|
+
eval { $param =~ /$newVal/ };
|
|
2306
|
+
$@ and $evalWarning = $@;
|
|
2307
|
+
}
|
|
2308
|
+
if ($evalWarning) {
|
|
2309
|
+
warn 'NoWarning: ' . CleanWarning() . "\n";
|
|
2310
|
+
next;
|
|
2311
|
+
}
|
|
2312
|
+
# add to existing expression if specified
|
|
2313
|
+
if ($plus and defined $oldVal) {
|
|
2314
|
+
$newVal = defined $newVal ? "$oldVal|$newVal" : $oldVal;
|
|
2315
|
+
}
|
|
2316
|
+
$$options{$param} = $newVal;
|
|
2279
2317
|
} else {
|
|
2280
2318
|
if ($param eq 'Escape') {
|
|
2281
2319
|
# set ESCAPE_PROC
|
|
@@ -2370,6 +2408,7 @@ sub ClearOptions($)
|
|
|
2370
2408
|
MissingTagValue =>undef,# value for missing tags when expanded in expressions
|
|
2371
2409
|
NoMultiExif => undef, # raise error when writing multi-segment EXIF
|
|
2372
2410
|
NoPDFList => undef, # flag to avoid splitting PDF List-type tag values
|
|
2411
|
+
NoWarning => undef, # regular expression for warnings to suppress
|
|
2373
2412
|
Password => undef, # password for password-protected PDF documents
|
|
2374
2413
|
PrintConv => 1, # flag to enable print conversion
|
|
2375
2414
|
QuickTimeHandler => 1, # flag to add mdir Handler to newly created Meta box
|
|
@@ -2478,7 +2517,15 @@ sub ExtractInfo($;@)
|
|
|
2478
2517
|
$self->WarnOnce('Install Time::HiRes to generate ProcessingTime');
|
|
2479
2518
|
}
|
|
2480
2519
|
}
|
|
2481
|
-
|
|
2520
|
+
|
|
2521
|
+
# create MD5 object if ImageDataMD5 is requested
|
|
2522
|
+
if ($$req{imagedatamd5} and not $$self{ImageDataMD5}) {
|
|
2523
|
+
if (require Digest::MD5) {
|
|
2524
|
+
$$self{ImageDataMD5} = Digest::MD5->new;
|
|
2525
|
+
} else {
|
|
2526
|
+
$self->WarnOnce('Install Digest::MD5 to calculate image data MD5');
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2482
2529
|
++$$self{FILE_SEQUENCE}; # count files read
|
|
2483
2530
|
}
|
|
2484
2531
|
|
|
@@ -2621,7 +2668,7 @@ sub ExtractInfo($;@)
|
|
|
2621
2668
|
if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) {
|
|
2622
2669
|
$self->FoundTag('FileType', 'DIR');
|
|
2623
2670
|
$self->FoundTag('FileTypeExtension', '');
|
|
2624
|
-
$self->
|
|
2671
|
+
$self->ExtractAltInfo();
|
|
2625
2672
|
$raf->Close() if $raf;
|
|
2626
2673
|
return 1;
|
|
2627
2674
|
}
|
|
@@ -2639,7 +2686,7 @@ sub ExtractInfo($;@)
|
|
|
2639
2686
|
} else {
|
|
2640
2687
|
$self->Error('Unknown file type');
|
|
2641
2688
|
}
|
|
2642
|
-
$self->
|
|
2689
|
+
$self->ExtractAltInfo();
|
|
2643
2690
|
last; # don't read the file
|
|
2644
2691
|
}
|
|
2645
2692
|
if (@fileTypeList) {
|
|
@@ -2805,8 +2852,7 @@ sub ExtractInfo($;@)
|
|
|
2805
2852
|
}
|
|
2806
2853
|
unless ($reEntry) {
|
|
2807
2854
|
$$self{PATH} = [ ]; # reset PATH
|
|
2808
|
-
|
|
2809
|
-
$self->BuildCompositeTags() if $$options{Composite};
|
|
2855
|
+
$self->ExtractAltInfo();
|
|
2810
2856
|
# do our HTML dump if requested
|
|
2811
2857
|
if ($$self{HTML_DUMP}) {
|
|
2812
2858
|
$raf->Seek(0, 2); # seek to end of file
|
|
@@ -2869,6 +2915,10 @@ sub ExtractInfo($;@)
|
|
|
2869
2915
|
# restore necessary members when exiting re-entrant code
|
|
2870
2916
|
$$self{$_} = $$reEntry{$_} foreach keys %$reEntry;
|
|
2871
2917
|
SetByteOrder($saveOrder);
|
|
2918
|
+
} elsif ($$self{ImageDataMD5}) {
|
|
2919
|
+
my $digest = $$self{ImageDataMD5}->hexdigest;
|
|
2920
|
+
# (don't store empty digest)
|
|
2921
|
+
$self->FoundTag(ImageDataMD5 => $digest) unless $digest eq 'd41d8cd98f00b204e9800998ecf8427e';
|
|
2872
2922
|
}
|
|
2873
2923
|
|
|
2874
2924
|
# ($type may be undef without an Error when processing sub-documents)
|
|
@@ -3500,6 +3550,10 @@ sub GetGroup($$;$)
|
|
|
3500
3550
|
$groups[6] = $$ex{G6};
|
|
3501
3551
|
}
|
|
3502
3552
|
}
|
|
3553
|
+
if ($$ex{G8}) {
|
|
3554
|
+
$groups[7] = '';
|
|
3555
|
+
$groups[8] = $$ex{G8};
|
|
3556
|
+
}
|
|
3503
3557
|
# generate tag ID group names unless obviously not needed
|
|
3504
3558
|
unless ($noID) {
|
|
3505
3559
|
my $id = $$tagInfo{KeysID} || $$tagInfo{TagID};
|
|
@@ -3600,14 +3654,15 @@ sub SetNewGroups($;@)
|
|
|
3600
3654
|
|
|
3601
3655
|
#------------------------------------------------------------------------------
|
|
3602
3656
|
# Build Composite tags from Require'd/Desire'd tags
|
|
3603
|
-
# Inputs: 0) ExifTool object reference
|
|
3657
|
+
# Inputs: 0) ExifTool object reference, 1) flag to build only tags that require
|
|
3658
|
+
# tags from alternate files (without this, these tags are ignored)
|
|
3604
3659
|
# Note: Tag values are calculated in alphabetical order unless a tag Require's
|
|
3605
3660
|
# or Desire's another Composite tag, in which case the calculation is
|
|
3606
3661
|
# deferred until after the other tag is calculated.
|
|
3607
3662
|
sub BuildCompositeTags($)
|
|
3608
3663
|
{
|
|
3609
3664
|
local $_;
|
|
3610
|
-
my $self =
|
|
3665
|
+
my ($self, $altOnly) = @_;
|
|
3611
3666
|
|
|
3612
3667
|
$$self{BuildingComposite} = 1;
|
|
3613
3668
|
|
|
@@ -3636,7 +3691,7 @@ COMPOSITE_TAG:
|
|
|
3636
3691
|
# loop through sub-documents if necessary
|
|
3637
3692
|
my $docNum = 0;
|
|
3638
3693
|
for (;;) {
|
|
3639
|
-
my (%tagKey, $found, $index);
|
|
3694
|
+
my (%tagKey, $found, $index, $requireAlt);
|
|
3640
3695
|
# save Require'd and Desire'd tag values in list
|
|
3641
3696
|
for ($index=0; ; ++$index) {
|
|
3642
3697
|
my $reqTag = $$require{$index} || $$desire{$index} || $$inhibit{$index};
|
|
@@ -3685,13 +3740,23 @@ COMPOSITE_TAG:
|
|
|
3685
3740
|
next COMPOSITE_TAG;
|
|
3686
3741
|
}
|
|
3687
3742
|
}
|
|
3743
|
+
my ($i, $key, @keys, $altFile);
|
|
3744
|
+
my $et = $self;
|
|
3745
|
+
# get tags from alternate file if a family 8 group was specified
|
|
3746
|
+
if ($reqTag =~ /\b(File\d+):/i and $$self{ALT_EXIFTOOL}{$1}) {
|
|
3747
|
+
$et = $$self{ALT_EXIFTOOL}{$1};
|
|
3748
|
+
$altFile = $1;
|
|
3749
|
+
# set flags indicating we require tags from alternate files
|
|
3750
|
+
$$self{DoAltComposite} = $requireAlt = 1;
|
|
3751
|
+
}
|
|
3688
3752
|
# (CAREFUL! keys may not be sequential if one was deleted)
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
push @keys, $key if defined $$rawValue{$key};
|
|
3753
|
+
for ($key=$name, $i=$$et{DUPL_TAG}{$name} || 0; ; --$i) {
|
|
3754
|
+
push @keys, $key if defined $$et{VALUE}{$key};
|
|
3692
3755
|
last if $i <= 0;
|
|
3693
3756
|
$key = "$name ($i)";
|
|
3694
3757
|
}
|
|
3758
|
+
# make sure the necessary information is available from the alternate file
|
|
3759
|
+
$self->CopyAltInfo($altFile, \@keys) if $altFile;
|
|
3695
3760
|
# find first matching tag
|
|
3696
3761
|
$key = $self->GroupMatches($reqGroup, \@keys);
|
|
3697
3762
|
$reqTag = $key || "$name (0)";
|
|
@@ -3714,6 +3779,8 @@ COMPOSITE_TAG:
|
|
|
3714
3779
|
}
|
|
3715
3780
|
$tagKey{$index} = $reqTag;
|
|
3716
3781
|
}
|
|
3782
|
+
# stop now if this requires alternate tags and we aren't building them
|
|
3783
|
+
last if $requireAlt xor $altOnly;
|
|
3717
3784
|
if ($docNum) {
|
|
3718
3785
|
if ($found) {
|
|
3719
3786
|
$$self{DOC_NUM} = $docNum;
|
|
@@ -4011,6 +4078,49 @@ sub CombineInfo($;@)
|
|
|
4011
4078
|
return \%combinedInfo;
|
|
4012
4079
|
}
|
|
4013
4080
|
|
|
4081
|
+
#------------------------------------------------------------------------------
|
|
4082
|
+
# Read metadata from alternate files and build composite tags
|
|
4083
|
+
# Inputs: 0) ExifTool ref
|
|
4084
|
+
# Notes: This is called after reading the main file so the tags are available
|
|
4085
|
+
# for being used in the file name, but before building Composite tags
|
|
4086
|
+
# so tags from the alternate files may be used in the Composite tags
|
|
4087
|
+
sub ExtractAltInfo($)
|
|
4088
|
+
{
|
|
4089
|
+
my $self = shift;
|
|
4090
|
+
# extract information from alternate files if necessary
|
|
4091
|
+
my ($g8, $altExifTool);
|
|
4092
|
+
my $opts = $$self{OPTIONS};
|
|
4093
|
+
if ($$opts{Composite} and (not $$opts{FastScan} or $$opts{FastScan} < 5)) {
|
|
4094
|
+
# build all composite tags except those requiring tags from alternate files
|
|
4095
|
+
$self->BuildCompositeTags();
|
|
4096
|
+
}
|
|
4097
|
+
foreach $g8 (sort keys %{$$self{ALT_EXIFTOOL}}) {
|
|
4098
|
+
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
|
4099
|
+
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
|
4100
|
+
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
|
4101
|
+
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
|
4102
|
+
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
|
4103
|
+
my $fileName = $$altExifTool{ALT_FILE};
|
|
4104
|
+
# allow tags from the main file to be used in the alternate file names
|
|
4105
|
+
# (eg. -file1 '$originalfilename')
|
|
4106
|
+
if ($fileName =~ /\$/) {
|
|
4107
|
+
my @tags = reverse sort keys %{$$self{VALUE}};
|
|
4108
|
+
$fileName = $self->InsertTagValues(\@tags, $fileName, 'Warn');
|
|
4109
|
+
next unless defined $fileName;
|
|
4110
|
+
}
|
|
4111
|
+
$altExifTool->ExtractInfo($fileName);
|
|
4112
|
+
# set family 8 group name for all tags
|
|
4113
|
+
foreach (keys %{$$altExifTool{VALUE}}) {
|
|
4114
|
+
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
|
4115
|
+
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
|
4116
|
+
$$ex{G8} = $g8;
|
|
4117
|
+
}
|
|
4118
|
+
$$altExifTool{DID_EXTRACT} = 1;
|
|
4119
|
+
}
|
|
4120
|
+
# if necessary, build composite tags that rely on tags from alternate files
|
|
4121
|
+
$self->BuildCompositeTags(1) if $$self{DoAltComposite};
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4014
4124
|
#------------------------------------------------------------------------------
|
|
4015
4125
|
# Get tag table name
|
|
4016
4126
|
# Inputs: 0) ExifTool object reference, 1) tag key
|
|
@@ -4133,7 +4243,11 @@ sub SplitFileName($)
|
|
|
4133
4243
|
} else {
|
|
4134
4244
|
($name = $file) =~ tr/\\/\//;
|
|
4135
4245
|
# remove path
|
|
4136
|
-
|
|
4246
|
+
if ($name =~ s/(.*)\///) {
|
|
4247
|
+
$dir = length($1) ? $1 : '/';
|
|
4248
|
+
} else {
|
|
4249
|
+
$dir = '.';
|
|
4250
|
+
}
|
|
4137
4251
|
}
|
|
4138
4252
|
return ($dir, $name);
|
|
4139
4253
|
}
|
|
@@ -4296,9 +4410,9 @@ sub GetFileTime($$)
|
|
|
4296
4410
|
# on Windows, try to work around incorrect file times when daylight saving time is in effect
|
|
4297
4411
|
if ($^O eq 'MSWin32') {
|
|
4298
4412
|
if (not eval { require Win32::API }) {
|
|
4299
|
-
$self->WarnOnce('Install Win32::API for proper handling of Windows file times');
|
|
4413
|
+
$self->WarnOnce('Install Win32::API for proper handling of Windows file times', 1);
|
|
4300
4414
|
} elsif (not eval { require Win32API::File }) {
|
|
4301
|
-
$self->WarnOnce('Install Win32API::File for proper handling of Windows file times');
|
|
4415
|
+
$self->WarnOnce('Install Win32API::File for proper handling of Windows file times', 1);
|
|
4302
4416
|
} else {
|
|
4303
4417
|
# get Win32 handle, needed for GetFileTime
|
|
4304
4418
|
my $win32Handle = eval { Win32API::File::GetOsFHandle($file) };
|
|
@@ -4548,6 +4662,29 @@ sub RemoveTagsFromList($$$$;$)
|
|
|
4548
4662
|
$_[0] = \@filteredTags; # update tag list
|
|
4549
4663
|
}
|
|
4550
4664
|
|
|
4665
|
+
#------------------------------------------------------------------------------
|
|
4666
|
+
# Copy tags from alternate input file
|
|
4667
|
+
# Inputs: 0) ExifTool ref, 1) family 8 group, 2) list ref for tag keys to copy
|
|
4668
|
+
# - updates tag key list to match keys newly added to $self
|
|
4669
|
+
sub CopyAltInfo($$$)
|
|
4670
|
+
{
|
|
4671
|
+
my ($self, $g8, $tags) = @_;
|
|
4672
|
+
my ($tag, $vtag);
|
|
4673
|
+
return unless $g8 =~ /(\d+)/;
|
|
4674
|
+
my $et = $$self{ALT_EXIFTOOL}{$g8} or return;
|
|
4675
|
+
my $altOrder = ($1 + 1) * 100000; # increment file order
|
|
4676
|
+
foreach $tag (@$tags) {
|
|
4677
|
+
($vtag = $tag) =~ s/( |$)/ #[$g8]/;
|
|
4678
|
+
unless (defined $$self{VALUE}{$vtag}) {
|
|
4679
|
+
$$self{VALUE}{$vtag} = $$et{VALUE}{$tag};
|
|
4680
|
+
$$self{TAG_INFO}{$vtag} = $$et{TAG_INFO}{$tag};
|
|
4681
|
+
$$self{TAG_EXTRA}{$vtag} = $$et{TAG_EXTRA}{$tag} || { };
|
|
4682
|
+
$$self{FILE_ORDER}{$vtag} = ($$et{FILE_ORDER}{$tag} || 0) + $altOrder;
|
|
4683
|
+
}
|
|
4684
|
+
$tag = $vtag;
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
|
|
4551
4688
|
#------------------------------------------------------------------------------
|
|
4552
4689
|
# Set list of found tags from previously requested tags
|
|
4553
4690
|
# Inputs: 0) ExifTool object reference
|
|
@@ -4574,11 +4711,17 @@ sub SetFoundTags($)
|
|
|
4574
4711
|
my $tagHash = $$self{VALUE};
|
|
4575
4712
|
my $reqTag;
|
|
4576
4713
|
foreach $reqTag (@$reqTags) {
|
|
4577
|
-
my (@matches, $group, $allGrp, $allTag, $byValue);
|
|
4714
|
+
my (@matches, $group, $allGrp, $allTag, $byValue, $g8);
|
|
4715
|
+
my $et = $self;
|
|
4578
4716
|
if ($reqTag =~ /^(.*):(.+)/) {
|
|
4579
4717
|
($group, $tag) = ($1, $2);
|
|
4580
4718
|
if ($group =~ /^(\*|all)$/i) {
|
|
4581
4719
|
$allGrp = 1;
|
|
4720
|
+
} elsif ($reqTag =~ /\bfile(\d+):/i) {
|
|
4721
|
+
$g8 = "File$1";
|
|
4722
|
+
$et = $$self{ALT_EXIFTOOL}{$g8} || $self;
|
|
4723
|
+
$fileOrder = $$et{FILE_ORDER};
|
|
4724
|
+
$tagHash = $$et{VALUE};
|
|
4582
4725
|
} elsif ($group !~ /^[-\w:]*$/) {
|
|
4583
4726
|
$self->Warn("Invalid group name '${group}'");
|
|
4584
4727
|
$group = 'invalid';
|
|
@@ -4620,7 +4763,7 @@ sub SetFoundTags($)
|
|
|
4620
4763
|
}
|
|
4621
4764
|
if (defined $group and not $allGrp) {
|
|
4622
4765
|
# keep only specified group
|
|
4623
|
-
@matches = $
|
|
4766
|
+
@matches = $et->GroupMatches($group, \@matches);
|
|
4624
4767
|
next unless @matches or not $allTag;
|
|
4625
4768
|
}
|
|
4626
4769
|
if (@matches > 1) {
|
|
@@ -4629,9 +4772,9 @@ sub SetFoundTags($)
|
|
|
4629
4772
|
# return only the highest priority tag unless duplicates wanted
|
|
4630
4773
|
unless ($doDups or $allTag or $allGrp) {
|
|
4631
4774
|
$tag = shift @matches;
|
|
4632
|
-
my $oldPriority = $$
|
|
4775
|
+
my $oldPriority = $$et{PRIORITY}{$tag} || 1;
|
|
4633
4776
|
foreach (@matches) {
|
|
4634
|
-
my $priority = $$
|
|
4777
|
+
my $priority = $$et{PRIORITY}{$_};
|
|
4635
4778
|
$priority = 1 unless defined $priority;
|
|
4636
4779
|
next unless $priority >= $oldPriority;
|
|
4637
4780
|
$tag = $_;
|
|
@@ -4645,6 +4788,13 @@ sub SetFoundTags($)
|
|
|
4645
4788
|
# bogus file order entry to avoid warning if sorting in file order
|
|
4646
4789
|
$$self{FILE_ORDER}{$matches[0]} = 9999;
|
|
4647
4790
|
}
|
|
4791
|
+
# copy over necessary information for tags from alternate files
|
|
4792
|
+
if ($g8) {
|
|
4793
|
+
$self->CopyAltInfo($g8, \@matches);
|
|
4794
|
+
# restore variables to original values for main file
|
|
4795
|
+
$fileOrder = $$self{FILE_ORDER};
|
|
4796
|
+
$tagHash = $$self{VALUE};
|
|
4797
|
+
}
|
|
4648
4798
|
# save indices of tags extracted by value
|
|
4649
4799
|
push @byValue, scalar(@$rtnTags) .. (scalar(@$rtnTags)+scalar(@matches)-1) if $byValue;
|
|
4650
4800
|
# save indices of wildcard tags
|
|
@@ -4821,12 +4971,14 @@ sub AUTOLOAD
|
|
|
4821
4971
|
sub Warn($$;$)
|
|
4822
4972
|
{
|
|
4823
4973
|
my ($self, $str, $ignorable) = @_;
|
|
4974
|
+
my $noWarn = $self->Options('NoWarning');
|
|
4824
4975
|
if ($ignorable) {
|
|
4825
4976
|
return 0 if $$self{OPTIONS}{IgnoreMinorErrors};
|
|
4826
4977
|
return 0 if $ignorable eq '3' and $$self{OPTIONS}{Validate};
|
|
4978
|
+
return 1 if defined $noWarn and eval { $str =~ /$noWarn/ };
|
|
4827
4979
|
$str = $ignorable eq '2' ? "[Minor] $str" : "[minor] $str";
|
|
4828
4980
|
}
|
|
4829
|
-
$self->FoundTag('Warning', $str);
|
|
4981
|
+
$self->FoundTag('Warning', $str) unless defined $noWarn and eval { $str =~ /$noWarn/ };
|
|
4830
4982
|
return 1;
|
|
4831
4983
|
}
|
|
4832
4984
|
|
|
@@ -5867,7 +6019,8 @@ sub ConvertTimeSpan($;$)
|
|
|
5867
6019
|
#------------------------------------------------------------------------------
|
|
5868
6020
|
# Patched timelocal() that fixes ActivePerl timezone bug
|
|
5869
6021
|
# Inputs/Returns: same as timelocal()
|
|
5870
|
-
# Notes: must 'require Time::Local' before calling this routine
|
|
6022
|
+
# Notes: must 'require Time::Local' before calling this routine.
|
|
6023
|
+
# Also note that year should be full year, and not relative to 1900 as with localtime
|
|
5871
6024
|
sub TimeLocal(@)
|
|
5872
6025
|
{
|
|
5873
6026
|
my $tm = Time::Local::timelocal(@_);
|
|
@@ -6326,7 +6479,6 @@ sub ProcessJPEG($$)
|
|
|
6326
6479
|
{
|
|
6327
6480
|
local $_;
|
|
6328
6481
|
my ($self, $dirInfo) = @_;
|
|
6329
|
-
my ($ch, $s, $length);
|
|
6330
6482
|
my $options = $$self{OPTIONS};
|
|
6331
6483
|
my $verbose = $$options{Verbose};
|
|
6332
6484
|
my $out = $$options{TextOut};
|
|
@@ -6335,10 +6487,17 @@ sub ProcessJPEG($$)
|
|
|
6335
6487
|
my $req = $$self{REQ_TAG_LOOKUP};
|
|
6336
6488
|
my $htmlDump = $$self{HTML_DUMP};
|
|
6337
6489
|
my %dumpParms = ( Out => $out );
|
|
6338
|
-
my ($
|
|
6490
|
+
my ($ch, $s, $length, $md5, $md5size);
|
|
6491
|
+
my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
|
|
6339
6492
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
|
6340
6493
|
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
|
6341
6494
|
|
|
6495
|
+
# get pointer to MD5 object if it exists and we are the top-level JPEG or JP2
|
|
6496
|
+
if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
|
|
6497
|
+
$md5 = $$self{ImageDataMD5};
|
|
6498
|
+
$md5size = 0;
|
|
6499
|
+
}
|
|
6500
|
+
|
|
6342
6501
|
# check to be sure this is a valid JPG (or J2C, or EXV) file
|
|
6343
6502
|
return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/;
|
|
6344
6503
|
if ($s eq "\xff\x01") {
|
|
@@ -6385,7 +6544,9 @@ sub ProcessJPEG($$)
|
|
|
6385
6544
|
#
|
|
6386
6545
|
# read ahead to the next segment unless we have reached EOI, SOS or SOD
|
|
6387
6546
|
#
|
|
6388
|
-
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer
|
|
6547
|
+
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $md5) or
|
|
6548
|
+
$marker==0x93))
|
|
6549
|
+
{
|
|
6389
6550
|
# read up to next marker (JPEG markers begin with 0xff)
|
|
6390
6551
|
my $buff;
|
|
6391
6552
|
$raf->ReadLine($buff) or last;
|
|
@@ -6415,6 +6576,19 @@ sub ProcessJPEG($$)
|
|
|
6415
6576
|
$nextSegPos = $raf->Tell();
|
|
6416
6577
|
$len -= 4; # subtract size of length word
|
|
6417
6578
|
last unless $raf->Seek($len, 1);
|
|
6579
|
+
} elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == 0xda or
|
|
6580
|
+
($marker >= 0xd0 and $marker <= 0xd7)))
|
|
6581
|
+
{
|
|
6582
|
+
# calculate MD5 for image data (includes leading ff d9 but not trailing ff da)
|
|
6583
|
+
$md5->add("\xff" . chr($marker));
|
|
6584
|
+
my $n = $skipped - (length($buff) - 1); # number of extra 0xff's
|
|
6585
|
+
if (not $n) {
|
|
6586
|
+
$buff = substr($buff, 0, -1); # remove trailing 0xff
|
|
6587
|
+
} elsif ($n > 1) {
|
|
6588
|
+
$buff .= "\xff" x ($n - 1); # add back extra 0xff's
|
|
6589
|
+
}
|
|
6590
|
+
$md5->add($buff);
|
|
6591
|
+
$md5size += $skipped + 2;
|
|
6418
6592
|
}
|
|
6419
6593
|
# read second segment too if this was the first
|
|
6420
6594
|
next unless defined $marker;
|
|
@@ -6443,7 +6617,8 @@ sub ProcessJPEG($$)
|
|
|
6443
6617
|
$self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
|
|
6444
6618
|
$dumpEnd = $segPos + $length;
|
|
6445
6619
|
}
|
|
6446
|
-
next
|
|
6620
|
+
next if $length < 6 or $gotSize;
|
|
6621
|
+
$gotSize = 1; # (ignore subsequent SOF segments in probably corrupted JPEG)
|
|
6447
6622
|
# extract some useful information
|
|
6448
6623
|
my ($p, $h, $w, $n) = unpack('Cn2C', $$segDataPt);
|
|
6449
6624
|
my $sof = GetTagTable('Image::ExifTool::JPEG::SOF');
|
|
@@ -6625,7 +6800,7 @@ sub ProcessJPEG($$)
|
|
|
6625
6800
|
next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump;
|
|
6626
6801
|
}
|
|
6627
6802
|
# must scan to EOI if Validate or JpegCompressionFactor used
|
|
6628
|
-
next if $$options{Validate} or $calcImageLen or $$req{trailer};
|
|
6803
|
+
next if $$options{Validate} or $calcImageLen or $$req{trailer} or $md5;
|
|
6629
6804
|
# nothing interesting to parse after start of scan (SOS)
|
|
6630
6805
|
$success = 1;
|
|
6631
6806
|
last; # all done parsing file
|
|
@@ -6633,6 +6808,11 @@ sub ProcessJPEG($$)
|
|
|
6633
6808
|
pop @$path;
|
|
6634
6809
|
$verbose and print $out "JPEG SOD\n";
|
|
6635
6810
|
$success = 1;
|
|
6811
|
+
if ($md5 and $$self{FILE_TYPE} eq 'JP2') {
|
|
6812
|
+
my $pos = $raf->Tell();
|
|
6813
|
+
$self->ImageDataMD5($raf, undef, 'SOD');
|
|
6814
|
+
$raf->Seek($pos, 0);
|
|
6815
|
+
}
|
|
6636
6816
|
next if $verbose > 2 or $htmlDump;
|
|
6637
6817
|
last; # all done parsing file
|
|
6638
6818
|
} elsif (defined $markerLenBytes{$marker}) {
|
|
@@ -6707,7 +6887,7 @@ sub ProcessJPEG($$)
|
|
|
6707
6887
|
} elsif ($marker == 0xe1) { # APP1 (EXIF, XMP, QVCI, PARROT)
|
|
6708
6888
|
# (some Kodak cameras don't put a second "\0", and I have seen an
|
|
6709
6889
|
# example where there was a second 4-byte APP1 segment header)
|
|
6710
|
-
if ($$segDataPt =~ /^(.{0,4})Exif\0
|
|
6890
|
+
if ($$segDataPt =~ /^(.{0,4})Exif\0./is) {
|
|
6711
6891
|
undef $dumpType; # (will be dumped here)
|
|
6712
6892
|
# this is EXIF data --
|
|
6713
6893
|
# get the data block (into a common variable)
|
|
@@ -7008,7 +7188,7 @@ sub ProcessJPEG($$)
|
|
|
7008
7188
|
$self->FoundTag('PreviewImage', $preview);
|
|
7009
7189
|
undef $preview;
|
|
7010
7190
|
}
|
|
7011
|
-
} elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, PreviewImage)
|
|
7191
|
+
} elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, DJI, PreviewImage)
|
|
7012
7192
|
if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) {
|
|
7013
7193
|
$dumpType = 'SCALADO';
|
|
7014
7194
|
my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt);
|
|
@@ -7039,6 +7219,16 @@ sub ProcessJPEG($$)
|
|
|
7039
7219
|
DirStart(\%dirInfo, 0, 0);
|
|
7040
7220
|
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams');
|
|
7041
7221
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7222
|
+
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^(.{32})?.{32}\x2c\x01\x20\0/s) {
|
|
7223
|
+
$dumpType = 'DJI ThermalParams2';
|
|
7224
|
+
DirStart(\%dirInfo, $1 ? 32 : 0, 0);
|
|
7225
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams2');
|
|
7226
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7227
|
+
} elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^.{32}\xaa\x55\x38\0/s) {
|
|
7228
|
+
$dumpType = 'DJI ThermalParams3';
|
|
7229
|
+
DirStart(\%dirInfo, 32, 0);
|
|
7230
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams3');
|
|
7231
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7042
7232
|
} elsif ($$self{HasIJPEG} and $length >= 120) {
|
|
7043
7233
|
$dumpType = 'InfiRay Factory';
|
|
7044
7234
|
SetByteOrder('II');
|
|
@@ -7152,6 +7342,13 @@ sub ProcessJPEG($$)
|
|
|
7152
7342
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7153
7343
|
delete $$self{SET_GROUP0};
|
|
7154
7344
|
delete $$self{SET_GROUP1};
|
|
7345
|
+
} elsif ($$segDataPt =~ /^DJI-DBG\0/) {
|
|
7346
|
+
$dumpType = 'DJI Info';
|
|
7347
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::Info');
|
|
7348
|
+
DirStart(\%dirInfo, 8, 0);
|
|
7349
|
+
$$self{SET_GROUP0} = 'APP7';
|
|
7350
|
+
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7351
|
+
delete $$self{SET_GROUP0};
|
|
7155
7352
|
} elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) {
|
|
7156
7353
|
# found in HP iPAQ_VoiceMessenger
|
|
7157
7354
|
$dumpType = 'Qualcomm';
|
|
@@ -7348,8 +7545,11 @@ sub ProcessJPEG($$)
|
|
|
7348
7545
|
}
|
|
7349
7546
|
} elsif ($marker == 0x51) { # SIZ (J2C)
|
|
7350
7547
|
my ($w, $h) = unpack('x2N2', $$segDataPt);
|
|
7351
|
-
|
|
7352
|
-
|
|
7548
|
+
unless ($gotSize) {
|
|
7549
|
+
$gotSize = 1;
|
|
7550
|
+
$self->FoundTag('ImageWidth', $w);
|
|
7551
|
+
$self->FoundTag('ImageHeight', $h);
|
|
7552
|
+
}
|
|
7353
7553
|
} elsif (($marker & 0xf0) != 0xe0) {
|
|
7354
7554
|
$dumpType = "$markerName segment";
|
|
7355
7555
|
$desc = "[JPEG $markerName]"; # (other known JPEG segments)
|
|
@@ -7412,6 +7612,8 @@ sub ProcessJPEG($$)
|
|
|
7412
7612
|
delete $extendedXMP{$guid};
|
|
7413
7613
|
}
|
|
7414
7614
|
}
|
|
7615
|
+
# print verbose MD5 message if necessary
|
|
7616
|
+
print $out "$$self{INDENT}(ImageDataMD5: $md5size bytes of JPEG image data)\n" if $md5size and $verbose;
|
|
7415
7617
|
# calculate JPEGDigest if requested
|
|
7416
7618
|
if (@dqt) {
|
|
7417
7619
|
require Image::ExifTool::JPEGDigest;
|
|
@@ -7680,13 +7882,16 @@ sub DoProcessTIFF($$;$)
|
|
|
7680
7882
|
}
|
|
7681
7883
|
}
|
|
7682
7884
|
# update FileType if necessary now that we know more about the file
|
|
7683
|
-
if ($$self{DNGVersion} and $$self{
|
|
7885
|
+
if ($$self{DNGVersion} and $$self{FileType} !~ /^(DNG|GPR)$/) {
|
|
7684
7886
|
# override whatever FileType we set since we now know it is DNG
|
|
7685
7887
|
$self->OverrideFileType($$self{TIFF_TYPE} = 'DNG');
|
|
7686
7888
|
}
|
|
7687
7889
|
if ($$self{TIFF_TYPE} eq 'TIFF') {
|
|
7688
7890
|
$self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage};
|
|
7689
7891
|
}
|
|
7892
|
+
if ($$self{ImageDataMD5} and $$self{A100DataOffset} and $raf->Seek($$self{A100DataOffset},0)) {
|
|
7893
|
+
$self->ImageDataMD5($raf, undef, 'A100');
|
|
7894
|
+
}
|
|
7690
7895
|
return 1;
|
|
7691
7896
|
}
|
|
7692
7897
|
#
|
|
@@ -7988,7 +8193,7 @@ sub ProcessDirectory($$$;$)
|
|
|
7988
8193
|
# patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
|
|
7989
8194
|
return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
|
|
7990
8195
|
}
|
|
7991
|
-
$$self{PROCESSED}{$addr} = $dirName;
|
|
8196
|
+
$$self{PROCESSED}{$addr} = $dirName unless $$tagTablePtr{VARS} and $$tagTablePtr{VARS}{ALLOW_REPROCESS};
|
|
7992
8197
|
}
|
|
7993
8198
|
my $oldOrder = GetByteOrder();
|
|
7994
8199
|
my @save = @$self{'INDENT','DIR_NAME','Compression','SubfileType'};
|
|
@@ -8566,7 +8771,7 @@ sub DoEscape($$)
|
|
|
8566
8771
|
sub SetFileType($;$$$)
|
|
8567
8772
|
{
|
|
8568
8773
|
my ($self, $fileType, $mimeType, $normExt) = @_;
|
|
8569
|
-
unless ($$self{
|
|
8774
|
+
unless ($$self{FileType} and not $$self{DOC_NUM}) {
|
|
8570
8775
|
my $baseType = $$self{FILE_TYPE};
|
|
8571
8776
|
my $ext = $$self{FILE_EXT};
|
|
8572
8777
|
$fileType or $fileType = $baseType;
|
|
@@ -8585,7 +8790,8 @@ sub SetFileType($;$$$)
|
|
|
8585
8790
|
$normExt = $fileTypeExt{$fileType};
|
|
8586
8791
|
$normExt = $fileType unless defined $normExt;
|
|
8587
8792
|
}
|
|
8588
|
-
$$self{FileType}
|
|
8793
|
+
# ($$self{FileType} is the file type of the main document)
|
|
8794
|
+
$$self{FileType} = $fileType unless $$self{DOC_NUM};
|
|
8589
8795
|
$self->FoundTag('FileType', $fileType);
|
|
8590
8796
|
$self->FoundTag('FileTypeExtension', uc $normExt);
|
|
8591
8797
|
$self->FoundTag('MIMEType', $mimeType || 'application/unknown');
|
|
@@ -8749,13 +8955,16 @@ sub ProcessBinaryData($$$)
|
|
|
8749
8955
|
{
|
|
8750
8956
|
my ($self, $dirInfo, $tagTablePtr) = @_;
|
|
8751
8957
|
my $dataPt = $$dirInfo{DataPt};
|
|
8752
|
-
my $
|
|
8753
|
-
my $
|
|
8958
|
+
my $dataLen = length $$dataPt;
|
|
8959
|
+
my $dirStart = $$dirInfo{DirStart} || 0;
|
|
8960
|
+
my $maxLen = $dataLen - $dirStart;
|
|
8961
|
+
my $size = $$dirInfo{DirLen};
|
|
8754
8962
|
my $base = $$dirInfo{Base} || 0;
|
|
8755
8963
|
my $verbose = $$self{OPTIONS}{Verbose};
|
|
8756
8964
|
my $unknown = $$self{OPTIONS}{Unknown};
|
|
8757
8965
|
my $dataPos = $$dirInfo{DataPos} || 0;
|
|
8758
8966
|
|
|
8967
|
+
$size = $maxLen if not defined $size or $size > $maxLen;
|
|
8759
8968
|
# get default format ('int8u' unless specified)
|
|
8760
8969
|
my $defaultFormat = $$tagTablePtr{FORMAT} || 'int8u';
|
|
8761
8970
|
my $increment = $formatSize{$defaultFormat};
|
|
@@ -8797,6 +9006,7 @@ sub ProcessBinaryData($$$)
|
|
|
8797
9006
|
$tagInfo = $self->GetTagInfo($tagTablePtr, $index);
|
|
8798
9007
|
unless ($tagInfo) {
|
|
8799
9008
|
next unless defined $tagInfo;
|
|
9009
|
+
# $entry = offset of value relative to directory start (or end if negative)
|
|
8800
9010
|
my $entry = int($index) * $increment + $varSize;
|
|
8801
9011
|
if ($entry < 0) {
|
|
8802
9012
|
$entry += $size;
|
|
@@ -8805,7 +9015,7 @@ sub ProcessBinaryData($$$)
|
|
|
8805
9015
|
next if $entry >= $size;
|
|
8806
9016
|
my $more = $size - $entry;
|
|
8807
9017
|
$more = 128 if $more > 128;
|
|
8808
|
-
my $v = substr($$dataPt, $entry+$
|
|
9018
|
+
my $v = substr($$dataPt, $entry+$dirStart, $more);
|
|
8809
9019
|
$tagInfo = $self->GetTagInfo($tagTablePtr, $index, \$v);
|
|
8810
9020
|
next unless $tagInfo;
|
|
8811
9021
|
}
|
|
@@ -8838,7 +9048,7 @@ sub ProcessBinaryData($$$)
|
|
|
8838
9048
|
$count = $more;
|
|
8839
9049
|
} elsif ($format eq 'pstring') {
|
|
8840
9050
|
$format = 'string';
|
|
8841
|
-
$count = Get8u($dataPt, ($entry++)+$
|
|
9051
|
+
$count = Get8u($dataPt, ($entry++)+$dirStart);
|
|
8842
9052
|
--$more;
|
|
8843
9053
|
} elsif (not $formatSize{$format}) {
|
|
8844
9054
|
if ($format =~ /(.*)\[(.*)\]/) {
|
|
@@ -8867,17 +9077,17 @@ sub ProcessBinaryData($$$)
|
|
|
8867
9077
|
} elsif ($format =~ /^var_/) {
|
|
8868
9078
|
# handle variable-length string formats
|
|
8869
9079
|
$format = substr($format, 4);
|
|
8870
|
-
pos($$dataPt) = $entry + $
|
|
9080
|
+
pos($$dataPt) = $entry + $dirStart;
|
|
8871
9081
|
undef $count;
|
|
8872
9082
|
if ($format eq 'ustring') {
|
|
8873
|
-
$count = pos($$dataPt) - ($entry+$
|
|
9083
|
+
$count = pos($$dataPt) - ($entry+$dirStart) if $$dataPt =~ /\G(..)*?\0\0/sg;
|
|
8874
9084
|
$varSize -= 2; # ($count includes base size of 2 bytes)
|
|
8875
9085
|
} elsif ($format eq 'pstring') {
|
|
8876
|
-
$count = Get8u($dataPt, ($entry++)+$
|
|
9086
|
+
$count = Get8u($dataPt, ($entry++)+$dirStart);
|
|
8877
9087
|
--$more;
|
|
8878
9088
|
} elsif ($format eq 'pstr32' or $format eq 'ustr32') {
|
|
8879
9089
|
last if $more < 4;
|
|
8880
|
-
$count = Get32u($dataPt, $entry + $
|
|
9090
|
+
$count = Get32u($dataPt, $entry + $dirStart);
|
|
8881
9091
|
$count *= 2 if $format eq 'ustr32';
|
|
8882
9092
|
$entry += 4;
|
|
8883
9093
|
$more -= 4;
|
|
@@ -8885,22 +9095,22 @@ sub ProcessBinaryData($$$)
|
|
|
8885
9095
|
} elsif ($format eq 'int16u') {
|
|
8886
9096
|
# int16u size of binary data to follow
|
|
8887
9097
|
last if $more < 2;
|
|
8888
|
-
$count = Get16u($dataPt, $entry + $
|
|
9098
|
+
$count = Get16u($dataPt, $entry + $dirStart) + 2;
|
|
8889
9099
|
$varSize -= 2; # ($count includes size word)
|
|
8890
9100
|
$format = 'undef';
|
|
8891
9101
|
} elsif ($format eq 'ue7') {
|
|
8892
9102
|
require Image::ExifTool::BPG;
|
|
8893
|
-
($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $
|
|
9103
|
+
($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $dirStart);
|
|
8894
9104
|
last unless defined $val;
|
|
8895
9105
|
--$varSize; # ($count includes base size of 1 byte)
|
|
8896
9106
|
} elsif ($$dataPt =~ /\0/g) {
|
|
8897
|
-
$count = pos($$dataPt) - ($entry+$
|
|
9107
|
+
$count = pos($$dataPt) - ($entry+$dirStart);
|
|
8898
9108
|
--$varSize; # ($count includes base size of 1 byte)
|
|
8899
9109
|
}
|
|
8900
9110
|
$count = $more if not defined $count or $count > $more;
|
|
8901
9111
|
$varSize += $count; # shift subsequent indices
|
|
8902
9112
|
unless (defined $val) {
|
|
8903
|
-
$val = substr($$dataPt, $entry+$
|
|
9113
|
+
$val = substr($$dataPt, $entry+$dirStart, $count);
|
|
8904
9114
|
$val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
|
|
8905
9115
|
$val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
|
|
8906
9116
|
}
|
|
@@ -8914,7 +9124,7 @@ sub ProcessBinaryData($$$)
|
|
|
8914
9124
|
# hook to allow format, etc to be set dynamically
|
|
8915
9125
|
if (defined $$tagInfo{Hook}) {
|
|
8916
9126
|
my $oldVarSize = $varSize;
|
|
8917
|
-
my $pos = $entry + $
|
|
9127
|
+
my $pos = $entry + $dirStart;
|
|
8918
9128
|
#### eval Hook ($format, $varSize, $size, $dataPt, $pos)
|
|
8919
9129
|
eval $$tagInfo{Hook};
|
|
8920
9130
|
# save variable size data if required for writing (in case changed by Hook)
|
|
@@ -8939,7 +9149,7 @@ sub ProcessBinaryData($$$)
|
|
|
8939
9149
|
next if $$tagInfo{LargeTag} and $$self{EXCL_TAG_LOOKUP}{lc $$tagInfo{Name}};
|
|
8940
9150
|
# read value now if necessary
|
|
8941
9151
|
unless (defined $val and not $$tagInfo{SubDirectory}) {
|
|
8942
|
-
$val = ReadValue($dataPt, $entry+$
|
|
9152
|
+
$val = ReadValue($dataPt, $entry+$dirStart, $format, $count, $more, \$rational);
|
|
8943
9153
|
next unless defined $val;
|
|
8944
9154
|
$mask = $$tagInfo{Mask};
|
|
8945
9155
|
$val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
|
|
@@ -8956,8 +9166,8 @@ sub ProcessBinaryData($$$)
|
|
|
8956
9166
|
Value => $val,
|
|
8957
9167
|
DataPt => $dataPt,
|
|
8958
9168
|
Size => $len,
|
|
8959
|
-
Start => $entry+$
|
|
8960
|
-
Addr => $entry+$
|
|
9169
|
+
Start => $entry+$dirStart,
|
|
9170
|
+
Addr => $entry+$dirStart+$base+$dataPos,
|
|
8961
9171
|
Format => $format,
|
|
8962
9172
|
Count => $count,
|
|
8963
9173
|
Extra => $mask ? sprintf(', mask 0x%.2x',$mask) : undef,
|
|
@@ -8983,16 +9193,27 @@ sub ProcessBinaryData($$$)
|
|
|
8983
9193
|
my $subdirBase = $base;
|
|
8984
9194
|
if (defined $$subdir{Base}) {
|
|
8985
9195
|
#### eval Base ($start,$base)
|
|
8986
|
-
my $start = $entry + $
|
|
9196
|
+
my $start = $entry + $dirStart + $dataPos;
|
|
8987
9197
|
$subdirBase = eval($$subdir{Base}) + $base;
|
|
8988
9198
|
}
|
|
8989
9199
|
my $start = $$subdir{Start} || 0;
|
|
9200
|
+
if ($start =~ /\$/) {
|
|
9201
|
+
# ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
|
|
9202
|
+
next unless $val;
|
|
9203
|
+
#### eval Start ($val, $dirStart)
|
|
9204
|
+
$start = eval($start);
|
|
9205
|
+
next if $start < $dirStart or $start > $dataLen;
|
|
9206
|
+
$len = $$subdir{DirLen};
|
|
9207
|
+
$len = $dataLen - $start unless $len and $len <= $dataLen - $start;
|
|
9208
|
+
} else {
|
|
9209
|
+
$start += $dirStart + $entry;
|
|
9210
|
+
}
|
|
8990
9211
|
my %subdirInfo = (
|
|
8991
9212
|
DataPt => $dataPt,
|
|
8992
9213
|
DataPos => $dataPos,
|
|
8993
|
-
DataLen =>
|
|
8994
|
-
DirStart => $
|
|
8995
|
-
DirLen => $len
|
|
9214
|
+
DataLen => $dataLen,
|
|
9215
|
+
DirStart => $start,
|
|
9216
|
+
DirLen => $len,
|
|
8996
9217
|
Base => $subdirBase,
|
|
8997
9218
|
);
|
|
8998
9219
|
delete $$self{NO_UNKNOWN};
|