exiftool_vendored 12.68.0 → 12.72.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +98 -15
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +10 -10
- data/bin/exiftool +32 -25
- data/bin/lib/Image/ExifTool/AAC.pm +175 -0
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +87 -20
- data/bin/lib/Image/ExifTool/DJI.pm +3 -2
- data/bin/lib/Image/ExifTool/DNG.pm +25 -2
- data/bin/lib/Image/ExifTool/EXE.pm +54 -6
- data/bin/lib/Image/ExifTool/Exif.pm +204 -22
- data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ID3.pm +76 -10
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/JSON.pm +4 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
- data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- data/bin/lib/Image/ExifTool/PNG.pm +8 -13
- data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
- data/bin/lib/Image/ExifTool/Pentax.pm +15 -6
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
- data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
- data/bin/lib/Image/ExifTool/Sony.pm +177 -37
- data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
- data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
- data/bin/lib/Image/ExifTool/Text.pm +4 -5
- data/bin/lib/Image/ExifTool/Validate.pm +23 -20
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteExif.pl +33 -8
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
- data/bin/lib/Image/ExifTool/Writer.pl +121 -28
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +94 -43
- data/bin/lib/Image/ExifTool.pod +28 -17
- data/bin/perl-Image-ExifTool.spec +9 -9
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -37,7 +37,7 @@ use vars qw($VERSION %leicaLensTypes);
|
|
37
37
|
use Image::ExifTool qw(:DataAccess :Utils);
|
38
38
|
use Image::ExifTool::Exif;
|
39
39
|
|
40
|
-
$VERSION = '2.
|
40
|
+
$VERSION = '2.21';
|
41
41
|
|
42
42
|
sub ProcessLeicaLEIC($$$);
|
43
43
|
sub WhiteBalanceConv($;$$);
|
@@ -1991,6 +1991,15 @@ my %shootingMode = (
|
|
1991
1991
|
},
|
1992
1992
|
PrintConvInv => '$_=$val; tr/A-Z0-9//dc; s/(.{3})(19|20)/$1/; $_',
|
1993
1993
|
},
|
1994
|
+
0x05ff => {
|
1995
|
+
Name => 'CameraIFD', # (Leica Q3)
|
1996
|
+
Condition => '$$valPt =~ /^(II\x2a\0\x08\0\0\0|MM\0\x2a\0\0\0\x08)/',
|
1997
|
+
SubDirectory => {
|
1998
|
+
TagTable => 'Image::ExifTool::PanasonicRaw::CameraIFD',
|
1999
|
+
Base => '$start',
|
2000
|
+
ProcessProc => \&Image::ExifTool::ProcessTIFF,
|
2001
|
+
},
|
2002
|
+
},
|
1994
2003
|
);
|
1995
2004
|
|
1996
2005
|
# Leica type5 ShotInfo (ref PH) (X2)
|
@@ -2834,10 +2843,14 @@ sub ProcessLeicaTrailer($;$)
|
|
2834
2843
|
my $val = Image::ExifTool::Exif::RebuildMakerNotes($et, \%dirInfo, $tagTablePtr);
|
2835
2844
|
unless (defined $val) {
|
2836
2845
|
$et->Warn('Error rebuilding maker notes (may be corrupt)') if $len > 4;
|
2837
|
-
$val = $buff
|
2846
|
+
$val = $buff;
|
2838
2847
|
}
|
2839
2848
|
my $key = $et->FoundTag($tagInfo, $val);
|
2840
2849
|
$et->SetGroup($key, 'ExifIFD');
|
2850
|
+
if ($$et{MAKER_NOTE_FIXUP}) {
|
2851
|
+
$$et{TAG_EXTRA}{$key}{Fixup} = $$et{MAKER_NOTE_FIXUP};
|
2852
|
+
delete $$et{MAKER_NOTE_FIXUP};
|
2853
|
+
}
|
2841
2854
|
}
|
2842
2855
|
}
|
2843
2856
|
SetByteOrder($oldOrder);
|
@@ -58,7 +58,7 @@ use Image::ExifTool::Exif;
|
|
58
58
|
use Image::ExifTool::GPS;
|
59
59
|
use Image::ExifTool::HP;
|
60
60
|
|
61
|
-
$VERSION = '3.
|
61
|
+
$VERSION = '3.45';
|
62
62
|
|
63
63
|
sub CryptShutterCount($$);
|
64
64
|
sub PrintFilter($$$);
|
@@ -410,7 +410,8 @@ sub DecodeAFPoints($$$$;$);
|
|
410
410
|
#
|
411
411
|
# Ricoh lenses
|
412
412
|
#
|
413
|
-
'31 1' => '
|
413
|
+
'31 1' => '18.3mm F2.8', #PH (GR III built-in)
|
414
|
+
'31 4' => '26.1mm F2.8', #PH (GR IIIx built-in)
|
414
415
|
);
|
415
416
|
|
416
417
|
# Pentax model ID codes - PH
|
@@ -1141,8 +1142,12 @@ my %binaryDataAttrs = (
|
|
1141
1142
|
3 => 'Manual',
|
1142
1143
|
4 => 'Super Macro', #JD
|
1143
1144
|
5 => 'Pan Focus',
|
1144
|
-
|
1145
|
-
|
1145
|
+
6 => 'Auto-area', # (GR III)
|
1146
|
+
8 => 'Select', # (GR III)
|
1147
|
+
9 => 'Pinpoint', # (GR III)
|
1148
|
+
10 => 'Tracking', # (GR III)
|
1149
|
+
11 => 'Continuous', # (GR III)
|
1150
|
+
12 => 'Snap', # (GR III)
|
1146
1151
|
16 => 'AF-S (Focus-priority)', #17
|
1147
1152
|
17 => 'AF-C (Focus-priority)', #17
|
1148
1153
|
18 => 'AF-A (Focus-priority)', #PH (educated guess)
|
@@ -1903,6 +1908,7 @@ my %binaryDataAttrs = (
|
|
1903
1908
|
'0 28' => 'Quick Macro', # (Q)
|
1904
1909
|
'0 29' => 'Forest', # (Q)
|
1905
1910
|
'0 30' => 'Backlight Silhouette', # (Q)
|
1911
|
+
'0 32' => 'DOF', #PH (GR III)
|
1906
1912
|
# AUTO PICT modes (auto-selected)
|
1907
1913
|
'1 4' => 'Auto PICT (Standard)', #13
|
1908
1914
|
'1 5' => 'Auto PICT (Portrait)', #7 (K100D)
|
@@ -2146,6 +2152,7 @@ my %binaryDataAttrs = (
|
|
2146
2152
|
10 => 'Cross Processing', #31 (K-70)
|
2147
2153
|
11 => 'Flat', #31 (K-70)
|
2148
2154
|
# 256 - seen for GR III
|
2155
|
+
# 257 - seen for GR III
|
2149
2156
|
# 262 - seen for GR III
|
2150
2157
|
32768 => 'n/a',
|
2151
2158
|
},
|
@@ -2584,8 +2591,10 @@ my %binaryDataAttrs = (
|
|
2584
2591
|
PrintConv => {
|
2585
2592
|
0 => 'Off',
|
2586
2593
|
1 => 'On',
|
2587
|
-
'0
|
2588
|
-
'1
|
2594
|
+
'0 0' => 'Off (Off)', #PH (GR III)
|
2595
|
+
'1 1' => 'On (On)', #PH (GR III)
|
2596
|
+
'0 2' => 'Off (Auto)', #PH (GR III)
|
2597
|
+
'1 2' => 'On (Auto)', #PH (GR III)
|
2589
2598
|
},
|
2590
2599
|
},
|
2591
2600
|
0x008b => { #PH (LS465)
|
@@ -15,7 +15,7 @@ use Image::ExifTool::Exif;
|
|
15
15
|
use Image::ExifTool::IPTC;
|
16
16
|
use Image::ExifTool::XMP;
|
17
17
|
|
18
|
-
$VERSION = '1.
|
18
|
+
$VERSION = '1.08';
|
19
19
|
|
20
20
|
sub ProcessPhotoMechanic($$);
|
21
21
|
|
@@ -138,7 +138,7 @@ my %rawCropConv = (
|
|
138
138
|
ValueConv => 'Image::ExifTool::Exif::ExifTime($val)',
|
139
139
|
ValueConvInv => 'Image::ExifTool::IPTC::IptcTime($val)',
|
140
140
|
},
|
141
|
-
CreatorIdentity => { },
|
141
|
+
CreatorIdentity => { List => 'Seq' },
|
142
142
|
);
|
143
143
|
|
144
144
|
#------------------------------------------------------------------------------
|
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
48
48
|
use Image::ExifTool::Exif;
|
49
49
|
use Image::ExifTool::GPS;
|
50
50
|
|
51
|
-
$VERSION = '2.
|
51
|
+
$VERSION = '2.91';
|
52
52
|
|
53
53
|
sub ProcessMOV($$;$);
|
54
54
|
sub ProcessKeys($$$);
|
@@ -638,6 +638,33 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
638
638
|
Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}',
|
639
639
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' },
|
640
640
|
},
|
641
|
+
{ #https://c2pa.org/specifications/
|
642
|
+
Name => 'JUMBF',
|
643
|
+
Condition => '$$valPt=~/^\xd8\xfe\xc3\xd6\x1b\x0e\x48\x3c\x92\x97\x58\x28\x87\x7e\xc4\x81.{4}manifest\0/s',
|
644
|
+
Deletable => 1,
|
645
|
+
SubDirectory => {
|
646
|
+
TagTable => 'Image::ExifTool::Jpeg2000::Main',
|
647
|
+
# 16 bytes uuid
|
648
|
+
# +4 bytes 0
|
649
|
+
# +9 bytes "manifest\0"
|
650
|
+
# +8 bytes absolute(!!!) offset to C2PA uuid "merkle\0" box
|
651
|
+
# =37 bytes total
|
652
|
+
Start => 37,
|
653
|
+
},
|
654
|
+
},
|
655
|
+
{ #https://c2pa.org/specifications/ (NC)
|
656
|
+
Name => 'CBOR',
|
657
|
+
Condition => '$$valPt=~/^\xd8\xfe\xc3\xd6\x1b\x0e\x48\x3c\x92\x97\x58\x28\x87\x7e\xc4\x81.{4}merkle\0/s',
|
658
|
+
Deletable => 1, # (NC)
|
659
|
+
SubDirectory => {
|
660
|
+
TagTable => 'Image::ExifTool::CBOR::Main',
|
661
|
+
# 16 bytes uuid
|
662
|
+
# +4 bytes 0
|
663
|
+
# +7 bytes "merkle\0"
|
664
|
+
# =27 bytes total
|
665
|
+
Start => 27,
|
666
|
+
},
|
667
|
+
},
|
641
668
|
{
|
642
669
|
Name => 'SensorData',
|
643
670
|
Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/',
|
@@ -2311,16 +2338,33 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
2311
2338
|
# RDT9 - only 16-byte header?
|
2312
2339
|
# the boxes below all have a similar header (little-endian):
|
2313
2340
|
# 0 int32u - number of records
|
2314
|
-
# 4
|
2341
|
+
# 4 int32u - sample rate (Hz)
|
2315
2342
|
# 6 int16u - record length in bytes
|
2316
|
-
# 8
|
2317
|
-
#
|
2318
|
-
#
|
2319
|
-
|
2320
|
-
|
2343
|
+
# 8 int16u - 0x0123 = little-endian, 0x3210 = big endian
|
2344
|
+
# 10 int16u[3] - all zeros
|
2345
|
+
# 16 - start of records (each record ends in an int64u timestamp "ts" in ns)
|
2346
|
+
RDTA => {
|
2347
|
+
Name => 'RicohRDTA',
|
2348
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTA' },
|
2349
|
+
},
|
2350
|
+
RDTB => {
|
2351
|
+
Name => 'RicohRDTB',
|
2352
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTB' },
|
2353
|
+
},
|
2354
|
+
RDTC => {
|
2355
|
+
Name => 'RicohRDTC',
|
2356
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTC' },
|
2357
|
+
},
|
2321
2358
|
# RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
|
2322
|
-
|
2359
|
+
RDTG => {
|
2360
|
+
Name => 'RicohRDTG',
|
2361
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTG' },
|
2362
|
+
},
|
2323
2363
|
# RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
|
2364
|
+
RDTL => {
|
2365
|
+
Name => 'RicohRDTL',
|
2366
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTL' },
|
2367
|
+
},
|
2324
2368
|
# ---- Samsung ----
|
2325
2369
|
vndr => 'Vendor', #PH (Samsung PL70)
|
2326
2370
|
SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
|
@@ -2344,7 +2388,7 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
2344
2388
|
# edli - 52 bytes all zero (Samsung WB30F)
|
2345
2389
|
# @etc - 4 bytes all zero (Samsung WB30F)
|
2346
2390
|
# saut - 4 bytes all zero (Samsung SM-N900T)
|
2347
|
-
# smrd - string "TRUEBLUE" (Samsung SM-C101)
|
2391
|
+
# smrd - string "TRUEBLUE" (Samsung SM-C101, etc)
|
2348
2392
|
# ---- TomTom Bandit Action Cam ----
|
2349
2393
|
TTMD => {
|
2350
2394
|
Name => 'TomTomMetaData',
|
@@ -2364,7 +2408,7 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
2364
2408
|
# opax - 164 bytes unknown (center and affine arrays? ref 26)
|
2365
2409
|
# opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
|
2366
2410
|
# intv - 16 bytes all zero
|
2367
|
-
# ----
|
2411
|
+
# ---- Xiaomi ----
|
2368
2412
|
mcvr => {
|
2369
2413
|
Name => 'PreviewImage',
|
2370
2414
|
Groups => { 2 => 'Preview' },
|
@@ -6576,11 +6620,13 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
6576
6620
|
'collection.user' => 'UserCollection', #22
|
6577
6621
|
'Encoded_With' => 'EncodedWith',
|
6578
6622
|
'content.identifier' => 'ContentIdentifier', #forum14874
|
6623
|
+
'encoder' => { }, # forum15418 (written by ffmpeg)
|
6579
6624
|
#
|
6580
6625
|
# the following tags aren't in the com.apple.quicktime namespace:
|
6581
6626
|
#
|
6582
6627
|
'com.apple.photos.captureMode' => 'CaptureMode',
|
6583
6628
|
'com.android.version' => 'AndroidVersion',
|
6629
|
+
'com.android.capture.fps' => 'AndroidCaptureFPS',
|
6584
6630
|
#
|
6585
6631
|
# also seen
|
6586
6632
|
#
|
@@ -9502,9 +9548,9 @@ sub ProcessMOV($$;$)
|
|
9502
9548
|
$et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"};
|
9503
9549
|
}
|
9504
9550
|
# stop processing at mdat/idat if -fast2 is used
|
9505
|
-
last if $fast > 1 and ($tag eq 'mdat' or $tag eq 'idat');
|
9551
|
+
last if $fast > 1 and ($tag eq 'mdat' or ($tag eq 'idat' and $$et{FileType} ne 'HEIC'));
|
9506
9552
|
# load values only if associated with a tag (or verbose) and not too big
|
9507
|
-
if ($size > 0x2000000) { # start to get worried above 32
|
9553
|
+
if ($size > 0x2000000) { # start to get worried above 32 MiB
|
9508
9554
|
# check for RIFF trailer (written by Auto-Vox dashcam)
|
9509
9555
|
if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
|
9510
9556
|
$et->VPrint(0, "Found RIFF trailer");
|
@@ -9521,9 +9567,9 @@ sub ProcessMOV($$;$)
|
|
9521
9567
|
if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
|
9522
9568
|
my $t = PrintableTagID($tag,2);
|
9523
9569
|
if ($size > 0x8000000) {
|
9524
|
-
$et->Warn("Skipping '${t}' atom > 128
|
9570
|
+
$et->Warn("Skipping '${t}' atom > 128 MiB", 1);
|
9525
9571
|
} else {
|
9526
|
-
$et->Warn("Skipping '${t}' atom > 32
|
9572
|
+
$et->Warn("Skipping '${t}' atom > 32 MiB", 2) or $ignore = 0;
|
9527
9573
|
}
|
9528
9574
|
}
|
9529
9575
|
}
|
@@ -83,7 +83,8 @@ my %processByMetaFormat = (
|
|
83
83
|
|
84
84
|
# data lengths for each INSV/INSP record type
|
85
85
|
my %insvDataLen = (
|
86
|
-
|
86
|
+
0x000 => 0, # directory table (any size)
|
87
|
+
0x200 => 0, # PreviewImage (any size) (a duplicate of PreviewImage in APP2 of INSP files)
|
87
88
|
0x300 => 0, # accelerometer (could be either 20 or 56 bytes)
|
88
89
|
0x400 => 16, # exposure (ref 6)
|
89
90
|
0x600 => 8, # timestamps (ref 6)
|
@@ -91,6 +92,8 @@ my %insvDataLen = (
|
|
91
92
|
# 0x900 => 48, # ? (Insta360 X3)
|
92
93
|
# 0xa00 => 5?, # ? (Insta360 ONE RS)
|
93
94
|
# 0xb00 => 10, # ? (Insta360 X3)
|
95
|
+
# 0xd00 => 10, # ? (Insta360 Ace Pro)
|
96
|
+
# 0x1200 ? # ? (Insta360 Ace Pro)
|
94
97
|
);
|
95
98
|
|
96
99
|
# limit the default amount of data we read for some record types
|
@@ -106,7 +109,7 @@ my %insvLimit = (
|
|
106
109
|
The tags below are extracted from timed metadata in QuickTime and other
|
107
110
|
formats of video files when the ExtractEmbedded option is used. Although
|
108
111
|
most of these tags are combined into the single table below, ExifTool
|
109
|
-
currently reads
|
112
|
+
currently reads 67 different formats of timed GPS metadata from video files.
|
110
113
|
},
|
111
114
|
VARS => { NO_ID => 1 },
|
112
115
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
@@ -2043,7 +2046,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2043
2046
|
return 1;
|
2044
2047
|
|
2045
2048
|
} elsif ($$dataPt =~ /^.{28}A.{11}([NS]).{15}([EW])/s) {
|
2046
|
-
|
2049
|
+
|
2047
2050
|
$debug and $et->FoundTag(GPSType => '2G');
|
2048
2051
|
# Vantrue N4 dashcam
|
2049
2052
|
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
@@ -2778,7 +2781,7 @@ sub ProcessInsta360($;$)
|
|
2778
2781
|
my ($et, $dirInfo) = @_;
|
2779
2782
|
my $raf = $$et{RAF};
|
2780
2783
|
my $offset = $dirInfo ? $$dirInfo{Offset} || 0 : 0;
|
2781
|
-
my $buff;
|
2784
|
+
my ($buff, $dirTable, $dirTablePos);
|
2782
2785
|
|
2783
2786
|
return 0 unless $raf->Seek(-78-$offset, 2) and $raf->Read($buff, 78) == 78 and
|
2784
2787
|
substr($buff,-32) eq "8db42d694ccc418790edff439fe026bf"; # check magic number
|
@@ -2868,7 +2871,19 @@ sub ProcessInsta360($;$)
|
|
2868
2871
|
if ($len % $dlen and $id != 0x700) { # (have seen one 0x700 record which was expected format but not multiple of 53 bytes)
|
2869
2872
|
$et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
|
2870
2873
|
} elsif ($id == 0x200) {
|
2871
|
-
|
2874
|
+
# there are 4 types of record 0x200
|
2875
|
+
# 1. JPEG preview (starts with ff d8 ff e1)
|
2876
|
+
# 2. TIFF preview (starts with 01 00 00 00, then record length)
|
2877
|
+
# 3. Unknown 1 (starts with 00 00 00 01)
|
2878
|
+
# 4. Unknown 2 (starts with 00 00 01 34)
|
2879
|
+
if ($buff =~ /^\xff\xd8\xff/) {
|
2880
|
+
$et->FoundTag(PreviewImage => $buff);
|
2881
|
+
} elsif ($buff =~ /^\x01\0\0\0(.{4})\x01/s and unpack('V',$1) == $dlen) {
|
2882
|
+
my ($w, $h) = unpack('x16V2',$buff);
|
2883
|
+
# build the TIFF image (could the 1 at byte 9 be the SamplesPerPixel?)
|
2884
|
+
my $hdr = Image::ExifTool::MakeTiffHeader($w, $h, 1, 8);
|
2885
|
+
$et->FoundTag(PreviewTIFF => $hdr . substr($buff, 40));
|
2886
|
+
}
|
2872
2887
|
} elsif ($id == 0x300) {
|
2873
2888
|
for ($p=0; $p<$len; $p+=$dlen) {
|
2874
2889
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
@@ -2899,7 +2914,7 @@ sub ProcessInsta360($;$)
|
|
2899
2914
|
my $tmp = substr($buff, $p, $dlen);
|
2900
2915
|
my @a = unpack('VVvaa8aa8aa8a8a8', $tmp);
|
2901
2916
|
unless (($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation)
|
2902
|
-
($a[7] eq 'E' or $a[7] eq 'W' or
|
2917
|
+
($a[7] eq 'E' or $a[7] eq 'W' or
|
2903
2918
|
# (odd, but I've seen "O" instead of "W". Perhaps
|
2904
2919
|
# when the language is french? ie. "Ouest"?)
|
2905
2920
|
$a[7] eq 'O'))
|
@@ -2913,13 +2928,15 @@ sub ProcessInsta360($;$)
|
|
2913
2928
|
$a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10;
|
2914
2929
|
$a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed)
|
2915
2930
|
$a[6] = -abs($a[6]) if $a[7] ne 'E';
|
2916
|
-
|
2931
|
+
my $ms = '';
|
2932
|
+
$a[2] and ($ms = sprintf('.%.3d', $a[2])) =~ s/0+$//;
|
2933
|
+
$et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . $ms . 'Z');
|
2917
2934
|
$et->HandleTag($tagTbl, GPSLatitude => $a[4]);
|
2918
2935
|
$et->HandleTag($tagTbl, GPSLongitude => $a[6]);
|
2919
2936
|
$et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph);
|
2920
2937
|
$et->HandleTag($tagTbl, GPSTrack => $a[9]);
|
2921
2938
|
$et->HandleTag($tagTbl, GPSAltitude => $a[10]);
|
2922
|
-
$et->HandleTag($tagTbl, Unknown02 =>
|
2939
|
+
$et->HandleTag($tagTbl, Unknown02 => $a[1]) if $unknown;
|
2923
2940
|
}
|
2924
2941
|
}
|
2925
2942
|
} elsif ($id == 0x101) {
|
@@ -2932,10 +2949,41 @@ sub ProcessInsta360($;$)
|
|
2932
2949
|
$et->HandleTag($tagTablePtr, $t, $val);
|
2933
2950
|
$p += 2 + $n;
|
2934
2951
|
}
|
2952
|
+
} elsif ($id == 0x0) {
|
2953
|
+
last if not $len;
|
2954
|
+
# example directory table for record locations from Insta360AcePro MP4 video:
|
2955
|
+
# vv vv - record ID
|
2956
|
+
# vv vv vv vv - record size
|
2957
|
+
# vv vv vv vv - offset from start of footer
|
2958
|
+
# 00 00 00 00 00 00 00 00 00 00
|
2959
|
+
# 01 01 82 04 00 00 1b 45 62 00
|
2960
|
+
# 02 00 28 46 05 00 ed fe 5c 00
|
2961
|
+
# 03 00 40 aa 24 00 ed fe 34 00
|
2962
|
+
# 04 00 00 c1 01 00 ed fe 30 00
|
2963
|
+
# [...]
|
2964
|
+
unless ($dirTable) {
|
2965
|
+
$dirTable = $buff;
|
2966
|
+
$dirTablePos = 0;
|
2967
|
+
}
|
2935
2968
|
}
|
2936
|
-
|
2937
|
-
|
2938
|
-
|
2969
|
+
# step through directory table instead of sequential scanning if possible
|
2970
|
+
if ($dirTable) {
|
2971
|
+
undef $epos;
|
2972
|
+
for (;;) {
|
2973
|
+
last if $dirTablePos + 10 > length($dirTable);
|
2974
|
+
my ($id, $siz, $off) = unpack("x${dirTablePos}vVV", $dirTable);
|
2975
|
+
$dirTablePos += 10;
|
2976
|
+
if ($id and $siz and $off + $siz < $trailerLen) {
|
2977
|
+
$epos = $off + $siz - $trailerLen;
|
2978
|
+
last;
|
2979
|
+
}
|
2980
|
+
}
|
2981
|
+
last unless defined $epos;
|
2982
|
+
} else {
|
2983
|
+
($epos -= 6) + $trailerLen < 0 and last; # step back to previous record
|
2984
|
+
}
|
2985
|
+
$raf->Seek($epos, 2) or last; # seek to start of next footer
|
2986
|
+
$raf->Read($buff, 6) == 6 or last; # read footer
|
2939
2987
|
}
|
2940
2988
|
$$et{DOC_NUM} = 0;
|
2941
2989
|
SetByteOrder('MM');
|
@@ -343,9 +343,10 @@ numerical, and generated automatically otherwise.
|
|
343
343
|
but applied automatically to individual tags. Value specifies
|
344
344
|
pattern for split, or 1 for default pattern ',?\\s+'.
|
345
345
|
|
346
|
-
'Avoid' - avoid creating this tag if possible.
|
347
|
-
effective if another tag exists with the same
|
348
|
-
this flag also sets the default Priority to 0
|
346
|
+
'Avoid' - avoid creating this tag when writing if possible.
|
347
|
+
This is only effective if another tag exists with the same
|
348
|
+
name. Setting this flag also sets the default Priority to 0
|
349
|
+
for this tag.
|
349
350
|
|
350
351
|
'Binary' - set to 1 for binary data. This has the same effect
|
351
352
|
as setting ValueConv to '\$val', but it it a bit cleaner and
|
@@ -615,9 +616,9 @@ numerical, and generated automatically otherwise.
|
|
615
616
|
arguments: the value, a flag which is set for the inverse
|
616
617
|
conversion, and a reference to the PrintConv hash, and returns
|
617
618
|
the converted value or undef on error -- it may call warn() to
|
618
|
-
return an error message.
|
619
|
+
return an error message. The lookup hash may also contain a
|
619
620
|
'Notes' entry which is used for documentation if the
|
620
|
-
SeparateTable flag is set).
|
621
|
+
SeparateTable flag is set). In an expression, $self is a
|
621
622
|
reference to the current ExifTool object, $val is the Raw
|
622
623
|
value, and $tag is the tag key. The subroutine takes 2
|
623
624
|
arguments: the Raw value and a reference to the current
|
@@ -893,6 +894,11 @@ numerical, and generated automatically otherwise.
|
|
893
894
|
writing this tag. Only needed if tag can be written to
|
894
895
|
groups other than the normal groups for this tag (very rare).
|
895
896
|
|
897
|
+
Deletable : [Writable SubDirectory's only] Overrides internal test for
|
898
|
+
metadata types with permanent directories (currently QuickTime
|
899
|
+
and Jpeg2000), allowing the tag containing these directories
|
900
|
+
to be deleted
|
901
|
+
|
896
902
|
OffsetPair : Used in EXIF table to specify the tagID for the corresponding
|
897
903
|
offset or length tag.
|
898
904
|
|
@@ -917,6 +923,9 @@ numerical, and generated automatically otherwise.
|
|
917
923
|
FixedSize : [EXIF only] Hack to ignore value size and use this instead.
|
918
924
|
Only valid if Format is also defined.
|
919
925
|
|
926
|
+
TruncateOK : [EXIF only] Hack to demote a truncated value in an IFD to a
|
927
|
+
minor error.
|
928
|
+
|
920
929
|
Struct : [XMP tags only] Reference to structure hash for structured XMP
|
921
930
|
tags. See "STRUCTURES" section below for more details. (For
|
922
931
|
backward compatibility, this may be a name to an entry in
|
@@ -30,7 +30,7 @@ use strict;
|
|
30
30
|
use vars qw($VERSION $AUTOLOAD);
|
31
31
|
use Image::ExifTool qw(:DataAccess :Utils);
|
32
32
|
|
33
|
-
$VERSION = '1.
|
33
|
+
$VERSION = '1.67';
|
34
34
|
|
35
35
|
sub ConvertTimecode($);
|
36
36
|
sub ProcessSGLT($$$);
|
@@ -500,6 +500,11 @@ my %code2charset = (
|
|
500
500
|
Name => 'OldXMP',
|
501
501
|
Binary => 1,
|
502
502
|
},
|
503
|
+
C2PA => { #https://c2pa.org/specifications/
|
504
|
+
Name => 'JUMBF',
|
505
|
+
Deletable => 1,
|
506
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
|
507
|
+
},
|
503
508
|
olym => {
|
504
509
|
Name => 'Olym',
|
505
510
|
SubDirectory => { TagTable => 'Image::ExifTool::Olympus::WAV' },
|
@@ -555,7 +560,7 @@ my %code2charset = (
|
|
555
560
|
},
|
556
561
|
},{ # (WebP) - have also seen with "Exif\0\0" header - PH
|
557
562
|
Name => 'EXIF',
|
558
|
-
Condition => '$$valPt =~ /^Exif\0\0(II\x2a\0|MM\0\x2a)/ and $self->Warn("Improper EXIF header",1)',
|
563
|
+
Condition => '$$valPt =~ /^Exif\0\0(II\x2a\0|MM\0\x2a)/ and ($self->Warn("Improper EXIF header",1) or 1)',
|
559
564
|
SubDirectory => {
|
560
565
|
TagTable => 'Image::ExifTool::Exif::Main',
|
561
566
|
ProcessProc => \&Image::ExifTool::ProcessTIFF,
|
@@ -570,6 +575,12 @@ my %code2charset = (
|
|
570
575
|
Notes => 'WebP files',
|
571
576
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
572
577
|
},
|
578
|
+
"XMP\0" => {
|
579
|
+
Name => 'XMP',
|
580
|
+
Notes => 'incorrectly written WebP files',
|
581
|
+
Condition => '$self->Warn("Incorrect XMP tag ID", 1) or 1',
|
582
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
583
|
+
},
|
573
584
|
ICCP => { #14 (WebP)
|
574
585
|
Name => 'ICC_Profile',
|
575
586
|
Notes => 'WebP files',
|
@@ -1063,7 +1074,16 @@ my %code2charset = (
|
|
1063
1074
|
},
|
1064
1075
|
1 => {
|
1065
1076
|
Name => 'MaxDataRate',
|
1066
|
-
|
1077
|
+
Notes => q{
|
1078
|
+
converted using SI byte prefixes unles the API ByteUnit option is set to
|
1079
|
+
"Binary"
|
1080
|
+
},
|
1081
|
+
PrintConv => q{
|
1082
|
+
my ($unit, $div) = $self->Options('ByteUnit') eq 'Binary' ? ('KiB/s',1024) : ('kB/s',1000);
|
1083
|
+
my $tmp = $val / $div;
|
1084
|
+
$tmp > 9999 and $tmp /= $div, $unit =~ s/^./M/;
|
1085
|
+
sprintf('%.4g %s', $tmp, $unit);
|
1086
|
+
},
|
1067
1087
|
},
|
1068
1088
|
# 2 => 'PaddingGranularity',
|
1069
1089
|
# 3 => 'Flags',
|
@@ -1983,7 +2003,7 @@ sub ProcessRIFF($$)
|
|
1983
2003
|
{
|
1984
2004
|
my ($et, $dirInfo) = @_;
|
1985
2005
|
my $raf = $$dirInfo{RAF};
|
1986
|
-
my ($buff, $buf2, $type, $mime, $err, $rf64);
|
2006
|
+
my ($buff, $buf2, $type, $mime, $err, $rf64, $moviEnd);
|
1987
2007
|
my $verbose = $et->Options('Verbose');
|
1988
2008
|
my $unknown = $et->Options('Unknown');
|
1989
2009
|
my $validate = $et->Options('Validate');
|
@@ -2017,8 +2037,34 @@ sub ProcessRIFF($$)
|
|
2017
2037
|
# Read chunks in RIFF image
|
2018
2038
|
#
|
2019
2039
|
for (;;) {
|
2040
|
+
if ($err) {
|
2041
|
+
last unless $moviEnd;
|
2042
|
+
# we arrived here because there was a problem parsing the movie data
|
2043
|
+
# so seek to the end to continue processing
|
2044
|
+
if ($moviEnd > 0x7fffffff and not $et->Options('LargeFileSupport')) {
|
2045
|
+
$et->Warn('Possibly corrupt LIST_movi data');
|
2046
|
+
$et->Warn('Stopped parsing at large LIST_movi chunk (LargeFileSupport not set)');
|
2047
|
+
undef $err;
|
2048
|
+
last;
|
2049
|
+
}
|
2050
|
+
if ($validate) {
|
2051
|
+
# (must actually try to read something after seeking to detect error)
|
2052
|
+
$raf->Seek($moviEnd-1, 0) and $raf->Read($buff, 1) == 1 or last;
|
2053
|
+
} else {
|
2054
|
+
$raf->Seek($moviEnd, 0) or last;
|
2055
|
+
}
|
2056
|
+
$pos = $moviEnd;
|
2057
|
+
$et->Warn('Possibly corrupt LIST_movi data');
|
2058
|
+
undef $err;
|
2059
|
+
undef $moviEnd;
|
2060
|
+
}
|
2061
|
+
if ($moviEnd) {
|
2062
|
+
$pos > $moviEnd and $err = 1, next; # error if we parsed past the end of the movie data
|
2063
|
+
undef $moviEnd if $pos == $moviEnd; # parsed all movie data?
|
2064
|
+
}
|
2020
2065
|
my $num = $raf->Read($buff, 8);
|
2021
2066
|
if ($num < 8) {
|
2067
|
+
$moviEnd and $err = 1, next;
|
2022
2068
|
$err = 1 if $num;
|
2023
2069
|
$et->Warn('Incorrect RIFF chunk size' . " $pos vs. $riffEnd") if $validate and $pos != $riffEnd;
|
2024
2070
|
last;
|
@@ -2029,7 +2075,7 @@ sub ProcessRIFF($$)
|
|
2029
2075
|
$et->OverrideFileType('Extended WEBP',undef,'webp') if $tag eq 'VP8X' and $type eq 'WEBP';
|
2030
2076
|
# special case: construct new tag name from specific LIST type
|
2031
2077
|
if ($tag eq 'LIST') {
|
2032
|
-
$raf->Read($buff, 4) == 4 or $err=1,
|
2078
|
+
$raf->Read($buff, 4) == 4 or $err=1, next;
|
2033
2079
|
$pos += 4;
|
2034
2080
|
$tag .= "_$buff";
|
2035
2081
|
$len -= 4; # already read 4 bytes (the LIST type)
|
@@ -2038,6 +2084,7 @@ sub ProcessRIFF($$)
|
|
2038
2084
|
}
|
2039
2085
|
$et->VPrint(0, "RIFF '${tag}' chunk ($len bytes of data):\n");
|
2040
2086
|
if ($len <= 0) {
|
2087
|
+
$moviEnd and $err = 1, next;
|
2041
2088
|
if ($len < 0) {
|
2042
2089
|
$et->Warn('Invalid chunk length');
|
2043
2090
|
} elsif ($tag eq "\0\0\0\0") {
|
@@ -2068,7 +2115,7 @@ sub ProcessRIFF($$)
|
|
2068
2115
|
my $tagInfo = $$tagTbl{$tag};
|
2069
2116
|
# (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
|
2070
2117
|
if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
|
2071
|
-
$raf->Read($buff, $len2) == $len2 or $err=1,
|
2118
|
+
$raf->Read($buff, $len2) == $len2 or $err=1, next;
|
2072
2119
|
if ($hash and $isImageData{$tag}) {
|
2073
2120
|
$hash->add($buff);
|
2074
2121
|
$et->VPrint(0, "$$et{INDENT}(ImageDataHash: '${tag}' chunk, $len2 bytes)\n");
|
@@ -2094,7 +2141,7 @@ sub ProcessRIFF($$)
|
|
2094
2141
|
$et->Warn('Incorrect RIFF chunk size') if $validate and $pos - 8 != $riffEnd;
|
2095
2142
|
$riffEnd += $len2 + 8;
|
2096
2143
|
# don't read into RIFF chunk (eg. concatenated video file)
|
2097
|
-
$raf->Read($buff, 4) == 4 or $err=1,
|
2144
|
+
$raf->Read($buff, 4) == 4 or $err=1, next; # (skip RIFF type word)
|
2098
2145
|
$pos += 4;
|
2099
2146
|
# extract information from remaining file as an embedded file
|
2100
2147
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
@@ -2107,18 +2154,21 @@ sub ProcessRIFF($$)
|
|
2107
2154
|
$et->ImageDataHash($raf, $len2, "'${tag}' chunk");
|
2108
2155
|
}
|
2109
2156
|
if ($tag eq 'LIST_movi' and $ee) {
|
2110
|
-
$raf->Seek($rewind, 0) or $err = 1,
|
2157
|
+
$raf->Seek($rewind, 0) or $err = 1, next if $rewind;
|
2158
|
+
# save end-of-movie offset so we can seek there if we get errors parsing the movie data
|
2159
|
+
$moviEnd = $raf->Tell() + $len2;
|
2111
2160
|
next; # parse into movi chunk
|
2112
2161
|
} elsif (not $rewind) {
|
2113
2162
|
if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
|
2163
|
+
$tag =~ s/([\0-\x1f\x7f-\xff])/sprintf('\\x%.2x',ord $1)/eg;
|
2114
2164
|
$et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
|
2115
2165
|
last;
|
2116
2166
|
}
|
2117
2167
|
if ($validate and $len2) {
|
2118
2168
|
# (must actually try to read something after seeking to detect error)
|
2119
|
-
$raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1,
|
2169
|
+
$raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, next;
|
2120
2170
|
} else {
|
2121
|
-
$raf->Seek($len2, 1) or $err=1,
|
2171
|
+
$raf->Seek($len2, 1) or $err=1, next;
|
2122
2172
|
}
|
2123
2173
|
}
|
2124
2174
|
}
|