exiftool-vendored.pl 12.60.0 → 12.65.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 +110 -0
- package/bin/LICENSE +674 -0
- package/bin/MANIFEST +11 -0
- package/bin/META.json +5 -3
- package/bin/META.yml +5 -3
- package/bin/Makefile.PL +7 -1
- package/bin/README +50 -45
- package/bin/config_files/guano.config +161 -0
- package/bin/exiftool +163 -103
- package/bin/lib/Image/ExifTool/7Z.pm +793 -0
- package/bin/lib/Image/ExifTool/Apple.pm +14 -7
- package/bin/lib/Image/ExifTool/BMP.pm +0 -1
- package/bin/lib/Image/ExifTool/BigTIFF.pm +8 -1
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +4 -4
- package/bin/lib/Image/ExifTool/Canon.pm +4 -1
- package/bin/lib/Image/ExifTool/CanonRaw.pm +4 -4
- package/bin/lib/Image/ExifTool/CanonVRD.pm +4 -1
- package/bin/lib/Image/ExifTool/Exif.pm +31 -14
- package/bin/lib/Image/ExifTool/FlashPix.pm +9 -2
- package/bin/lib/Image/ExifTool/FujiFilm.pm +3 -3
- package/bin/lib/Image/ExifTool/GPS.pm +5 -2
- package/bin/lib/Image/ExifTool/Geotag.pm +4 -1
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +243 -20
- package/bin/lib/Image/ExifTool/Lang/fr.pm +1467 -202
- package/bin/lib/Image/ExifTool/MPF.pm +2 -1
- package/bin/lib/Image/ExifTool/Matroska.pm +16 -1
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +941 -33
- package/bin/lib/Image/ExifTool/NikonCustom.pm +874 -63
- package/bin/lib/Image/ExifTool/PDF.pm +39 -12
- package/bin/lib/Image/ExifTool/PLIST.pm +8 -1
- package/bin/lib/Image/ExifTool/PNG.pm +6 -6
- package/bin/lib/Image/ExifTool/PhaseOne.pm +5 -5
- package/bin/lib/Image/ExifTool/QuickTime.pm +96 -32
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +68 -37
- package/bin/lib/Image/ExifTool/README +2 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +11 -9
- package/bin/lib/Image/ExifTool/Samsung.pm +227 -227
- package/bin/lib/Image/ExifTool/Shortcuts.pm +2 -1
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +4 -4
- package/bin/lib/Image/ExifTool/Sony.pm +237 -32
- package/bin/lib/Image/ExifTool/TagLookup.pm +4762 -4629
- package/bin/lib/Image/ExifTool/TagNames.pod +737 -20
- package/bin/lib/Image/ExifTool/Validate.pm +17 -1
- package/bin/lib/Image/ExifTool/WPG.pm +296 -0
- package/bin/lib/Image/ExifTool/WriteExif.pl +9 -7
- package/bin/lib/Image/ExifTool/WritePDF.pl +7 -8
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -9
- package/bin/lib/Image/ExifTool/WriteXMP.pl +2 -2
- package/bin/lib/Image/ExifTool/Writer.pl +47 -16
- package/bin/lib/Image/ExifTool/XMP.pm +30 -6
- package/bin/lib/Image/ExifTool/XMP2.pl +32 -0
- package/bin/lib/Image/ExifTool/XMPStruct.pl +96 -28
- package/bin/lib/Image/ExifTool/ZIP.pm +159 -41
- package/bin/lib/Image/ExifTool.pm +280 -164
- package/bin/lib/Image/ExifTool.pod +117 -52
- package/bin/perl-Image-ExifTool.spec +44 -43
- package/bin/pp_build_exe.args +8 -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.65';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -114,7 +114,7 @@ sub WriteTIFF($$$);
|
|
|
114
114
|
sub PackUTF8(@);
|
|
115
115
|
sub UnpackUTF8($);
|
|
116
116
|
sub SetPreferredByteOrder($;$);
|
|
117
|
-
sub
|
|
117
|
+
sub ImageDataHash($$$;$$);
|
|
118
118
|
sub CopyBlock($$$);
|
|
119
119
|
sub CopyFileAttrs($$$);
|
|
120
120
|
sub TimeNow(;$$);
|
|
@@ -126,7 +126,7 @@ sub MakeTiffHeader($$$$;$$);
|
|
|
126
126
|
sub SplitFileName($);
|
|
127
127
|
sub EncodeFileName($$;$);
|
|
128
128
|
sub Open($*$;$);
|
|
129
|
-
sub Exists(
|
|
129
|
+
sub Exists($$;$);
|
|
130
130
|
sub IsDirectory($$);
|
|
131
131
|
sub Rename($$$);
|
|
132
132
|
sub Unlink($@);
|
|
@@ -142,8 +142,8 @@ sub ReadValue($$$;$$$);
|
|
|
142
142
|
@loadAllTables = qw(
|
|
143
143
|
PhotoMechanic Exif GeoTiff CanonRaw KyoceraRaw Lytro MinoltaRaw PanasonicRaw
|
|
144
144
|
SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions
|
|
145
|
-
ICO PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF
|
|
146
|
-
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
|
|
147
147
|
Photoshop::Layers Photoshop::ImageData FujiFilm::RAF FujiFilm::IFD
|
|
148
148
|
Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD Sony::PMP ITC ID3 ID3::Lyrics3
|
|
149
149
|
FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible MPC MPEG::Audio
|
|
@@ -152,8 +152,9 @@ sub ReadValue($$$;$$$);
|
|
|
152
152
|
Real::Media Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE
|
|
153
153
|
JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion
|
|
154
154
|
EXE::PEString EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard
|
|
155
|
-
Text VCard::VCalendar VCard::VNote RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR
|
|
156
|
-
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
|
|
157
158
|
);
|
|
158
159
|
|
|
159
160
|
# alphabetical list of current Lang modules
|
|
@@ -190,12 +191,12 @@ $defaultLang = 'en'; # default language
|
|
|
190
191
|
# 3) PLIST must be in this list for the binary PLIST format, although it may
|
|
191
192
|
# cause a file to be checked twice for XML
|
|
192
193
|
@fileTypes = qw(JPEG EXV CRW DR4 TIFF GIF MRW RAF X3F JP2 PNG MIE MIFF PS PDF
|
|
193
|
-
PSD XMP BMP BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV
|
|
194
|
-
FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
|
195
|
-
HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR
|
|
196
|
-
CZI TAR
|
|
197
|
-
MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA
|
|
198
|
-
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
|
+
7Z 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);
|
|
199
200
|
|
|
200
201
|
# file types that we can write (edit)
|
|
201
202
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
|
@@ -227,6 +228,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
227
228
|
'3GP' => ['MOV', '3rd Gen. Partnership Project audio/video'],
|
|
228
229
|
'3GP2'=> '3G2',
|
|
229
230
|
'3GPP'=> '3GP',
|
|
231
|
+
'7Z' => ['7Z', '7z archive'],
|
|
230
232
|
A => ['EXE', 'Static library'],
|
|
231
233
|
AA => ['AA', 'Audible Audiobook'],
|
|
232
234
|
AAE => ['PLIST','Apple edit information'],
|
|
@@ -328,6 +330,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
328
330
|
FPF => ['FPF', 'FLIR Public image Format'],
|
|
329
331
|
FPX => ['FPX', 'FlashPix'],
|
|
330
332
|
GIF => ['GIF', 'Compuserve Graphics Interchange Format'],
|
|
333
|
+
GLV => ['MOV', 'Garmin Low-resolution Video'],
|
|
331
334
|
GPR => ['TIFF', 'General Purpose RAW'], # https://gopro.github.io/gpr/
|
|
332
335
|
GZ => 'GZIP',
|
|
333
336
|
GZIP => ['GZIP', 'GNU ZIP compressed archive'],
|
|
@@ -554,6 +557,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
554
557
|
XMP => ['XMP', 'Extensible Metadata Platform'],
|
|
555
558
|
WOFF => ['Font', 'Web Open Font Format'],
|
|
556
559
|
WOFF2=> ['Font', 'Web Open Font Format2'],
|
|
560
|
+
WPG => ['WPG', 'WordPerfect Graphics'],
|
|
557
561
|
WTV => ['WTV', 'Windows recorded TV show'],
|
|
558
562
|
ZIP => ['ZIP', 'ZIP archive'],
|
|
559
563
|
);
|
|
@@ -588,6 +592,7 @@ my %fileDescription = (
|
|
|
588
592
|
# types may be specified by some modules, eg. QuickTime.pm and RIFF.pm)
|
|
589
593
|
%mimeType = (
|
|
590
594
|
'3FR' => 'image/x-hasselblad-3fr',
|
|
595
|
+
'7Z' => 'application/x-7z-compressed',
|
|
591
596
|
AA => 'audio/audible',
|
|
592
597
|
AAE => 'application/vnd.apple.photos',
|
|
593
598
|
AI => 'application/vnd.adobe.illustrator',
|
|
@@ -789,6 +794,7 @@ my %fileDescription = (
|
|
|
789
794
|
WMA => 'audio/x-ms-wma',
|
|
790
795
|
WMF => 'application/x-wmf',
|
|
791
796
|
WMV => 'video/x-ms-wmv',
|
|
797
|
+
WPG => 'image/x-wpg',
|
|
792
798
|
WTV => 'video/x-ms-wtv',
|
|
793
799
|
X3F => 'image/x-sigma-x3f',
|
|
794
800
|
XCF => 'image/x-xcf',
|
|
@@ -970,7 +976,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
970
976
|
QTIF => '.{4}(idsc|idat|iicc)',
|
|
971
977
|
R3D => '\0\0..RED(1|2)',
|
|
972
978
|
RAF => 'FUJIFILM',
|
|
973
|
-
RAR => 'Rar!\x1a\x07\0',
|
|
979
|
+
RAR => 'Rar!\x1a\x07\x01?\0',
|
|
974
980
|
RAW => '(.{25}ARECOYK|II|MM)',
|
|
975
981
|
Real => '(\.RMF|\.ra\xfd|pnm://|rtsp://|http://)',
|
|
976
982
|
RIFF => '(RIFF|LA0[234]|OFR |LPAC|wvpk|RF64)', # RIFF plus other variants
|
|
@@ -984,6 +990,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
984
990
|
VCard=> '(?i)BEGIN:(VCARD|VCALENDAR|VNOTE)\r\n',
|
|
985
991
|
VRD => 'CANON OPTIONAL DATA\0',
|
|
986
992
|
WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)',
|
|
993
|
+
WPG => '\xff\x57\x50\x43',
|
|
987
994
|
WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d',
|
|
988
995
|
X3F => 'FOVb',
|
|
989
996
|
XCF => 'gimp xcf ',
|
|
@@ -1045,6 +1052,93 @@ my %xmpShorthandOpt = ( 0 => 'None', 1 => 'Shorthand', 2 => ['Shorthand','OneDes
|
|
|
1045
1052
|
maccroatian => 'MacCroatian', cp10082 => 'MacCroatian',
|
|
1046
1053
|
);
|
|
1047
1054
|
|
|
1055
|
+
# list of available options
|
|
1056
|
+
# +-----------------------------------------------------+
|
|
1057
|
+
# ! DON'T FORGET!! When adding any new option, must !
|
|
1058
|
+
# ! decide how it is handled in SetNewValuesFromFile() !
|
|
1059
|
+
# +-----------------------------------------------------+
|
|
1060
|
+
# (Note: All options must exist in this lookup, even if undefined,
|
|
1061
|
+
# to facilitate case-insensitive options. 'Group#' is handled specially)
|
|
1062
|
+
my @availableOptions = (
|
|
1063
|
+
[ 'Binary', undef, 'flag to extract binary values even if tag not specified' ],
|
|
1064
|
+
[ 'ByteOrder', undef, 'default byte order when creating EXIF information' ],
|
|
1065
|
+
[ 'Charset', 'UTF8', 'character set for converting Unicode characters' ],
|
|
1066
|
+
[ 'CharsetEXIF', undef, 'internal EXIF "ASCII" string encoding' ],
|
|
1067
|
+
[ 'CharsetFileName', undef, 'external encoding for file names' ],
|
|
1068
|
+
[ 'CharsetID3', 'Latin','internal ID3v1 character set' ],
|
|
1069
|
+
[ 'CharsetIPTC', 'Latin','fallback IPTC character set if no CodedCharacterSet' ],
|
|
1070
|
+
[ 'CharsetPhotoshop', 'Latin','internal encoding for Photoshop resource names' ],
|
|
1071
|
+
[ 'CharsetQuickTime', 'MacRoman', 'internal QuickTime string encoding' ],
|
|
1072
|
+
[ 'CharsetRIFF', 0, 'internal RIFF string encoding (0=default to Latin)' ],
|
|
1073
|
+
[ 'Compact', { }, 'write compact XMP' ],
|
|
1074
|
+
[ 'Composite', 1, 'flag to calculate Composite tags' ],
|
|
1075
|
+
[ 'Compress', undef, 'flag to write new values as compressed if possible' ],
|
|
1076
|
+
[ 'CoordFormat', undef, 'GPS lat/long coordinate format' ],
|
|
1077
|
+
[ 'DateFormat', undef, 'format for date/time' ],
|
|
1078
|
+
[ 'Duplicates', 1, 'flag to save duplicate tag values' ],
|
|
1079
|
+
[ 'Escape', undef, 'escape special characters' ],
|
|
1080
|
+
[ 'Exclude', undef, 'tags to exclude' ],
|
|
1081
|
+
[ 'ExtendedXMP', 1, 'strategy for reading extended XMP' ],
|
|
1082
|
+
[ 'ExtractEmbedded', undef, 'flag to extract information from embedded documents' ],
|
|
1083
|
+
[ 'FastScan', undef, 'flag to avoid scanning for trailer' ],
|
|
1084
|
+
[ 'Filter', undef, 'output filter for all tag values' ],
|
|
1085
|
+
[ 'FilterW', undef, 'input filter when writing tag values' ],
|
|
1086
|
+
[ 'FixBase', undef, 'fix maker notes base offsets' ],
|
|
1087
|
+
[ 'GeoMaxIntSecs', 1800, 'geotag maximum interpolation time (secs)' ],
|
|
1088
|
+
[ 'GeoMaxExtSecs', 1800, 'geotag maximum extrapolation time (secs)' ],
|
|
1089
|
+
[ 'GeoMaxHDOP', undef, 'geotag maximum HDOP' ],
|
|
1090
|
+
[ 'GeoMaxPDOP', undef, 'geotag maximum PDOP' ],
|
|
1091
|
+
[ 'GeoMinSats', undef, 'geotag minimum satellites' ],
|
|
1092
|
+
[ 'GeoSpeedRef', undef, 'geotag GPSSpeedRef' ],
|
|
1093
|
+
[ 'GlobalTimeShift', undef, 'apply time shift to all extracted date/time values' ],
|
|
1094
|
+
[ 'Group#', undef, 'return tags for specified groups in family #' ],
|
|
1095
|
+
[ 'HexTagIDs', 0, 'use hex tag ID\'s in family 7 group names' ],
|
|
1096
|
+
[ 'HtmlDump', 0, 'HTML dump (0-3, higher # = bigger limit)' ],
|
|
1097
|
+
[ 'HtmlDumpBase', undef, 'base address for HTML dump' ],
|
|
1098
|
+
[ 'IgnoreMinorErrors',undef, 'ignore minor errors when reading/writing' ],
|
|
1099
|
+
[ 'IgnoreTags', undef, 'list of tags to ignore when extracting' ],
|
|
1100
|
+
[ 'ImageHashType', 'MD5', 'image hash algorithm' ],
|
|
1101
|
+
[ 'Lang', $defaultLang, 'localized language for descriptions etc' ],
|
|
1102
|
+
[ 'LargeFileSupport', undef, 'flag indicating support of 64-bit file offsets' ],
|
|
1103
|
+
[ 'List', undef, '[deprecated, use ListSplit and ListJoin instead]' ],
|
|
1104
|
+
[ 'ListItem', undef, 'used to return a specific item from lists' ],
|
|
1105
|
+
[ 'ListJoin', ', ', 'join lists together with this separator' ],
|
|
1106
|
+
[ 'ListSep', ', ', '[deprecated, use ListSplit and ListJoin instead]' ],
|
|
1107
|
+
[ 'ListSplit', undef, 'regex for splitting list-type tag values when writing' ],
|
|
1108
|
+
[ 'MakerNotes', undef, 'extract maker notes as a block' ],
|
|
1109
|
+
[ 'MDItemTags', undef, 'extract MacOS metadata item tags' ],
|
|
1110
|
+
[ 'MissingTagValue', undef, 'value for missing tags when expanded in expressions' ],
|
|
1111
|
+
[ 'NoMultiExif', undef, 'raise error when writing multi-segment EXIF' ],
|
|
1112
|
+
[ 'NoPDFList', undef, 'flag to avoid splitting PDF List-type tag values' ],
|
|
1113
|
+
[ 'NoWarning', undef, 'regular expression for warnings to suppress' ],
|
|
1114
|
+
[ 'Password', undef, 'password for password-protected PDF documents' ],
|
|
1115
|
+
[ 'PrintConv', 1, 'flag to enable print conversion' ],
|
|
1116
|
+
[ 'QuickTimeHandler', 1, 'flag to add mdir Handler to newly created Meta box' ],
|
|
1117
|
+
[ 'QuickTimePad', undef, 'flag to preserve padding of QuickTime CR3 tags' ],
|
|
1118
|
+
[ 'QuickTimeUTC', undef, 'assume that QuickTime date/time tags are stored as UTC' ],
|
|
1119
|
+
[ 'RequestAll', undef, 'extract all tags that must be specifically requested' ],
|
|
1120
|
+
[ 'RequestTags', undef, 'extra tags to request (on top of those in the tag list)' ],
|
|
1121
|
+
[ 'SaveFormat', undef, 'save family 6 tag TIFF format' ],
|
|
1122
|
+
[ 'SavePath', undef, 'save family 5 location path' ],
|
|
1123
|
+
[ 'ScanForXMP', undef, 'flag to scan for XMP information in all files' ],
|
|
1124
|
+
[ 'Sort', 'Input','order to sort found tags (Input, File, Tag, Descr, Group#)' ],
|
|
1125
|
+
[ 'Sort2', 'File', 'secondary sort order for tags in a group (File, Tag, Descr)' ],
|
|
1126
|
+
[ 'StrictDate', undef, 'flag to return undef for invalid date conversions' ],
|
|
1127
|
+
[ 'Struct', undef, 'return structures as hash references' ],
|
|
1128
|
+
[ 'StructFormat', undef, 'format for structure serialization when reading/writing' ],
|
|
1129
|
+
[ 'SystemTags', undef, 'extract additional File System tags' ],
|
|
1130
|
+
[ 'TextOut', \*STDOUT, 'file for Verbose/HtmlDump output' ],
|
|
1131
|
+
[ 'TimeZone', undef, 'local time zone' ],
|
|
1132
|
+
[ 'Unknown', 0, 'flag to get values of unknown tags (0-2)' ],
|
|
1133
|
+
[ 'UserParam', { }, 'user parameters for additional user-defined tag values' ],
|
|
1134
|
+
[ 'Validate', undef, 'perform additional validation' ],
|
|
1135
|
+
[ 'Verbose', 0, 'print verbose messages (0-5, higher # = more verbose)' ],
|
|
1136
|
+
[ 'WriteMode', 'wcg', 'enable all write modes by default' ],
|
|
1137
|
+
[ 'XAttrTags', undef, 'extract MacOS extended attribute tags' ],
|
|
1138
|
+
[ 'XMPAutoConv', 1, 'automatic conversion of unknown XMP tag values' ],
|
|
1139
|
+
[ 'XMPShorthand', 0, '[deprecated, use Compact=Shorthand instead]' ],
|
|
1140
|
+
);
|
|
1141
|
+
|
|
1048
1142
|
# default family 0 group priority for writing
|
|
1049
1143
|
# (NOTE: tags in groups not specified here will not be written unless
|
|
1050
1144
|
# overridden by the module or specified when writing)
|
|
@@ -1823,15 +1917,17 @@ my %systemTagsNotes = (
|
|
|
1823
1917
|
if specifically requested
|
|
1824
1918
|
},
|
|
1825
1919
|
},
|
|
1826
|
-
|
|
1920
|
+
ImageDataHash => {
|
|
1827
1921
|
Notes => q{
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
videos, and some RIFF-based files
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1922
|
+
Hash of image data. Generated only if specifically requested for JPEG, TIFF,
|
|
1923
|
+
PNG, CRW, CR3, MRW, RAF, X3F, IIQ, JP2, JXL, HEIC and AVIF images, MOV/MP4
|
|
1924
|
+
videos, and some RIFF-based files such as AVI, WAV and WEBP. The hash
|
|
1925
|
+
algorithm is set by the API L<ImageHashType|../ExifTool.html#ImageHashType> option, and is 'MD5' by default.
|
|
1926
|
+
The hash includes the main image data, plus JpgFromRaw/OtherImage for some
|
|
1927
|
+
formats, but does not include ThumbnailImage or PreviewImage. Includes
|
|
1928
|
+
video and audio data for MOV/MP4. The L<XMP-et:OriginalImageHash and
|
|
1929
|
+
XMP-et:OriginalImageHashType tags|XMP.html#ExifTool> provide a way to store
|
|
1930
|
+
the this hash value and the hash type in the file.
|
|
1835
1931
|
},
|
|
1836
1932
|
},
|
|
1837
1933
|
);
|
|
@@ -2125,8 +2221,10 @@ sub Options($$;@)
|
|
|
2125
2221
|
|
|
2126
2222
|
while (@_) {
|
|
2127
2223
|
my $param = shift;
|
|
2224
|
+
my $plus;
|
|
2128
2225
|
# fix parameter case if necessary
|
|
2129
2226
|
unless (exists $$options{$param}) {
|
|
2227
|
+
$plus = $param =~ s/\+$//;
|
|
2130
2228
|
my ($fixed) = grep /^$param$/i, keys %$options;
|
|
2131
2229
|
if ($fixed) {
|
|
2132
2230
|
$param = $fixed;
|
|
@@ -2291,6 +2389,35 @@ sub Options($$;@)
|
|
|
2291
2389
|
$compact{$p} = $val; # preserve most recent setting
|
|
2292
2390
|
}
|
|
2293
2391
|
$$options{Compact} = $$options{XMPShorthand} = \%compact;
|
|
2392
|
+
} elsif ($param eq 'NoWarning') {
|
|
2393
|
+
# validate regular expression
|
|
2394
|
+
undef $evalWarning;
|
|
2395
|
+
if (defined $newVal) {
|
|
2396
|
+
local $SIG{'__WARN__'} = \&SetWarning;
|
|
2397
|
+
eval { $param =~ /$newVal/ };
|
|
2398
|
+
$@ and $evalWarning = $@;
|
|
2399
|
+
}
|
|
2400
|
+
if ($evalWarning) {
|
|
2401
|
+
warn 'NoWarning: ' . CleanWarning() . "\n";
|
|
2402
|
+
next;
|
|
2403
|
+
}
|
|
2404
|
+
# add to existing expression if specified
|
|
2405
|
+
if ($plus and defined $oldVal) {
|
|
2406
|
+
$newVal = defined $newVal ? "$oldVal|$newVal" : $oldVal;
|
|
2407
|
+
}
|
|
2408
|
+
$$options{$param} = $newVal;
|
|
2409
|
+
} elsif ($param eq 'ImageHashType') {
|
|
2410
|
+
if (defined $newVal and $newVal =~ /^(MD5|SHA256|SHA512)$/i) {
|
|
2411
|
+
$$options{$param} = uc($newVal);
|
|
2412
|
+
} else {
|
|
2413
|
+
warn("Invalid $param setting '${newVal}'\n"), return $oldVal;
|
|
2414
|
+
}
|
|
2415
|
+
} elsif ($param eq 'StructFormat') {
|
|
2416
|
+
if (defined $newVal) {
|
|
2417
|
+
$newVal =~ /^(JSON|JSONQ)$/i or warn("Invalid $param setting '${newVal}'\n"), return $oldVal;
|
|
2418
|
+
$newVal = uc($newVal);
|
|
2419
|
+
}
|
|
2420
|
+
$$options{$param} = $newVal;
|
|
2294
2421
|
} else {
|
|
2295
2422
|
if ($param eq 'Escape') {
|
|
2296
2423
|
# set ESCAPE_PROC
|
|
@@ -2328,89 +2455,11 @@ sub ClearOptions($)
|
|
|
2328
2455
|
local $_;
|
|
2329
2456
|
my $self = shift;
|
|
2330
2457
|
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
#
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
# (Note: All options must exist in this lookup, even if undefined,
|
|
2337
|
-
# to facilitate case-insensitive options. 'Group#' is handled specially)
|
|
2338
|
-
$$self{OPTIONS} = {
|
|
2339
|
-
Binary => undef, # flag to extract binary values even if tag not specified
|
|
2340
|
-
ByteOrder => undef, # default byte order when creating EXIF information
|
|
2341
|
-
Charset => 'UTF8', # character set for converting Unicode characters
|
|
2342
|
-
CharsetEXIF => undef, # internal EXIF "ASCII" string encoding
|
|
2343
|
-
CharsetFileName => undef, # external encoding for file names
|
|
2344
|
-
CharsetID3 => 'Latin', # internal ID3v1 character set
|
|
2345
|
-
CharsetIPTC => 'Latin', # fallback IPTC character set if no CodedCharacterSet
|
|
2346
|
-
CharsetPhotoshop => 'Latin', # internal encoding for Photoshop resource names
|
|
2347
|
-
CharsetQuickTime => 'MacRoman', # internal QuickTime string encoding
|
|
2348
|
-
CharsetRIFF => 0, # internal RIFF string encoding (0=default to Latin)
|
|
2349
|
-
Compact => { }, # write compact XMP
|
|
2350
|
-
Composite => 1, # flag to calculate Composite tags
|
|
2351
|
-
Compress => undef, # flag to write new values as compressed if possible
|
|
2352
|
-
CoordFormat => undef, # GPS lat/long coordinate format
|
|
2353
|
-
DateFormat => undef, # format for date/time
|
|
2354
|
-
Duplicates => 1, # flag to save duplicate tag values
|
|
2355
|
-
Escape => undef, # escape special characters
|
|
2356
|
-
Exclude => undef, # tags to exclude
|
|
2357
|
-
ExtendedXMP => 1, # strategy for reading extended XMP
|
|
2358
|
-
ExtractEmbedded =>undef,# flag to extract information from embedded documents
|
|
2359
|
-
FastScan => undef, # flag to avoid scanning for trailer
|
|
2360
|
-
Filter => undef, # output filter for all tag values
|
|
2361
|
-
FilterW => undef, # input filter when writing tag values
|
|
2362
|
-
FixBase => undef, # fix maker notes base offsets
|
|
2363
|
-
GeoMaxIntSecs => 1800, # geotag maximum interpolation time (secs)
|
|
2364
|
-
GeoMaxExtSecs => 1800, # geotag maximum extrapolation time (secs)
|
|
2365
|
-
GeoMaxHDOP => undef, # geotag maximum HDOP
|
|
2366
|
-
GeoMaxPDOP => undef, # geotag maximum PDOP
|
|
2367
|
-
GeoMinSats => undef, # geotag minimum satellites
|
|
2368
|
-
GeoSpeedRef => undef, # geotag GPSSpeedRef
|
|
2369
|
-
GlobalTimeShift => undef, # apply time shift to all extracted date/time values
|
|
2370
|
-
# Group# => undef, # return tags for specified groups in family #
|
|
2371
|
-
HexTagIDs => 0, # use hex tag ID's in family 7 group names
|
|
2372
|
-
HtmlDump => 0, # HTML dump (0-3, higher # = bigger limit)
|
|
2373
|
-
HtmlDumpBase => undef, # base address for HTML dump
|
|
2374
|
-
IgnoreMinorErrors => undef, # ignore minor errors when reading/writing
|
|
2375
|
-
IgnoreTags => undef, # list of tags to ignore when extracting
|
|
2376
|
-
Lang => $defaultLang,# localized language for descriptions etc
|
|
2377
|
-
LargeFileSupport => undef, # flag indicating support of 64-bit file offsets
|
|
2378
|
-
List => undef, # extract lists of PrintConv values into arrays [no longer documented]
|
|
2379
|
-
ListItem => undef, # used to return a specific item from lists
|
|
2380
|
-
ListJoin => ', ', # join lists together with this separator
|
|
2381
|
-
ListSep => ', ', # list item separator [no longer documented]
|
|
2382
|
-
ListSplit => undef, # regex for splitting list-type tag values when writing
|
|
2383
|
-
MakerNotes => undef, # extract maker notes as a block
|
|
2384
|
-
MDItemTags => undef, # extract MacOS metadata item tags
|
|
2385
|
-
MissingTagValue =>undef,# value for missing tags when expanded in expressions
|
|
2386
|
-
NoMultiExif => undef, # raise error when writing multi-segment EXIF
|
|
2387
|
-
NoPDFList => undef, # flag to avoid splitting PDF List-type tag values
|
|
2388
|
-
Password => undef, # password for password-protected PDF documents
|
|
2389
|
-
PrintConv => 1, # flag to enable print conversion
|
|
2390
|
-
QuickTimeHandler => 1, # flag to add mdir Handler to newly created Meta box
|
|
2391
|
-
QuickTimePad=> undef, # flag to preserve padding of QuickTime CR3 tags
|
|
2392
|
-
QuickTimeUTC=> undef, # assume that QuickTime date/time tags are stored as UTC
|
|
2393
|
-
RequestAll => undef, # extract all tags that must be specifically requested
|
|
2394
|
-
RequestTags => undef, # extra tags to request (on top of those in the tag list)
|
|
2395
|
-
SaveFormat => undef, # save family 6 tag TIFF format
|
|
2396
|
-
SavePath => undef, # save family 5 location path
|
|
2397
|
-
ScanForXMP => undef, # flag to scan for XMP information in all files
|
|
2398
|
-
Sort => 'Input', # order to sort found tags (Input, File, Tag, Descr, Group#)
|
|
2399
|
-
Sort2 => 'File', # secondary sort order for tags in a group (File, Tag, Descr)
|
|
2400
|
-
StrictDate => undef, # flag to return undef for invalid date conversions
|
|
2401
|
-
Struct => undef, # return structures as hash references
|
|
2402
|
-
SystemTags => undef, # extract additional File System tags
|
|
2403
|
-
TextOut => \*STDOUT,# file for Verbose/HtmlDump output
|
|
2404
|
-
TimeZone => undef, # local time zone
|
|
2405
|
-
Unknown => 0, # flag to get values of unknown tags (0-2)
|
|
2406
|
-
UserParam => { }, # user parameters for additional user-defined tag values
|
|
2407
|
-
Validate => undef, # perform additional validation
|
|
2408
|
-
Verbose => 0, # print verbose messages (0-5, higher # = more verbose)
|
|
2409
|
-
WriteMode => 'wcg', # enable all write modes by default
|
|
2410
|
-
XAttrTags => undef, # extract MacOS extended attribute tags
|
|
2411
|
-
XMPAutoConv => 1, # automatic conversion of unknown XMP tag values
|
|
2412
|
-
XMPShorthand=> 0, # (unused, but needed for backward compatibility)
|
|
2413
|
-
};
|
|
2458
|
+
$$self{OPTIONS} = { }; # clear all options
|
|
2459
|
+
|
|
2460
|
+
# load default options
|
|
2461
|
+
$$self{OPTIONS}{$$_[0]} = $$_[1] foreach @availableOptions;
|
|
2462
|
+
|
|
2414
2463
|
# keep necessary member variables in sync with options
|
|
2415
2464
|
delete $$self{CUR_LANG};
|
|
2416
2465
|
delete $$self{ESCAPE_PROC};
|
|
@@ -2494,32 +2543,22 @@ sub ExtractInfo($;@)
|
|
|
2494
2543
|
}
|
|
2495
2544
|
}
|
|
2496
2545
|
|
|
2497
|
-
# create
|
|
2498
|
-
if ($$req{
|
|
2499
|
-
|
|
2500
|
-
|
|
2546
|
+
# create Hash object if ImageDataHash is requested
|
|
2547
|
+
if ($$req{imagedatahash} and not $$self{ImageDataHash}) {
|
|
2548
|
+
my $imageHashType = $self->Options('ImageHashType');
|
|
2549
|
+
if ($imageHashType =~ /^SHA(256|512)$/i) {
|
|
2550
|
+
if (require Digest::SHA) {
|
|
2551
|
+
$$self{ImageDataHash} = Digest::SHA->new($1);
|
|
2552
|
+
} else {
|
|
2553
|
+
$self->WarnOnce("Install Digest::SHA to calculate image data SHA$1");
|
|
2554
|
+
}
|
|
2555
|
+
} elsif (require Digest::MD5) {
|
|
2556
|
+
$$self{ImageDataHash} = Digest::MD5->new;
|
|
2501
2557
|
} else {
|
|
2502
2558
|
$self->WarnOnce('Install Digest::MD5 to calculate image data MD5');
|
|
2503
2559
|
}
|
|
2504
2560
|
}
|
|
2505
2561
|
++$$self{FILE_SEQUENCE}; # count files read
|
|
2506
|
-
# extract information from alternate files if necessary
|
|
2507
|
-
my ($g8, $altExifTool);
|
|
2508
|
-
foreach $g8 (keys %{$$self{ALT_EXIFTOOL}}) {
|
|
2509
|
-
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
|
2510
|
-
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
|
2511
|
-
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
|
2512
|
-
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
|
2513
|
-
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
|
2514
|
-
$altExifTool->ExtractInfo($$altExifTool{ALT_FILE});
|
|
2515
|
-
# set family 8 group name for all tags
|
|
2516
|
-
foreach (keys %{$$altExifTool{VALUE}}) {
|
|
2517
|
-
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
|
2518
|
-
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
|
2519
|
-
$$ex{G8} = $g8;
|
|
2520
|
-
}
|
|
2521
|
-
$$altExifTool{DID_EXTRACT} = 1;
|
|
2522
|
-
}
|
|
2523
2562
|
}
|
|
2524
2563
|
|
|
2525
2564
|
my $filename = $$self{FILENAME}; # image file name ('' if already open)
|
|
@@ -2661,7 +2700,7 @@ sub ExtractInfo($;@)
|
|
|
2661
2700
|
if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) {
|
|
2662
2701
|
$self->FoundTag('FileType', 'DIR');
|
|
2663
2702
|
$self->FoundTag('FileTypeExtension', '');
|
|
2664
|
-
$self->
|
|
2703
|
+
$self->ExtractAltInfo();
|
|
2665
2704
|
$raf->Close() if $raf;
|
|
2666
2705
|
return 1;
|
|
2667
2706
|
}
|
|
@@ -2679,7 +2718,7 @@ sub ExtractInfo($;@)
|
|
|
2679
2718
|
} else {
|
|
2680
2719
|
$self->Error('Unknown file type');
|
|
2681
2720
|
}
|
|
2682
|
-
$self->
|
|
2721
|
+
$self->ExtractAltInfo();
|
|
2683
2722
|
last; # don't read the file
|
|
2684
2723
|
}
|
|
2685
2724
|
if (@fileTypeList) {
|
|
@@ -2845,8 +2884,7 @@ sub ExtractInfo($;@)
|
|
|
2845
2884
|
}
|
|
2846
2885
|
unless ($reEntry) {
|
|
2847
2886
|
$$self{PATH} = [ ]; # reset PATH
|
|
2848
|
-
|
|
2849
|
-
$self->BuildCompositeTags() if $$options{Composite};
|
|
2887
|
+
$self->ExtractAltInfo();
|
|
2850
2888
|
# do our HTML dump if requested
|
|
2851
2889
|
if ($$self{HTML_DUMP}) {
|
|
2852
2890
|
$raf->Seek(0, 2); # seek to end of file
|
|
@@ -2909,10 +2947,13 @@ sub ExtractInfo($;@)
|
|
|
2909
2947
|
# restore necessary members when exiting re-entrant code
|
|
2910
2948
|
$$self{$_} = $$reEntry{$_} foreach keys %$reEntry;
|
|
2911
2949
|
SetByteOrder($saveOrder);
|
|
2912
|
-
} elsif ($$self{
|
|
2913
|
-
my $digest = $$self{
|
|
2950
|
+
} elsif ($$self{ImageDataHash}) {
|
|
2951
|
+
my $digest = $$self{ImageDataHash}->hexdigest;
|
|
2914
2952
|
# (don't store empty digest)
|
|
2915
|
-
$self->FoundTag(
|
|
2953
|
+
$self->FoundTag(ImageDataHash => $digest) unless
|
|
2954
|
+
$digest eq 'd41d8cd98f00b204e9800998ecf8427e' or
|
|
2955
|
+
$digest eq 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' or
|
|
2956
|
+
$digest eq 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e';
|
|
2916
2957
|
}
|
|
2917
2958
|
|
|
2918
2959
|
# ($type may be undef without an Error when processing sub-documents)
|
|
@@ -3648,14 +3689,15 @@ sub SetNewGroups($;@)
|
|
|
3648
3689
|
|
|
3649
3690
|
#------------------------------------------------------------------------------
|
|
3650
3691
|
# Build Composite tags from Require'd/Desire'd tags
|
|
3651
|
-
# Inputs: 0) ExifTool object reference
|
|
3692
|
+
# Inputs: 0) ExifTool object reference, 1) flag to build only tags that require
|
|
3693
|
+
# tags from alternate files (without this, these tags are ignored)
|
|
3652
3694
|
# Note: Tag values are calculated in alphabetical order unless a tag Require's
|
|
3653
3695
|
# or Desire's another Composite tag, in which case the calculation is
|
|
3654
3696
|
# deferred until after the other tag is calculated.
|
|
3655
3697
|
sub BuildCompositeTags($)
|
|
3656
3698
|
{
|
|
3657
3699
|
local $_;
|
|
3658
|
-
my $self =
|
|
3700
|
+
my ($self, $altOnly) = @_;
|
|
3659
3701
|
|
|
3660
3702
|
$$self{BuildingComposite} = 1;
|
|
3661
3703
|
|
|
@@ -3684,7 +3726,7 @@ COMPOSITE_TAG:
|
|
|
3684
3726
|
# loop through sub-documents if necessary
|
|
3685
3727
|
my $docNum = 0;
|
|
3686
3728
|
for (;;) {
|
|
3687
|
-
my (%tagKey, $found, $index);
|
|
3729
|
+
my (%tagKey, $found, $index, $requireAlt);
|
|
3688
3730
|
# save Require'd and Desire'd tag values in list
|
|
3689
3731
|
for ($index=0; ; ++$index) {
|
|
3690
3732
|
my $reqTag = $$require{$index} || $$desire{$index} || $$inhibit{$index};
|
|
@@ -3739,6 +3781,8 @@ COMPOSITE_TAG:
|
|
|
3739
3781
|
if ($reqTag =~ /\b(File\d+):/i and $$self{ALT_EXIFTOOL}{$1}) {
|
|
3740
3782
|
$et = $$self{ALT_EXIFTOOL}{$1};
|
|
3741
3783
|
$altFile = $1;
|
|
3784
|
+
# set flags indicating we require tags from alternate files
|
|
3785
|
+
$$self{DoAltComposite} = $requireAlt = 1;
|
|
3742
3786
|
}
|
|
3743
3787
|
# (CAREFUL! keys may not be sequential if one was deleted)
|
|
3744
3788
|
for ($key=$name, $i=$$et{DUPL_TAG}{$name} || 0; ; --$i) {
|
|
@@ -3770,6 +3814,8 @@ COMPOSITE_TAG:
|
|
|
3770
3814
|
}
|
|
3771
3815
|
$tagKey{$index} = $reqTag;
|
|
3772
3816
|
}
|
|
3817
|
+
# stop now if this requires alternate tags and we aren't building them
|
|
3818
|
+
last if $requireAlt xor $altOnly;
|
|
3773
3819
|
if ($docNum) {
|
|
3774
3820
|
if ($found) {
|
|
3775
3821
|
$$self{DOC_NUM} = $docNum;
|
|
@@ -3850,6 +3896,15 @@ sub GetCompositeTagInfo($)
|
|
|
3850
3896
|
return $Image::ExifTool::Composite{$compositeID{$tag}[0]};
|
|
3851
3897
|
}
|
|
3852
3898
|
|
|
3899
|
+
#------------------------------------------------------------------------------
|
|
3900
|
+
# Return List ExifTool API options
|
|
3901
|
+
# Returns: 0) reference to list of available options -- each entry is a list
|
|
3902
|
+
# [0=option name, 1=default value, 2=description]
|
|
3903
|
+
sub AvailableOptions()
|
|
3904
|
+
{
|
|
3905
|
+
return \@availableOptions;
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3853
3908
|
#------------------------------------------------------------------------------
|
|
3854
3909
|
# Get tag name (removes copy index)
|
|
3855
3910
|
# Inputs: 0) Tag key
|
|
@@ -4067,6 +4122,49 @@ sub CombineInfo($;@)
|
|
|
4067
4122
|
return \%combinedInfo;
|
|
4068
4123
|
}
|
|
4069
4124
|
|
|
4125
|
+
#------------------------------------------------------------------------------
|
|
4126
|
+
# Read metadata from alternate files and build composite tags
|
|
4127
|
+
# Inputs: 0) ExifTool ref
|
|
4128
|
+
# Notes: This is called after reading the main file so the tags are available
|
|
4129
|
+
# for being used in the file name, but before building Composite tags
|
|
4130
|
+
# so tags from the alternate files may be used in the Composite tags
|
|
4131
|
+
sub ExtractAltInfo($)
|
|
4132
|
+
{
|
|
4133
|
+
my $self = shift;
|
|
4134
|
+
# extract information from alternate files if necessary
|
|
4135
|
+
my ($g8, $altExifTool);
|
|
4136
|
+
my $opts = $$self{OPTIONS};
|
|
4137
|
+
if ($$opts{Composite} and (not $$opts{FastScan} or $$opts{FastScan} < 5)) {
|
|
4138
|
+
# build all composite tags except those requiring tags from alternate files
|
|
4139
|
+
$self->BuildCompositeTags();
|
|
4140
|
+
}
|
|
4141
|
+
foreach $g8 (sort keys %{$$self{ALT_EXIFTOOL}}) {
|
|
4142
|
+
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
|
4143
|
+
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
|
4144
|
+
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
|
4145
|
+
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
|
4146
|
+
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
|
4147
|
+
my $fileName = $$altExifTool{ALT_FILE};
|
|
4148
|
+
# allow tags from the main file to be used in the alternate file names
|
|
4149
|
+
# (eg. -file1 '$originalfilename')
|
|
4150
|
+
if ($fileName =~ /\$/) {
|
|
4151
|
+
my @tags = reverse sort keys %{$$self{VALUE}};
|
|
4152
|
+
$fileName = $self->InsertTagValues(\@tags, $fileName, 'Warn');
|
|
4153
|
+
next unless defined $fileName;
|
|
4154
|
+
}
|
|
4155
|
+
$altExifTool->ExtractInfo($fileName);
|
|
4156
|
+
# set family 8 group name for all tags
|
|
4157
|
+
foreach (keys %{$$altExifTool{VALUE}}) {
|
|
4158
|
+
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
|
4159
|
+
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
|
4160
|
+
$$ex{G8} = $g8;
|
|
4161
|
+
}
|
|
4162
|
+
$$altExifTool{DID_EXTRACT} = 1;
|
|
4163
|
+
}
|
|
4164
|
+
# if necessary, build composite tags that rely on tags from alternate files
|
|
4165
|
+
$self->BuildCompositeTags(1) if $$self{DoAltComposite};
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4070
4168
|
#------------------------------------------------------------------------------
|
|
4071
4169
|
# Get tag table name
|
|
4072
4170
|
# Inputs: 0) ExifTool object reference, 1) tag key
|
|
@@ -4291,11 +4389,11 @@ sub Open($*$;$)
|
|
|
4291
4389
|
|
|
4292
4390
|
#------------------------------------------------------------------------------
|
|
4293
4391
|
# Check to see if a file exists (with Windows Unicode support)
|
|
4294
|
-
# Inputs: 0) ExifTool ref, 1) file name
|
|
4392
|
+
# Inputs: 0) ExifTool ref, 1) file name, 2) flag if we are writing this file
|
|
4295
4393
|
# Returns: true if file exists
|
|
4296
|
-
sub Exists(
|
|
4394
|
+
sub Exists($$;$)
|
|
4297
4395
|
{
|
|
4298
|
-
my ($self, $file) = @_;
|
|
4396
|
+
my ($self, $file, $writing) = @_;
|
|
4299
4397
|
|
|
4300
4398
|
if ($self->EncodeFileName($file)) {
|
|
4301
4399
|
local $SIG{'__WARN__'} = \&SetWarning;
|
|
@@ -4305,10 +4403,12 @@ sub Exists($$)
|
|
|
4305
4403
|
Win32API::File::OPEN_EXISTING(), 0, []) };
|
|
4306
4404
|
return 0 unless $wh;
|
|
4307
4405
|
eval { Win32API::File::CloseHandle($wh) };
|
|
4308
|
-
}
|
|
4406
|
+
} elsif ($writing) {
|
|
4309
4407
|
# (named pipes already exist, but we pretend that they don't
|
|
4310
4408
|
# so we will be able to write them, so test with for pipe -p)
|
|
4311
4409
|
return(-e $file and not -p $file);
|
|
4410
|
+
} else {
|
|
4411
|
+
return(-e $file);
|
|
4312
4412
|
}
|
|
4313
4413
|
return 1;
|
|
4314
4414
|
}
|
|
@@ -4811,6 +4911,7 @@ sub SetFoundTags($)
|
|
|
4811
4911
|
$groupList = [ $$options{$groupOpt} ];
|
|
4812
4912
|
}
|
|
4813
4913
|
foreach (@$groupList) {
|
|
4914
|
+
next unless defined $_;
|
|
4814
4915
|
# groups have priority in order they were specified
|
|
4815
4916
|
++$wantOrder;
|
|
4816
4917
|
my ($groupName, $want);
|
|
@@ -4917,12 +5018,14 @@ sub AUTOLOAD
|
|
|
4917
5018
|
sub Warn($$;$)
|
|
4918
5019
|
{
|
|
4919
5020
|
my ($self, $str, $ignorable) = @_;
|
|
5021
|
+
my $noWarn = $self->Options('NoWarning');
|
|
4920
5022
|
if ($ignorable) {
|
|
4921
5023
|
return 0 if $$self{OPTIONS}{IgnoreMinorErrors};
|
|
4922
5024
|
return 0 if $ignorable eq '3' and $$self{OPTIONS}{Validate};
|
|
5025
|
+
return 1 if defined $noWarn and eval { $str =~ /$noWarn/ };
|
|
4923
5026
|
$str = $ignorable eq '2' ? "[Minor] $str" : "[minor] $str";
|
|
4924
5027
|
}
|
|
4925
|
-
$self->FoundTag('Warning', $str);
|
|
5028
|
+
$self->FoundTag('Warning', $str) unless defined $noWarn and eval { $str =~ /$noWarn/ };
|
|
4926
5029
|
return 1;
|
|
4927
5030
|
}
|
|
4928
5031
|
|
|
@@ -5526,6 +5629,7 @@ my %formatSize = (
|
|
|
5526
5629
|
ifd => 4,
|
|
5527
5630
|
ifd64 => 8,
|
|
5528
5631
|
ue7 => 1,
|
|
5632
|
+
utf8 => 1, # (Exif 3.0)
|
|
5529
5633
|
);
|
|
5530
5634
|
my %readValueProc = (
|
|
5531
5635
|
int8s => \&Get8s,
|
|
@@ -5740,7 +5844,8 @@ sub MakeTagName($)
|
|
|
5740
5844
|
my $name = shift;
|
|
5741
5845
|
$name =~ tr/-_a-zA-Z0-9//dc; # remove illegal characters
|
|
5742
5846
|
$name = ucfirst $name; # capitalize first letter
|
|
5743
|
-
$name = "Tag$name" if length($name) < 2
|
|
5847
|
+
$name = "Tag$name" if length($name) < 2 or $name =~ /^[-0-9]/;
|
|
5848
|
+
# must at least 2 characters long and not start with - or 0-9-
|
|
5744
5849
|
return $name;
|
|
5745
5850
|
}
|
|
5746
5851
|
|
|
@@ -6431,15 +6536,15 @@ sub ProcessJPEG($$)
|
|
|
6431
6536
|
my $req = $$self{REQ_TAG_LOOKUP};
|
|
6432
6537
|
my $htmlDump = $$self{HTML_DUMP};
|
|
6433
6538
|
my %dumpParms = ( Out => $out );
|
|
6434
|
-
my ($ch, $s, $length, $
|
|
6435
|
-
my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
|
|
6539
|
+
my ($ch, $s, $length, $hash, $hashsize);
|
|
6540
|
+
my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
|
|
6436
6541
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
|
6437
6542
|
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
|
6438
6543
|
|
|
6439
|
-
# get pointer to
|
|
6440
|
-
if ($$self{FILE_TYPE}
|
|
6441
|
-
$
|
|
6442
|
-
$
|
|
6544
|
+
# get pointer to hash object if it exists and we are the top-level JPEG or JP2
|
|
6545
|
+
if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
|
|
6546
|
+
$hash = $$self{ImageDataHash};
|
|
6547
|
+
$hashsize = 0;
|
|
6443
6548
|
}
|
|
6444
6549
|
|
|
6445
6550
|
# check to be sure this is a valid JPG (or J2C, or EXV) file
|
|
@@ -6488,7 +6593,7 @@ sub ProcessJPEG($$)
|
|
|
6488
6593
|
#
|
|
6489
6594
|
# read ahead to the next segment unless we have reached EOI, SOS or SOD
|
|
6490
6595
|
#
|
|
6491
|
-
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $
|
|
6596
|
+
unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $hash) or
|
|
6492
6597
|
$marker==0x93))
|
|
6493
6598
|
{
|
|
6494
6599
|
# read up to next marker (JPEG markers begin with 0xff)
|
|
@@ -6520,19 +6625,19 @@ sub ProcessJPEG($$)
|
|
|
6520
6625
|
$nextSegPos = $raf->Tell();
|
|
6521
6626
|
$len -= 4; # subtract size of length word
|
|
6522
6627
|
last unless $raf->Seek($len, 1);
|
|
6523
|
-
} elsif ($
|
|
6628
|
+
} elsif ($hash and defined $marker and ($marker == 0x00 or $marker == 0xda or
|
|
6524
6629
|
($marker >= 0xd0 and $marker <= 0xd7)))
|
|
6525
6630
|
{
|
|
6526
|
-
# calculate
|
|
6527
|
-
$
|
|
6631
|
+
# calculate hash for image data (includes leading ff d9 but not trailing ff da)
|
|
6632
|
+
$hash->add("\xff" . chr($marker));
|
|
6528
6633
|
my $n = $skipped - (length($buff) - 1); # number of extra 0xff's
|
|
6529
6634
|
if (not $n) {
|
|
6530
6635
|
$buff = substr($buff, 0, -1); # remove trailing 0xff
|
|
6531
6636
|
} elsif ($n > 1) {
|
|
6532
6637
|
$buff .= "\xff" x ($n - 1); # add back extra 0xff's
|
|
6533
6638
|
}
|
|
6534
|
-
$
|
|
6535
|
-
$
|
|
6639
|
+
$hash->add($buff);
|
|
6640
|
+
$hashsize += $skipped + 2;
|
|
6536
6641
|
}
|
|
6537
6642
|
# read second segment too if this was the first
|
|
6538
6643
|
next unless defined $marker;
|
|
@@ -6561,7 +6666,8 @@ sub ProcessJPEG($$)
|
|
|
6561
6666
|
$self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
|
|
6562
6667
|
$dumpEnd = $segPos + $length;
|
|
6563
6668
|
}
|
|
6564
|
-
next
|
|
6669
|
+
next if $length < 6 or $gotSize;
|
|
6670
|
+
$gotSize = 1; # (ignore subsequent SOF segments in probably corrupted JPEG)
|
|
6565
6671
|
# extract some useful information
|
|
6566
6672
|
my ($p, $h, $w, $n) = unpack('Cn2C', $$segDataPt);
|
|
6567
6673
|
my $sof = GetTagTable('Image::ExifTool::JPEG::SOF');
|
|
@@ -6743,7 +6849,7 @@ sub ProcessJPEG($$)
|
|
|
6743
6849
|
next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump;
|
|
6744
6850
|
}
|
|
6745
6851
|
# must scan to EOI if Validate or JpegCompressionFactor used
|
|
6746
|
-
next if $$options{Validate} or $calcImageLen or $$req{trailer} or $
|
|
6852
|
+
next if $$options{Validate} or $calcImageLen or $$req{trailer} or $hash;
|
|
6747
6853
|
# nothing interesting to parse after start of scan (SOS)
|
|
6748
6854
|
$success = 1;
|
|
6749
6855
|
last; # all done parsing file
|
|
@@ -6751,6 +6857,11 @@ sub ProcessJPEG($$)
|
|
|
6751
6857
|
pop @$path;
|
|
6752
6858
|
$verbose and print $out "JPEG SOD\n";
|
|
6753
6859
|
$success = 1;
|
|
6860
|
+
if ($hash and $$self{FILE_TYPE} eq 'JP2') {
|
|
6861
|
+
my $pos = $raf->Tell();
|
|
6862
|
+
$self->ImageDataHash($raf, undef, 'SOD');
|
|
6863
|
+
$raf->Seek($pos, 0);
|
|
6864
|
+
}
|
|
6754
6865
|
next if $verbose > 2 or $htmlDump;
|
|
6755
6866
|
last; # all done parsing file
|
|
6756
6867
|
} elsif (defined $markerLenBytes{$marker}) {
|
|
@@ -6767,7 +6878,7 @@ sub ProcessJPEG($$)
|
|
|
6767
6878
|
or ($$options{RequestAll} and $$options{RequestAll} > 2)))
|
|
6768
6879
|
{
|
|
6769
6880
|
my $num = unpack('C',$$segDataPt) & 0x0f; # get table index
|
|
6770
|
-
$dqt[$num] = $$segDataPt if $num < 4; # save for
|
|
6881
|
+
$dqt[$num] = $$segDataPt if $num < 4; # save for hash calculation
|
|
6771
6882
|
}
|
|
6772
6883
|
# handle all other markers
|
|
6773
6884
|
my $dumpType = '';
|
|
@@ -7115,9 +7226,6 @@ sub ProcessJPEG($$)
|
|
|
7115
7226
|
$self->HandleTag($tagTablePtr, 'APP3', $$dataPt);
|
|
7116
7227
|
undef $combinedSegData;
|
|
7117
7228
|
}
|
|
7118
|
-
} elsif ($$self{HasIJPEG}) {
|
|
7119
|
-
$dumpType = 'InfiRay Data',
|
|
7120
|
-
|
|
7121
7229
|
} elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) {
|
|
7122
7230
|
$dumpType = 'PreviewImage'; # (Samsung, HP, BenQ)
|
|
7123
7231
|
$preview = $$segDataPt;
|
|
@@ -7483,8 +7591,11 @@ sub ProcessJPEG($$)
|
|
|
7483
7591
|
}
|
|
7484
7592
|
} elsif ($marker == 0x51) { # SIZ (J2C)
|
|
7485
7593
|
my ($w, $h) = unpack('x2N2', $$segDataPt);
|
|
7486
|
-
|
|
7487
|
-
|
|
7594
|
+
unless ($gotSize) {
|
|
7595
|
+
$gotSize = 1;
|
|
7596
|
+
$self->FoundTag('ImageWidth', $w);
|
|
7597
|
+
$self->FoundTag('ImageHeight', $h);
|
|
7598
|
+
}
|
|
7488
7599
|
} elsif (($marker & 0xf0) != 0xe0) {
|
|
7489
7600
|
$dumpType = "$markerName segment";
|
|
7490
7601
|
$desc = "[JPEG $markerName]"; # (other known JPEG segments)
|
|
@@ -7547,8 +7658,8 @@ sub ProcessJPEG($$)
|
|
|
7547
7658
|
delete $extendedXMP{$guid};
|
|
7548
7659
|
}
|
|
7549
7660
|
}
|
|
7550
|
-
# print verbose
|
|
7551
|
-
print $out "$$self{INDENT}(
|
|
7661
|
+
# print verbose hash message if necessary
|
|
7662
|
+
print $out "$$self{INDENT}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
|
|
7552
7663
|
# calculate JPEGDigest if requested
|
|
7553
7664
|
if (@dqt) {
|
|
7554
7665
|
require Image::ExifTool::JPEGDigest;
|
|
@@ -7743,6 +7854,8 @@ sub DoProcessTIFF($$;$)
|
|
|
7743
7854
|
return 1;
|
|
7744
7855
|
}
|
|
7745
7856
|
}
|
|
7857
|
+
} elsif ($fileType eq 'ARW') {
|
|
7858
|
+
$$self{LOW_PRIORITY_DIR}{IFD1} = 1; # lower priority of IFD1 tags in ARW files
|
|
7746
7859
|
}
|
|
7747
7860
|
# we have a valid TIFF (or whatever) file
|
|
7748
7861
|
if ($fileType and not $$self{VALUE}{FileType}) {
|
|
@@ -7824,6 +7937,9 @@ sub DoProcessTIFF($$;$)
|
|
|
7824
7937
|
if ($$self{TIFF_TYPE} eq 'TIFF') {
|
|
7825
7938
|
$self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage};
|
|
7826
7939
|
}
|
|
7940
|
+
if ($$self{ImageDataHash} and $$self{A100DataOffset} and $raf->Seek($$self{A100DataOffset},0)) {
|
|
7941
|
+
$self->ImageDataHash($raf, undef, 'A100');
|
|
7942
|
+
}
|
|
7827
7943
|
return 1;
|
|
7828
7944
|
}
|
|
7829
7945
|
#
|