exiftool-vendored.pl 12.73.0 → 12.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/Changes +94 -6
- package/bin/MANIFEST +4 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +46 -45
- package/bin/config_files/example.config +10 -2
- package/bin/exiftool +143 -94
- package/bin/lib/File/RandomAccess.pm +31 -5
- package/bin/lib/File/RandomAccess.pod +4 -4
- package/bin/lib/Image/ExifTool/7Z.pm +3 -3
- package/bin/lib/Image/ExifTool/AFCP.pm +2 -2
- package/bin/lib/Image/ExifTool/BZZ.pm +2 -2
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +7 -7
- package/bin/lib/Image/ExifTool/Canon.pm +17 -13
- package/bin/lib/Image/ExifTool/CanonVRD.pm +8 -2
- package/bin/lib/Image/ExifTool/DICOM.pm +2 -2
- package/bin/lib/Image/ExifTool/DNG.pm +4 -4
- package/bin/lib/Image/ExifTool/Exif.pm +54 -5
- package/bin/lib/Image/ExifTool/FLIR.pm +2 -2
- package/bin/lib/Image/ExifTool/Fixup.pm +3 -3
- package/bin/lib/Image/ExifTool/FlashPix.pm +3 -3
- package/bin/lib/Image/ExifTool/FujiFilm.pm +8 -3
- package/bin/lib/Image/ExifTool/GPS.pm +5 -3
- package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- package/bin/lib/Image/ExifTool/Geolocation.pm +237 -0
- package/bin/lib/Image/ExifTool/Geotag.pm +4 -4
- package/bin/lib/Image/ExifTool/HtmlDump.pm +7 -4
- package/bin/lib/Image/ExifTool/ID3.pm +2 -2
- package/bin/lib/Image/ExifTool/Import.pm +9 -6
- package/bin/lib/Image/ExifTool/JSON.pm +11 -11
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +51 -12
- package/bin/lib/Image/ExifTool/MIE.pm +3 -3
- package/bin/lib/Image/ExifTool/MWG.pm +1 -0
- package/bin/lib/Image/ExifTool/MacOS.pm +19 -4
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +5 -3
- package/bin/lib/Image/ExifTool/NikonCustom.pm +3 -3
- package/bin/lib/Image/ExifTool/Ogg.pm +4 -3
- package/bin/lib/Image/ExifTool/Olympus.pm +3 -1
- package/bin/lib/Image/ExifTool/PDF.pm +59 -9
- package/bin/lib/Image/ExifTool/PLIST.pm +3 -3
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +3 -3
- package/bin/lib/Image/ExifTool/Pentax.pm +1 -1
- package/bin/lib/Image/ExifTool/PhaseOne.pm +2 -2
- package/bin/lib/Image/ExifTool/Photoshop.pm +3 -3
- package/bin/lib/Image/ExifTool/PostScript.pm +2 -2
- package/bin/lib/Image/ExifTool/QuickTime.pm +223 -117
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +260 -242
- package/bin/lib/Image/ExifTool/RSRC.pm +2 -2
- package/bin/lib/Image/ExifTool/Samsung.pm +4 -4
- package/bin/lib/Image/ExifTool/Shift.pl +1 -2
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +3 -3
- package/bin/lib/Image/ExifTool/Sony.pm +3 -3
- package/bin/lib/Image/ExifTool/TagInfoXML.pm +2 -2
- package/bin/lib/Image/ExifTool/TagLookup.pm +85 -8
- package/bin/lib/Image/ExifTool/TagNames.pod +148 -8
- package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteExif.pl +26 -23
- package/bin/lib/Image/ExifTool/WritePDF.pl +1 -1
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +15 -2
- package/bin/lib/Image/ExifTool/WriteXMP.pl +4 -2
- package/bin/lib/Image/ExifTool/Writer.pl +77 -52
- package/bin/lib/Image/ExifTool/XMP.pm +2 -1
- package/bin/lib/Image/ExifTool/XMP2.pl +9 -0
- package/bin/lib/Image/ExifTool/ZIP.pm +6 -6
- package/bin/lib/Image/ExifTool.pm +204 -63
- package/bin/lib/Image/ExifTool.pod +118 -94
- package/bin/perl-Image-ExifTool.spec +45 -44
- package/bin/pp_build_exe.args +4 -230
- package/package.json +4 -4
|
@@ -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.78';
|
|
33
33
|
$RELEASE = '';
|
|
34
34
|
@ISA = qw(Exporter);
|
|
35
35
|
%EXPORT_TAGS = (
|
|
@@ -77,7 +77,7 @@ sub GetDeleteGroups();
|
|
|
77
77
|
sub AddUserDefinedTags($%);
|
|
78
78
|
sub SetAlternateFile($$$);
|
|
79
79
|
# non-public routines below
|
|
80
|
-
sub InsertTagValues(
|
|
80
|
+
sub InsertTagValues($$;$$$$);
|
|
81
81
|
sub IsWritable($);
|
|
82
82
|
sub IsSameFile($$$);
|
|
83
83
|
sub IsRawType($);
|
|
@@ -195,9 +195,9 @@ $defaultLang = 'en'; # default language
|
|
|
195
195
|
OGG FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF
|
|
196
196
|
LFP HTML VRD RTF FITS XISF XCF DSS QTIF FPX PICT ZIP GZIP PLIST
|
|
197
197
|
RAR 7Z BZ2 CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font
|
|
198
|
-
RSRC M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard
|
|
199
|
-
R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD
|
|
200
|
-
TXT AAC);
|
|
198
|
+
JUMBF RSRC M2TS MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard
|
|
199
|
+
LRI R3D AA PDB PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD
|
|
200
|
+
ICO TXT AAC);
|
|
201
201
|
|
|
202
202
|
# file types that we can write (edit)
|
|
203
203
|
my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS
|
|
@@ -260,6 +260,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
260
260
|
BPG => ['BPG', 'Better Portable Graphics'],
|
|
261
261
|
BTF => ['BTF', 'Big Tagged Image File Format'], #(unofficial)
|
|
262
262
|
BZ2 => ['BZ2', 'BZIP2 archive'],
|
|
263
|
+
C2PA => ['JUMBF','Coalition for Content Provenance and Authenticity'],
|
|
263
264
|
CHM => ['CHM', 'Microsoft Compiled HTML format'],
|
|
264
265
|
CIFF => ['CRW', 'Camera Image File Format'],
|
|
265
266
|
COS => ['COS', 'Capture One Settings'],
|
|
@@ -374,6 +375,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV);
|
|
|
374
375
|
JPS => ['JPEG', 'JPEG Stereo image'],
|
|
375
376
|
JPX => ['JP2', 'JPEG 2000 with extensions'],
|
|
376
377
|
JSON => ['JSON', 'JavaScript Object Notation'],
|
|
378
|
+
JUMBF=> ['JUMBF','JPEG Universal Metadata Box Format'],
|
|
377
379
|
JXL => ['JXL', 'JPEG XL'],
|
|
378
380
|
JXR => ['TIFF', 'JPEG XR'],
|
|
379
381
|
K25 => ['TIFF', 'Kodak DC25 RAW'],
|
|
@@ -612,6 +614,7 @@ my %fileDescription = (
|
|
|
612
614
|
BPG => 'image/bpg',
|
|
613
615
|
BTF => 'image/x-tiff-big', #(NC) (ref http://www.asmail.be/msg0055371937.html)
|
|
614
616
|
BZ2 => 'application/bzip2',
|
|
617
|
+
C2PA => 'application/c2pa',
|
|
615
618
|
'Canon 1D RAW' => 'image/x-raw', # (uses .TIF file extension)
|
|
616
619
|
CHM => 'application/x-chm',
|
|
617
620
|
COS => 'application/octet-stream', #PH (NC)
|
|
@@ -686,6 +689,7 @@ my %fileDescription = (
|
|
|
686
689
|
JPS => 'image/x-jps',
|
|
687
690
|
JPX => 'image/jpx',
|
|
688
691
|
JSON => 'application/json',
|
|
692
|
+
JUMBF=> 'application/octet-stream', #PH (invented format)
|
|
689
693
|
JXL => 'image/jxl', #PH (NC)
|
|
690
694
|
JXR => 'image/jxr',
|
|
691
695
|
K25 => 'image/x-kodak-k25',
|
|
@@ -856,6 +860,7 @@ my %moduleName = (
|
|
|
856
860
|
HDR => 'Radiance',
|
|
857
861
|
JP2 => 'Jpeg2000',
|
|
858
862
|
JPEG => '',
|
|
863
|
+
JUMBF=> 'Jpeg2000',
|
|
859
864
|
JXL => 'Jpeg2000',
|
|
860
865
|
LFP => 'Lytro',
|
|
861
866
|
LRI => 0,
|
|
@@ -947,7 +952,8 @@ $testLen = 1024; # number of bytes to read when testing for magic number
|
|
|
947
952
|
JP2 => '(\0\0\0\x0cjP( |\x1a\x1a)\x0d\x0a\x87\x0a|\xff\x4f\xff\x51\0)',
|
|
948
953
|
JPEG => '\xff\xd8\xff',
|
|
949
954
|
JSON => '(\xef\xbb\xbf)?\s*(\[\s*)?\{\s*"[^"]*"\s*:',
|
|
950
|
-
|
|
955
|
+
JUMBF=> '.{4}jumb\0.{3}jumd',
|
|
956
|
+
JXL => '(\xff\x0a|\0\0\0\x0cJXL \x0d\x0a......ftypjxl )',
|
|
951
957
|
LFP => '\x89LFP\x0d\x0a\x1a\x0a',
|
|
952
958
|
LIF => '\x70\0{3}.{4}\x2a.{4}<\0',
|
|
953
959
|
LNK => '.{4}\x01\x14\x02\0{5}\xc0\0{6}\x46',
|
|
@@ -1095,6 +1101,9 @@ my @availableOptions = (
|
|
|
1095
1101
|
[ 'Filter', undef, 'output filter for all tag values' ],
|
|
1096
1102
|
[ 'FilterW', undef, 'input filter when writing tag values' ],
|
|
1097
1103
|
[ 'FixBase', undef, 'fix maker notes base offsets' ],
|
|
1104
|
+
[ 'Geolocation', undef, 'generate geolocation tags' ],
|
|
1105
|
+
[ 'GeolocMinPop', undef, 'minimum geolocation population' ],
|
|
1106
|
+
[ 'GeolocMaxDist', undef, 'maximum geolocation distance' ],
|
|
1098
1107
|
[ 'GeoMaxIntSecs', 1800, 'geotag maximum interpolation time (secs)' ],
|
|
1099
1108
|
[ 'GeoMaxExtSecs', 1800, 'geotag maximum extrapolation time (secs)' ],
|
|
1100
1109
|
[ 'GeoMaxHDOP', undef, 'geotag maximum HDOP' ],
|
|
@@ -1162,6 +1171,7 @@ my @defaultWriteGroups = qw(
|
|
|
1162
1171
|
|
|
1163
1172
|
# group hash for ExifTool-generated tags
|
|
1164
1173
|
my %allGroupsExifTool = ( 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'ExifTool' );
|
|
1174
|
+
my %geoGroups = ( Groups => { 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'Location' } );
|
|
1165
1175
|
|
|
1166
1176
|
# special tag names (not used for tag info)
|
|
1167
1177
|
%specialTags = map { $_ => 1 } qw(
|
|
@@ -1640,6 +1650,11 @@ my %systemTagsNotes = (
|
|
|
1640
1650
|
Groups => { 0 => 'XML', 1 => 'XML' },
|
|
1641
1651
|
Binary => 1,
|
|
1642
1652
|
},
|
|
1653
|
+
JUMBF => {
|
|
1654
|
+
Notes => 'the C2PA JUMBF data block, extracted only if specifically requested',
|
|
1655
|
+
Groups => { 0 => 'JUMBF', 1 => 'JUMBF' },
|
|
1656
|
+
Binary => 1,
|
|
1657
|
+
},
|
|
1643
1658
|
ICC_Profile => {
|
|
1644
1659
|
Notes => q{
|
|
1645
1660
|
the full ICC_Profile data block. This tag is generated only if specifically
|
|
@@ -1738,6 +1753,11 @@ my %systemTagsNotes = (
|
|
|
1738
1753
|
Notes => 'PDF-format embedded preview image',
|
|
1739
1754
|
Binary => 1,
|
|
1740
1755
|
},
|
|
1756
|
+
PreviewJXL => {
|
|
1757
|
+
Groups => { 2 => 'Preview' },
|
|
1758
|
+
Notes => 'JXL-format embedded preview image',
|
|
1759
|
+
Binary => 1,
|
|
1760
|
+
},
|
|
1741
1761
|
ExifByteOrder => {
|
|
1742
1762
|
Writable => 1,
|
|
1743
1763
|
DelCheck => q{"Can't delete"},
|
|
@@ -1946,6 +1966,82 @@ my %systemTagsNotes = (
|
|
|
1946
1966
|
the this hash value and the hash type in the file.
|
|
1947
1967
|
},
|
|
1948
1968
|
},
|
|
1969
|
+
Geolocate => {
|
|
1970
|
+
Writable => 1,
|
|
1971
|
+
WriteOnly => 1,
|
|
1972
|
+
WriteNothing => 1,
|
|
1973
|
+
AllowGroup => '(xmp|iptc)',
|
|
1974
|
+
Notes => q{
|
|
1975
|
+
this write-only tag accepts GPS coordinates in the same form as GPSPosition
|
|
1976
|
+
and by default writes XMP City, State, CountryCode and Country, but the IPTC
|
|
1977
|
+
group may be specified to instead write IPTC City, Province-State,
|
|
1978
|
+
Country-PrimaryLocationCode and Country-PrimaryLocationName. Writable
|
|
1979
|
+
regardless of the API Geolocation option setting
|
|
1980
|
+
},
|
|
1981
|
+
DelCheck => q{
|
|
1982
|
+
my $grp = lc($wantGroup || 'xmp');
|
|
1983
|
+
if ($grp eq 'xmp') {
|
|
1984
|
+
$self->SetNewValue('XMP:'.$_) foreach qw(City State CountryCode Country);
|
|
1985
|
+
} elsif ($grp eq 'iptc') {
|
|
1986
|
+
$self->SetNewValue('IPTC:'.$_) foreach qw(City Province-State Country-PrimaryLocationCode Country-PrimaryLocationName);
|
|
1987
|
+
}
|
|
1988
|
+
return '';
|
|
1989
|
+
},
|
|
1990
|
+
ValueConvInv => q{
|
|
1991
|
+
my ($lat, $lon) = split /[, ]+/, $val;
|
|
1992
|
+
defined $lat and defined $lon or warn('Invalid GPS position, use "Lat, Lon"'), return undef;
|
|
1993
|
+
my $grp = lc($wantGroup || 'xmp');
|
|
1994
|
+
if ($grp ne 'xmp' and $grp ne 'iptc') {
|
|
1995
|
+
warn "Invalid group name for Geolocate\n";
|
|
1996
|
+
} else {
|
|
1997
|
+
require Image::ExifTool::Geolocation;
|
|
1998
|
+
my @a = Image::ExifTool::Geolocation::Geolocate($lat, $lon,
|
|
1999
|
+
$$self{OPTIONS}{GeolocMinPop}, $$self{OPTIONS}{GeolocMaxDist});
|
|
2000
|
+
my $i = 0;
|
|
2001
|
+
if (not defined $a[0]) {
|
|
2002
|
+
warn "No suitable geolocation found\n";
|
|
2003
|
+
} elsif ($grp eq 'xmp') {
|
|
2004
|
+
foreach (qw(City State CountryCode Country)) {
|
|
2005
|
+
next unless defined $a[$i++];
|
|
2006
|
+
$self->SetNewValue('XMP:'.$_, $self->Decode($a[$i-1],'UTF8'));
|
|
2007
|
+
}
|
|
2008
|
+
} else {
|
|
2009
|
+
$a[2] .= ' '; # pad country code with space to meet IPTC length requirements
|
|
2010
|
+
foreach (qw(City Province-State Country-PrimaryLocationCode Country-PrimaryLocationName)) {
|
|
2011
|
+
next unless defined $a[$i++];
|
|
2012
|
+
$self->SetNewValue('IPTC:'.$_, $self->Decode($a[$i-1],'UTF8'));
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
return '';
|
|
2017
|
+
},
|
|
2018
|
+
PrintConvInv => q{
|
|
2019
|
+
return undef unless $val =~ /(.*? ?[NS]?), ?(.*? ?[EW]?)$/ or
|
|
2020
|
+
$val =~ /^\s*(-?\d+(?:\.\d+)?)\s*(-?\d+(?:\.\d+)?)\s*$/;
|
|
2021
|
+
my ($lat, $lon) = ($1, $2);
|
|
2022
|
+
require Image::ExifTool::GPS;
|
|
2023
|
+
$lat = Image::ExifTool::GPS::ToDegrees($lat, 1, "lat");
|
|
2024
|
+
$lon = Image::ExifTool::GPS::ToDegrees($lon, 1, "lon");
|
|
2025
|
+
return "$lat $lon";
|
|
2026
|
+
},
|
|
2027
|
+
},
|
|
2028
|
+
GeolocationCity => {
|
|
2029
|
+
%geoGroups,
|
|
2030
|
+
Notes => q{
|
|
2031
|
+
name of city nearest to the current GPS coordinates. Geolocation tags are
|
|
2032
|
+
generated only if API Geolocation option is set
|
|
2033
|
+
},
|
|
2034
|
+
},
|
|
2035
|
+
GeolocationRegion => { %geoGroups, Notes => 'geolocation state, province or region' },
|
|
2036
|
+
GeolocationCountry => { %geoGroups, Notes => 'geolocation country name' },
|
|
2037
|
+
GeolocationCountryCode=>{%geoGroups, Notes => 'geolocation country code' },
|
|
2038
|
+
GeolocationTimeZone => { %geoGroups, Notes => 'geolocation time zone name' },
|
|
2039
|
+
GeolocationPopulation=>{ %geoGroups, Notes => 'city population rounded to 1 significant digit' },
|
|
2040
|
+
GeolocationDistance => { %geoGroups, Notes => 'distance in km from current GPS to city', PrintConv => '"$val km"' },
|
|
2041
|
+
GeolocationBearing => { %geoGroups, Notes => 'compass bearing to city center' },
|
|
2042
|
+
GeolocationPosition => { %geoGroups, Notes => 'approximate GPS coordinates of city',
|
|
2043
|
+
PrintConv => '$val =~ s/ /, /; $val',
|
|
2044
|
+
},
|
|
1949
2045
|
);
|
|
1950
2046
|
|
|
1951
2047
|
# tags defined by UserParam option (added at runtime)
|
|
@@ -2196,7 +2292,7 @@ sub new
|
|
|
2196
2292
|
# use Image::ExifTool 'ImageInfo';
|
|
2197
2293
|
# my $info = ImageInfo($file, 'DateTimeOriginal', 'ImageSize');
|
|
2198
2294
|
# - or -
|
|
2199
|
-
# my $et =
|
|
2295
|
+
# my $et = Image::ExifTool->new;
|
|
2200
2296
|
# my $info = $et->ImageInfo($file, \@tagList, {Sort=>'Group0'} );
|
|
2201
2297
|
sub ImageInfo($;@)
|
|
2202
2298
|
{
|
|
@@ -2206,7 +2302,7 @@ sub ImageInfo($;@)
|
|
|
2206
2302
|
if (ref $_[0] and UNIVERSAL::isa($_[0],'Image::ExifTool')) {
|
|
2207
2303
|
$self = shift;
|
|
2208
2304
|
} else {
|
|
2209
|
-
$self =
|
|
2305
|
+
$self = Image::ExifTool->new;
|
|
2210
2306
|
}
|
|
2211
2307
|
my %saveOptions = %{$$self{OPTIONS}}; # save original options
|
|
2212
2308
|
|
|
@@ -2529,7 +2625,7 @@ sub ExtractInfo($;@)
|
|
|
2529
2625
|
FILE_TYPE => $$self{FILE_TYPE},
|
|
2530
2626
|
};
|
|
2531
2627
|
$saveOrder = GetByteOrder(),
|
|
2532
|
-
$$self{RAF} =
|
|
2628
|
+
$$self{RAF} = File::RandomAccess->new($_[0]);
|
|
2533
2629
|
$$self{PROCESSED} = { };
|
|
2534
2630
|
delete $$self{EXIF_DATA};
|
|
2535
2631
|
delete $$self{EXIF_POS};
|
|
@@ -2636,7 +2732,7 @@ sub ExtractInfo($;@)
|
|
|
2636
2732
|
# open the file
|
|
2637
2733
|
if ($self->Open(\*EXIFTOOL_FILE, $filename)) {
|
|
2638
2734
|
# create random access file object
|
|
2639
|
-
$raf =
|
|
2735
|
+
$raf = File::RandomAccess->new(\*EXIFTOOL_FILE);
|
|
2640
2736
|
# patch to force pipe to be buffered because seek returns success
|
|
2641
2737
|
# in Windows cmd shell pipe even though it really failed
|
|
2642
2738
|
$$raf{TESTED} = -1 if $filename eq '-' or $filename =~ /\|$/;
|
|
@@ -2727,7 +2823,7 @@ sub ExtractInfo($;@)
|
|
|
2727
2823
|
if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) {
|
|
2728
2824
|
$self->FoundTag('FileType', 'DIR');
|
|
2729
2825
|
$self->FoundTag('FileTypeExtension', '');
|
|
2730
|
-
$self->
|
|
2826
|
+
$self->DoneExtract();
|
|
2731
2827
|
$raf->Close() if $raf;
|
|
2732
2828
|
return 1;
|
|
2733
2829
|
}
|
|
@@ -2745,7 +2841,7 @@ sub ExtractInfo($;@)
|
|
|
2745
2841
|
} else {
|
|
2746
2842
|
$self->Error('Unknown file type');
|
|
2747
2843
|
}
|
|
2748
|
-
$self->
|
|
2844
|
+
$self->DoneExtract();
|
|
2749
2845
|
last; # don't read the file
|
|
2750
2846
|
}
|
|
2751
2847
|
if (@fileTypeList) {
|
|
@@ -2767,12 +2863,16 @@ sub ExtractInfo($;@)
|
|
|
2767
2863
|
$raf->BinMode(); # set binary mode before we start reading
|
|
2768
2864
|
my $pos = $raf->Tell(); # get file position so we can rewind
|
|
2769
2865
|
# loop through list of file types to test
|
|
2770
|
-
my ($buff, $
|
|
2866
|
+
my ($buff, $err);
|
|
2771
2867
|
my %dirInfo = ( RAF => $raf, Base => $pos, TestBuff => \$buff );
|
|
2772
2868
|
# read start of file for testing
|
|
2773
|
-
$raf->Read($buff, $testLen)
|
|
2774
|
-
|
|
2775
|
-
|
|
2869
|
+
if ($raf->Read($buff, $testLen)) {
|
|
2870
|
+
$raf->Seek($pos, 0) or $err = 'Error seeking in file';
|
|
2871
|
+
} else {
|
|
2872
|
+
$err = $$raf{ERROR};
|
|
2873
|
+
$buff = '';
|
|
2874
|
+
}
|
|
2875
|
+
until ($err) {
|
|
2776
2876
|
my $unkHeader;
|
|
2777
2877
|
$type = shift @fileTypeList;
|
|
2778
2878
|
if ($type) {
|
|
@@ -2795,7 +2895,7 @@ sub ExtractInfo($;@)
|
|
|
2795
2895
|
$type = ($1 eq "\xff\xd8\xff") ? 'JPEG' : 'TIFF';
|
|
2796
2896
|
my $skip = pos($buff) - length($1);
|
|
2797
2897
|
$dirInfo{Base} = $pos + $skip;
|
|
2798
|
-
$raf->Seek($pos + $skip, 0) or $
|
|
2898
|
+
$raf->Seek($pos + $skip, 0) or $err = 'Error seeking in file', last;
|
|
2799
2899
|
$self->Warn("Processing $type-like data after unknown $skip-byte header");
|
|
2800
2900
|
$unkHeader = 1 unless $$self{DOC_NUM};
|
|
2801
2901
|
}
|
|
@@ -2841,14 +2941,13 @@ sub ExtractInfo($;@)
|
|
|
2841
2941
|
last;
|
|
2842
2942
|
}
|
|
2843
2943
|
# seek back to try again from the same position in the file
|
|
2844
|
-
$raf->Seek($pos, 0) or $
|
|
2944
|
+
$raf->Seek($pos, 0) or $err = 'Error seeking in file';
|
|
2845
2945
|
}
|
|
2846
|
-
if (not defined $type and not $$self{DOC_NUM}) {
|
|
2946
|
+
if (not $err and not defined $type and not $$self{DOC_NUM}) {
|
|
2847
2947
|
# if we were given a single image with a known type there
|
|
2848
2948
|
# must be a format error since we couldn't read it, otherwise
|
|
2849
2949
|
# it is likely we don't support images of this type
|
|
2850
2950
|
my $fileType = GetFileType($realname) || '';
|
|
2851
|
-
my $err;
|
|
2852
2951
|
if (not length $buff) {
|
|
2853
2952
|
$err = 'File is empty';
|
|
2854
2953
|
} else {
|
|
@@ -2889,10 +2988,9 @@ sub ExtractInfo($;@)
|
|
|
2889
2988
|
}
|
|
2890
2989
|
}
|
|
2891
2990
|
}
|
|
2892
|
-
$self->Error($err);
|
|
2893
2991
|
}
|
|
2894
|
-
if ($
|
|
2895
|
-
$self->Error(
|
|
2992
|
+
if ($err) {
|
|
2993
|
+
$self->Error($err);
|
|
2896
2994
|
} elsif ($self->Options('ScanForXMP') and (not defined $type or
|
|
2897
2995
|
(not $fast and not $$self{FoundXMP})))
|
|
2898
2996
|
{
|
|
@@ -2911,7 +3009,7 @@ sub ExtractInfo($;@)
|
|
|
2911
3009
|
}
|
|
2912
3010
|
unless ($reEntry) {
|
|
2913
3011
|
$$self{PATH} = [ ]; # reset PATH
|
|
2914
|
-
$self->
|
|
3012
|
+
$self->DoneExtract();
|
|
2915
3013
|
# do our HTML dump if requested
|
|
2916
3014
|
if ($$self{HTML_DUMP}) {
|
|
2917
3015
|
$raf->Seek(0, 2); # seek to end of file
|
|
@@ -2946,27 +3044,10 @@ sub ExtractInfo($;@)
|
|
|
2946
3044
|
last; # (loop was a cheap "goto")
|
|
2947
3045
|
}
|
|
2948
3046
|
|
|
2949
|
-
#
|
|
2950
|
-
|
|
2951
|
-
Image::ExifTool::Validate::FinishValidate($self, $$req{validate});
|
|
2952
|
-
}
|
|
2953
|
-
|
|
3047
|
+
# Note: This should be the only tag generated after BuildCompositeTags,
|
|
3048
|
+
# and as such it can't be used in user-defined Composite tags
|
|
2954
3049
|
@startTime and $self->FoundTag('ProcessingTime', Time::HiRes::tv_interval(\@startTime));
|
|
2955
3050
|
|
|
2956
|
-
# add user-defined parameters that ended with '!'
|
|
2957
|
-
if (%{$$options{UserParam}}) {
|
|
2958
|
-
my $doMsg = $$options{Verbose};
|
|
2959
|
-
my $table = GetTagTable('Image::ExifTool::UserParam');
|
|
2960
|
-
foreach (sort keys %{$$options{UserParam}}) {
|
|
2961
|
-
next unless /#$/;
|
|
2962
|
-
if ($doMsg) {
|
|
2963
|
-
$self->VPrint(0, "UserParam tags:\n");
|
|
2964
|
-
undef $doMsg;
|
|
2965
|
-
}
|
|
2966
|
-
$self->HandleTag($table, $_, $$options{UserParam}{$_});
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
|
|
2970
3051
|
# restore original options
|
|
2971
3052
|
%saveOptions and $$self{OPTIONS} = \%saveOptions;
|
|
2972
3053
|
|
|
@@ -2974,13 +3055,6 @@ sub ExtractInfo($;@)
|
|
|
2974
3055
|
# restore necessary members when exiting re-entrant code
|
|
2975
3056
|
$$self{$_} = $$reEntry{$_} foreach keys %$reEntry;
|
|
2976
3057
|
SetByteOrder($saveOrder);
|
|
2977
|
-
} elsif ($$self{ImageDataHash}) {
|
|
2978
|
-
my $digest = $$self{ImageDataHash}->hexdigest;
|
|
2979
|
-
# (don't store empty digest)
|
|
2980
|
-
$self->FoundTag(ImageDataHash => $digest) unless
|
|
2981
|
-
$digest eq 'd41d8cd98f00b204e9800998ecf8427e' or
|
|
2982
|
-
$digest eq 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' or
|
|
2983
|
-
$digest eq 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e';
|
|
2984
3058
|
}
|
|
2985
3059
|
|
|
2986
3060
|
# ($type may be undef without an Error when processing sub-documents)
|
|
@@ -4114,7 +4188,7 @@ sub Init($)
|
|
|
4114
4188
|
$$self{FileType} = ''; # identified file type
|
|
4115
4189
|
if ($self->Options('HtmlDump')) {
|
|
4116
4190
|
require Image::ExifTool::HtmlDump;
|
|
4117
|
-
$$self{HTML_DUMP} =
|
|
4191
|
+
$$self{HTML_DUMP} = Image::ExifTool::HtmlDump->new;
|
|
4118
4192
|
}
|
|
4119
4193
|
# make sure our TextOut is a file reference
|
|
4120
4194
|
$$self{OPTIONS}{TextOut} = \*STDOUT unless ref $$self{OPTIONS}{TextOut};
|
|
@@ -4151,17 +4225,80 @@ sub CombineInfo($;@)
|
|
|
4151
4225
|
}
|
|
4152
4226
|
|
|
4153
4227
|
#------------------------------------------------------------------------------
|
|
4154
|
-
#
|
|
4228
|
+
# Finish generating tags after extracting information from a file
|
|
4155
4229
|
# Inputs: 0) ExifTool ref
|
|
4156
|
-
# Notes:
|
|
4157
|
-
#
|
|
4158
|
-
#
|
|
4159
|
-
|
|
4230
|
+
# Notes: The sequencing here is a bit tricky because tags from the main file
|
|
4231
|
+
# may be used in the names of alternate files, so we finish generating
|
|
4232
|
+
# all main file tags first (including all Composite tags which don't
|
|
4233
|
+
# rely on alternate files) before extracting tags from alternate files,
|
|
4234
|
+
# then we finish by generating the remaingin Composite tags.
|
|
4235
|
+
sub DoneExtract($)
|
|
4160
4236
|
{
|
|
4161
4237
|
my $self = shift;
|
|
4162
4238
|
# extract information from alternate files if necessary
|
|
4163
4239
|
my ($g8, $altExifTool);
|
|
4164
4240
|
my $opts = $$self{OPTIONS};
|
|
4241
|
+
|
|
4242
|
+
# generate ImageDataHash if requested
|
|
4243
|
+
if ($$self{ImageDataHash}) {
|
|
4244
|
+
my $digest = $$self{ImageDataHash}->hexdigest;
|
|
4245
|
+
# (don't store empty digest)
|
|
4246
|
+
$self->FoundTag(ImageDataHash => $digest) unless
|
|
4247
|
+
$digest eq 'd41d8cd98f00b204e9800998ecf8427e' or
|
|
4248
|
+
$digest eq 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' or
|
|
4249
|
+
$digest eq 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e';
|
|
4250
|
+
}
|
|
4251
|
+
# generate Validate tag if requested
|
|
4252
|
+
if ($$opts{Validate}) {
|
|
4253
|
+
Image::ExifTool::Validate::FinishValidate($self, $$self{REQ_TAG_LOOKUP}{validate});
|
|
4254
|
+
}
|
|
4255
|
+
# generate geolocation tags if requested
|
|
4256
|
+
if ($$opts{Geolocation} and ((defined $$self{VALUE}{GPSLatitude} and
|
|
4257
|
+
defined $$self{VALUE}{GPSLongitude}) or $$self{VALUE}{GPSCoordinates} or
|
|
4258
|
+
$$opts{Geolocation} =~ /,/))
|
|
4259
|
+
{
|
|
4260
|
+
my $lat = $self->GetValue('GPSLatitude', 'ValueConv');
|
|
4261
|
+
my $lon = $self->GetValue('GPSLongitude', 'ValueConv');
|
|
4262
|
+
if (defined $lat and defined $lon) {
|
|
4263
|
+
my $latRef = $$self{VALUE}{GPSLatitudeRef};
|
|
4264
|
+
my $lonRef = $$self{VALUE}{GPSLongitudeRef};
|
|
4265
|
+
$lat = -$lat if $lat and $lat > 0 and $latRef and $latRef eq 'S';
|
|
4266
|
+
$lon = -$lon if $lon and $lon > 0 and $lonRef and $lonRef eq 'W';
|
|
4267
|
+
} elsif ($$self{VALUE}{GPSCoordinates}) {
|
|
4268
|
+
my $pos = $self->GetValue('GPSCoordinates', 'ValueConv');
|
|
4269
|
+
($lat, $lon) = split /[, ]+/, $pos;
|
|
4270
|
+
} else {
|
|
4271
|
+
($lat, $lon) = split /[, ]+/, $$opts{Geolocation};
|
|
4272
|
+
}
|
|
4273
|
+
if (defined $lat and defined $lon) {
|
|
4274
|
+
require Image::ExifTool::Geolocation;
|
|
4275
|
+
my @geo = Image::ExifTool::Geolocation::Geolocate($lat, $lon, $$opts{GeolocMinPop}, $$opts{GeolocMaxDist});
|
|
4276
|
+
if ($geo[0]) {
|
|
4277
|
+
$self->FoundTag(GeolocationCity => $self->Decode($geo[0],'UTF8'));
|
|
4278
|
+
$self->FoundTag(GeolocationRegion => $self->Decode($geo[1],'UTF8')) if $geo[1];
|
|
4279
|
+
$self->FoundTag(GeolocationCountryCode => $geo[2]);
|
|
4280
|
+
$self->FoundTag(GeolocationCountry => $geo[3]) if $geo[3];
|
|
4281
|
+
$self->FoundTag(GeolocationTimeZone => $geo[4]) if $geo[4];
|
|
4282
|
+
$self->FoundTag(GeolocationPopulation => $geo[5]);
|
|
4283
|
+
$self->FoundTag(GeolocationDistance => $geo[6]);
|
|
4284
|
+
$self->FoundTag(GeolocationBearing => $geo[7]) if defined $geo[7];
|
|
4285
|
+
$self->FoundTag(GeolocationPosition => "$geo[8] $geo[9]");
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
# generate tags for user-defined parameters that ended with '#'
|
|
4290
|
+
if (%{$$opts{UserParam}}) {
|
|
4291
|
+
my $doMsg = $$opts{Verbose};
|
|
4292
|
+
my $table = GetTagTable('Image::ExifTool::UserParam');
|
|
4293
|
+
foreach (sort keys %{$$opts{UserParam}}) {
|
|
4294
|
+
next unless /#$/;
|
|
4295
|
+
if ($doMsg) {
|
|
4296
|
+
$self->VPrint(0, "UserParam tags:\n");
|
|
4297
|
+
undef $doMsg;
|
|
4298
|
+
}
|
|
4299
|
+
$self->HandleTag($table, $_, $$opts{UserParam}{$_});
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4165
4302
|
if ($$opts{Composite} and (not $$opts{FastScan} or $$opts{FastScan} < 5)) {
|
|
4166
4303
|
# build all composite tags except those requiring tags from alternate files
|
|
4167
4304
|
$self->BuildCompositeTags();
|
|
@@ -4172,12 +4309,13 @@ sub ExtractAltInfo($)
|
|
|
4172
4309
|
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
|
4173
4310
|
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
|
4174
4311
|
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
|
4312
|
+
$$altExifTool{ReqTagAlreadySet} = 1;
|
|
4175
4313
|
my $fileName = $$altExifTool{ALT_FILE};
|
|
4176
4314
|
# allow tags from the main file to be used in the alternate file names
|
|
4177
4315
|
# (eg. -file1 '$originalfilename')
|
|
4178
4316
|
if ($fileName =~ /\$/) {
|
|
4179
4317
|
my @tags = reverse sort keys %{$$self{VALUE}};
|
|
4180
|
-
$fileName = $self->InsertTagValues(\@tags,
|
|
4318
|
+
$fileName = $self->InsertTagValues($fileName, \@tags, 'Warn');
|
|
4181
4319
|
next unless defined $fileName;
|
|
4182
4320
|
}
|
|
4183
4321
|
$altExifTool->ExtractInfo($fileName);
|
|
@@ -4504,7 +4642,7 @@ sub GetFileTime($$)
|
|
|
4504
4642
|
$atime = $mtime = $ctime = pack 'LL', 0, 0;
|
|
4505
4643
|
unless ($k32GetFileTime) {
|
|
4506
4644
|
return () if defined $k32GetFileTime;
|
|
4507
|
-
$k32GetFileTime =
|
|
4645
|
+
$k32GetFileTime = Win32::API->new('KERNEL32', 'GetFileTime', 'NPPP', 'I');
|
|
4508
4646
|
unless ($k32GetFileTime) {
|
|
4509
4647
|
$self->Warn('Error calling Win32::API::GetFileTime');
|
|
4510
4648
|
$k32GetFileTime = 0;
|
|
@@ -4541,7 +4679,7 @@ sub ParseArguments($;@)
|
|
|
4541
4679
|
my (@exclude, $wasExcludeOpt);
|
|
4542
4680
|
|
|
4543
4681
|
$$self{REQUESTED_TAGS} = [ ];
|
|
4544
|
-
$$self{REQ_TAG_LOOKUP} = { };
|
|
4682
|
+
$$self{REQ_TAG_LOOKUP} = { } unless $$self{ReqTagAlreadySet};
|
|
4545
4683
|
$$self{EXCL_TAG_LOOKUP} = { };
|
|
4546
4684
|
$$self{IO_TAG_LIST} = undef;
|
|
4547
4685
|
delete $$self{EXCL_XMP_LOOKUP};
|
|
@@ -4583,7 +4721,7 @@ sub ParseArguments($;@)
|
|
|
4583
4721
|
my $buff = $@ ? pack('C*',unpack($] < 5.010000 ? 'U0C*' : 'C0C*',$$arg)) : Encode::encode('utf8',$$arg);
|
|
4584
4722
|
$arg = \$buff;
|
|
4585
4723
|
}
|
|
4586
|
-
$$self{RAF} =
|
|
4724
|
+
$$self{RAF} = File::RandomAccess->new($arg);
|
|
4587
4725
|
# set filename to empty string to indicate that
|
|
4588
4726
|
# we have a file but we didn't open it
|
|
4589
4727
|
$$self{FILENAME} = '';
|
|
@@ -5798,7 +5936,7 @@ sub Decode($$$;$$$)
|
|
|
5798
5936
|
# Inputs: 0) ExifTool object ref, 1) string, 2) destination character set name,
|
|
5799
5937
|
# 3) optional destination byte order (2-byte and 4-byte fixed-width sets only)
|
|
5800
5938
|
# Returns: string in specified encoding
|
|
5801
|
-
sub Encode(
|
|
5939
|
+
sub Encode($$;$$)
|
|
5802
5940
|
{
|
|
5803
5941
|
my ($self, $val, $to, $toOrder) = @_;
|
|
5804
5942
|
return $self->Decode($val, undef, undef, $to, $toOrder);
|
|
@@ -6981,7 +7119,7 @@ sub ProcessJPEG($$)
|
|
|
6981
7119
|
} elsif ($$segDataPt =~ /^(II|MM).{4}HEAPJPGM/s) {
|
|
6982
7120
|
next if $fast > 1; # skip processing for very fast
|
|
6983
7121
|
$dumpType = 'CIFF';
|
|
6984
|
-
my %dirInfo = ( RAF =>
|
|
7122
|
+
my %dirInfo = ( RAF => File::RandomAccess->new($segDataPt) );
|
|
6985
7123
|
$$self{SET_GROUP1} = 'CIFF';
|
|
6986
7124
|
push @{$$self{PATH}}, 'CIFF';
|
|
6987
7125
|
require Image::ExifTool::CanonRaw;
|
|
@@ -7506,6 +7644,8 @@ sub ProcessJPEG($$)
|
|
|
7506
7644
|
} elsif ($$segDataPt =~ /^AROT\0/ and $length > 10) {
|
|
7507
7645
|
# iPhone "AROT" segment containing integrated intensity per 16 scan lines
|
|
7508
7646
|
# (with number of elements N = ImageHeight / 16 - 1, ref PH/NealKrawetz)
|
|
7647
|
+
# "Absolute ROTational difference between two frames"
|
|
7648
|
+
# (see https://www.hackerfactor.com/blog/index.php?/archives/822-Apple-Rot.html)
|
|
7509
7649
|
$xtra = 'segment (N=' . unpack('x6N', $$segDataPt) . ')';
|
|
7510
7650
|
}
|
|
7511
7651
|
} elsif ($marker == 0xeb) { # APP11 (JPEG-HDR, JUMBF)
|
|
@@ -7564,6 +7704,7 @@ sub ProcessJPEG($$)
|
|
|
7564
7704
|
$dirInfo{DataPt} = \$buff;
|
|
7565
7705
|
$dirInfo{DataPos} = $segPos + 8; # (shows correct offsets for single-segment JUMBF)
|
|
7566
7706
|
$dirInfo{DataLen} = $dirInfo{DirLen} = $size;
|
|
7707
|
+
$dirInfo{DirName} = 'JUMBF';
|
|
7567
7708
|
my $tagTablePtr = GetTagTable('Image::ExifTool::Jpeg2000::Main');
|
|
7568
7709
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
|
7569
7710
|
delete $jumbfChunk{$type};
|
|
@@ -8005,7 +8146,7 @@ sub DoProcessTIFF($$;$)
|
|
|
8005
8146
|
}
|
|
8006
8147
|
}
|
|
8007
8148
|
# update FileType if necessary now that we know more about the file
|
|
8008
|
-
if ($$self{DNGVersion} and $$self{FileType} !~ /^(DNG|GPR)$/) {
|
|
8149
|
+
if ($$self{DNGVersion} and $$self{FILE_TYPE} eq 'TIFF' and $$self{FileType} !~ /^(DNG|GPR)$/) {
|
|
8009
8150
|
# override whatever FileType we set since we now know it is DNG
|
|
8010
8151
|
$self->OverrideFileType($$self{TIFF_TYPE} = 'DNG');
|
|
8011
8152
|
}
|