exiftool-vendored.pl 12.55.0 → 12.60.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 +97 -4
- package/bin/MANIFEST +9 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +19 -19
- package/bin/arg_files/xmp2exif.args +4 -1
- package/bin/config_files/example.config +1 -0
- package/bin/config_files/rotate_regions.config +1 -1
- package/bin/exiftool +197 -122
- package/bin/fmt_files/kml.fmt +3 -0
- package/bin/fmt_files/kml_track.fmt +3 -0
- package/bin/lib/Image/ExifTool/AIFF.pm +2 -2
- package/bin/lib/Image/ExifTool/APE.pm +2 -2
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +25 -19
- package/bin/lib/Image/ExifTool/Canon.pm +33 -7
- package/bin/lib/Image/ExifTool/CanonRaw.pm +5 -1
- package/bin/lib/Image/ExifTool/DJI.pm +28 -2
- package/bin/lib/Image/ExifTool/Exif.pm +107 -20
- package/bin/lib/Image/ExifTool/FlashPix.pm +92 -9
- package/bin/lib/Image/ExifTool/FujiFilm.pm +9 -4
- package/bin/lib/Image/ExifTool/GPS.pm +7 -2
- package/bin/lib/Image/ExifTool/Geotag.pm +30 -7
- package/bin/lib/Image/ExifTool/InfiRay.pm +227 -0
- package/bin/lib/Image/ExifTool/JPEG.pm +53 -7
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +5 -5
- package/bin/lib/Image/ExifTool/LIF.pm +10 -2
- package/bin/lib/Image/ExifTool/LNK.pm +5 -4
- package/bin/lib/Image/ExifTool/MIE.pm +3 -3
- package/bin/lib/Image/ExifTool/MPEG.pm +2 -2
- package/bin/lib/Image/ExifTool/MakerNotes.pm +3 -2
- package/bin/lib/Image/ExifTool/Minolta.pm +6 -7
- package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -1
- package/bin/lib/Image/ExifTool/Nikon.pm +1199 -1325
- package/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
- package/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
- package/bin/lib/Image/ExifTool/Olympus.pm +88 -6
- package/bin/lib/Image/ExifTool/OpenEXR.pm +32 -15
- package/bin/lib/Image/ExifTool/PNG.pm +89 -3
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
- package/bin/lib/Image/ExifTool/Pentax.pm +8 -5
- package/bin/lib/Image/ExifTool/PhaseOne.pm +14 -1
- package/bin/lib/Image/ExifTool/Photoshop.pm +38 -7
- package/bin/lib/Image/ExifTool/QuickTime.pm +44 -13
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +63 -20
- package/bin/lib/Image/ExifTool/README +19 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +34 -13
- package/bin/lib/Image/ExifTool/Rawzor.pm +2 -2
- package/bin/lib/Image/ExifTool/Real.pm +2 -2
- package/bin/lib/Image/ExifTool/Ricoh.pm +2 -1
- package/bin/lib/Image/ExifTool/Sigma.pm +5 -4
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +9 -3
- package/bin/lib/Image/ExifTool/Sony.pm +28 -1
- package/bin/lib/Image/ExifTool/TagLookup.pm +4691 -4624
- package/bin/lib/Image/ExifTool/TagNames.pod +511 -117
- package/bin/lib/Image/ExifTool/VCard.pm +19 -5
- package/bin/lib/Image/ExifTool/Validate.pm +5 -5
- package/bin/lib/Image/ExifTool/WriteExif.pl +42 -0
- package/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
- package/bin/lib/Image/ExifTool/Writer.pl +150 -36
- package/bin/lib/Image/ExifTool/XMP.pm +19 -4
- package/bin/lib/Image/ExifTool/XMP2.pl +2 -1
- package/bin/lib/Image/ExifTool.pm +248 -54
- package/bin/lib/Image/ExifTool.pod +94 -58
- package/bin/perl-Image-ExifTool.spec +18 -18
- package/bin/pp_build_exe.args +7 -6
- package/package.json +3 -3
|
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
|
47
47
|
use Image::ExifTool::Exif;
|
|
48
48
|
use Image::ExifTool::GPS;
|
|
49
49
|
|
|
50
|
-
$VERSION = '2.
|
|
50
|
+
$VERSION = '2.84';
|
|
51
51
|
|
|
52
52
|
sub ProcessMOV($$;$);
|
|
53
53
|
sub ProcessKeys($$$);
|
|
@@ -419,6 +419,18 @@ my %channelLabel = (
|
|
|
419
419
|
0x1ffff => 'Discrete_65535',
|
|
420
420
|
);
|
|
421
421
|
|
|
422
|
+
my %qtFlags = ( #12
|
|
423
|
+
0 => 'undef', 22 => 'unsigned int', 71 => 'float[2] size',
|
|
424
|
+
1 => 'UTF-8', 23 => 'float', 72 => 'float[4] rect',
|
|
425
|
+
2 => 'UTF-16', 24 => 'double', 74 => 'int64s',
|
|
426
|
+
3 => 'ShiftJIS', 27 => 'BMP', 75 => 'int8u',
|
|
427
|
+
4 => 'UTF-8 sort', 28 => 'QT atom', 76 => 'int16u',
|
|
428
|
+
5 => 'UTF-16 sort', 65 => 'int8s', 77 => 'int32u',
|
|
429
|
+
13 => 'JPEG', 66 => 'int16s', 78 => 'int64u',
|
|
430
|
+
14 => 'PNG', 67 => 'int32s', 79 => 'double[3][3]',
|
|
431
|
+
21 => 'signed int', 70 => 'float[2] point',
|
|
432
|
+
);
|
|
433
|
+
|
|
422
434
|
# properties which don't get inherited from the parent
|
|
423
435
|
my %dontInherit = (
|
|
424
436
|
ispe => 1, # size of parent may be different
|
|
@@ -435,15 +447,16 @@ my %dupDirOK = ( ipco => 1, '----' => 1 );
|
|
|
435
447
|
my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl',
|
|
436
448
|
stsc => 'stbl', stts => 'stbl' );
|
|
437
449
|
|
|
450
|
+
# atoms required for generating ImageDataMD5
|
|
451
|
+
my %md5Box = ( vide => { %eeStd }, soun => { %eeStd } );
|
|
452
|
+
|
|
438
453
|
# boxes and their containers for the various handler types that we want to save
|
|
439
454
|
# when the ExtractEmbedded is enabled (currently only the 'gps ' container name is
|
|
440
455
|
# used, but others have been checked against all available sample files and may be
|
|
441
456
|
# useful in the future if the names are used for different boxes on other locations)
|
|
442
457
|
my %eeBox = (
|
|
443
458
|
# (note: vide is only processed if specific atoms exist in the VideoSampleDesc)
|
|
444
|
-
vide => { %eeStd,
|
|
445
|
-
JPEG => 'stsd',
|
|
446
|
-
},
|
|
459
|
+
vide => { %eeStd, JPEG => 'stsd' },
|
|
447
460
|
text => { %eeStd },
|
|
448
461
|
meta => { %eeStd },
|
|
449
462
|
sbtl => { %eeStd },
|
|
@@ -1159,7 +1172,10 @@ my %eeBox2 = (
|
|
|
1159
1172
|
},
|
|
1160
1173
|
{
|
|
1161
1174
|
Name => 'GarminGPS',
|
|
1162
|
-
Condition =>
|
|
1175
|
+
Condition => q{
|
|
1176
|
+
$$valPt=~/^\x9b\x63\x0f\x8d\x63\x74\x40\xec\x82\x04\xbc\x5f\xf5\x09\x17\x28/ and
|
|
1177
|
+
$$self{OPTIONS}{ExtractEmbedded}
|
|
1178
|
+
},
|
|
1163
1179
|
SubDirectory => {
|
|
1164
1180
|
TagTable => 'Image::ExifTool::QuickTime::Stream',
|
|
1165
1181
|
ProcessProc => \&ProcessGarminGPS,
|
|
@@ -1961,7 +1977,7 @@ my %eeBox2 = (
|
|
|
1961
1977
|
Name => 'SanyoMOV',
|
|
1962
1978
|
Condition => q{
|
|
1963
1979
|
$$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
|
|
1964
|
-
|
|
1980
|
+
$$self{FileType} eq "MOV"
|
|
1965
1981
|
},
|
|
1966
1982
|
SubDirectory => {
|
|
1967
1983
|
TagTable => 'Image::ExifTool::Sanyo::MOV',
|
|
@@ -1972,7 +1988,7 @@ my %eeBox2 = (
|
|
|
1972
1988
|
Name => 'SanyoMP4',
|
|
1973
1989
|
Condition => q{
|
|
1974
1990
|
$$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
|
|
1975
|
-
|
|
1991
|
+
$$self{FileType} eq "MP4"
|
|
1976
1992
|
},
|
|
1977
1993
|
SubDirectory => {
|
|
1978
1994
|
TagTable => 'Image::ExifTool::Sanyo::MP4',
|
|
@@ -7146,7 +7162,7 @@ my %eeBox2 = (
|
|
|
7146
7162
|
$$self{AudioFormat} = $val;
|
|
7147
7163
|
return undef unless $val =~ /^[\w ]{4}$/i;
|
|
7148
7164
|
# check for protected audio format
|
|
7149
|
-
$self->OverrideFileType('M4P') if $val eq 'drms' and $$self{
|
|
7165
|
+
$self->OverrideFileType('M4P') if $val eq 'drms' and $$self{FileType} eq 'M4A';
|
|
7150
7166
|
return $val;
|
|
7151
7167
|
},
|
|
7152
7168
|
# see this link for print conversions (not complete):
|
|
@@ -8768,6 +8784,16 @@ sub HandleItemInfo($)
|
|
|
8768
8784
|
$et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip;
|
|
8769
8785
|
}
|
|
8770
8786
|
}
|
|
8787
|
+
# do MD5 checksum of AVIF "av01" image data
|
|
8788
|
+
if ($type eq 'av01' and $$et{ImageDataMD5}) {
|
|
8789
|
+
my $md5 = $$et{ImageDataMD5};
|
|
8790
|
+
my $tot = 0;
|
|
8791
|
+
foreach $extent (@{$$item{Extents}}) {
|
|
8792
|
+
$raf->Seek($$extent[1] + $base, 0) or $et->Warn('Seek error in av01 image data'), last;
|
|
8793
|
+
$tot += $et->ImageDataMD5($raf, $$extent[2], 'av01 image', 1);
|
|
8794
|
+
}
|
|
8795
|
+
$et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $tot bytes of av01 data)\n") if $tot;
|
|
8796
|
+
}
|
|
8771
8797
|
next unless $name;
|
|
8772
8798
|
# assemble the data for this item
|
|
8773
8799
|
undef $buff;
|
|
@@ -9270,7 +9296,8 @@ sub ProcessMOV($$;$)
|
|
|
9270
9296
|
$$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
|
|
9271
9297
|
|
|
9272
9298
|
my $ee = $$et{OPTIONS}{ExtractEmbedded};
|
|
9273
|
-
|
|
9299
|
+
my $md5 = $$et{ImageDataMD5};
|
|
9300
|
+
if ($ee or $md5) {
|
|
9274
9301
|
$unkOpt = $$et{OPTIONS}{Unknown};
|
|
9275
9302
|
require 'Image/ExifTool/QuickTimeStream.pl';
|
|
9276
9303
|
}
|
|
@@ -9352,7 +9379,7 @@ sub ProcessMOV($$;$)
|
|
|
9352
9379
|
# set flag to store additional information for ExtractEmbedded option
|
|
9353
9380
|
my $handlerType = $$et{HandlerType};
|
|
9354
9381
|
if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) {
|
|
9355
|
-
if ($ee) {
|
|
9382
|
+
if ($ee or $md5) {
|
|
9356
9383
|
# (there is another 'gps ' box with a track log that doesn't contain offsets)
|
|
9357
9384
|
if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) {
|
|
9358
9385
|
$eeTag = 1;
|
|
@@ -9364,6 +9391,9 @@ sub ProcessMOV($$;$)
|
|
|
9364
9391
|
} elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) {
|
|
9365
9392
|
$eeTag = 1;
|
|
9366
9393
|
$$et{OPTIONS}{Unknown} = 1;
|
|
9394
|
+
} elsif ($md5 and $md5Box{$handlerType} and $md5Box{$handlerType}{$tag}) {
|
|
9395
|
+
$eeTag = 1;
|
|
9396
|
+
$$et{OPTIONS}{Unknown} = 1;
|
|
9367
9397
|
}
|
|
9368
9398
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
|
9369
9399
|
|
|
@@ -9596,7 +9626,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9596
9626
|
}
|
|
9597
9627
|
if ($tag eq 'stbl') {
|
|
9598
9628
|
# process sample data when exiting SampleTable box if extracting embedded
|
|
9599
|
-
ProcessSamples($et) if $ee;
|
|
9629
|
+
ProcessSamples($et) if $ee or $md5;
|
|
9600
9630
|
} elsif ($tag eq 'minf') {
|
|
9601
9631
|
$$et{HandlerType} = ''; # reset handler type at end of media info box
|
|
9602
9632
|
}
|
|
@@ -9656,6 +9686,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9656
9686
|
}
|
|
9657
9687
|
}
|
|
9658
9688
|
$langInfo or $langInfo = $tagInfo;
|
|
9689
|
+
my $str = $qtFlags{$flags} ? " ($qtFlags{$flags})" : '';
|
|
9659
9690
|
$et->VerboseInfo($tag, $langInfo,
|
|
9660
9691
|
Value => ref $value ? $$value : $value,
|
|
9661
9692
|
DataPt => \$val,
|
|
@@ -9664,7 +9695,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9664
9695
|
Size => $len,
|
|
9665
9696
|
Format => $format,
|
|
9666
9697
|
Index => $index,
|
|
9667
|
-
Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang),
|
|
9698
|
+
Extra => sprintf(", Type='${type}', Flags=0x%x%s, Lang=0x%.4x",$flags,$str,$lang),
|
|
9668
9699
|
) if $verbose;
|
|
9669
9700
|
# use "Keys" in path instead of ItemList if this was defined by a Keys tag
|
|
9670
9701
|
my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';
|
|
@@ -9793,7 +9824,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9793
9824
|
++$index if defined $index;
|
|
9794
9825
|
}
|
|
9795
9826
|
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
|
9796
|
-
if ($topLevel and $$et{
|
|
9827
|
+
if ($topLevel and $$et{FileType} and $$et{FileType} eq 'MP4' and
|
|
9797
9828
|
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
|
|
9798
9829
|
$$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
|
|
9799
9830
|
{
|
|
@@ -81,12 +81,15 @@ my %processByMetaFormat = (
|
|
|
81
81
|
ctbx => 1, # ('marl' in GM videos)
|
|
82
82
|
);
|
|
83
83
|
|
|
84
|
-
# data lengths for each INSV record type
|
|
84
|
+
# data lengths for each INSV/INSP record type
|
|
85
85
|
my %insvDataLen = (
|
|
86
|
+
0x200 => 0, # PreivewImage (any size) (a duplicate of PreviewImage in APP2 of INSP files)
|
|
86
87
|
0x300 => 0, # accelerometer (could be either 20 or 56 bytes)
|
|
87
88
|
0x400 => 16, # exposure (ref 6)
|
|
88
89
|
0x600 => 8, # timestamps (ref 6)
|
|
89
90
|
0x700 => 53, # GPS
|
|
91
|
+
# 0x900 => 48, # ? (Insta360 X3)
|
|
92
|
+
# 0xb00 => 10, # ? (Insta360 X3)
|
|
90
93
|
);
|
|
91
94
|
|
|
92
95
|
# limit the default amount of data we read for some record types
|
|
@@ -596,6 +599,8 @@ my %insvLimit = (
|
|
|
596
599
|
0x1a => 'Firmware',
|
|
597
600
|
0x2a => {
|
|
598
601
|
Name => 'Parameters',
|
|
602
|
+
# (see https://exiftool.org/forum/index.php?msg=78942)
|
|
603
|
+
Notes => 'number of lenses, 6-axis orientation of each lens, raw resolution',
|
|
599
604
|
ValueConv => '$val =~ tr/_/ /; $val',
|
|
600
605
|
},
|
|
601
606
|
);
|
|
@@ -1122,23 +1127,37 @@ sub Process_text($$$;$)
|
|
|
1122
1127
|
# Inputs: 0) ExifTool ref
|
|
1123
1128
|
# Notes: Also accesses ExifTool RAF*, SET_GROUP1, HandlerType, MetaFormat,
|
|
1124
1129
|
# ee*, and avcC elements (* = must exist)
|
|
1130
|
+
# - may be called either due to ExtractEmbedded option, or ImageDataMD5 requested
|
|
1131
|
+
# - MD5 includes only video and audio data
|
|
1125
1132
|
sub ProcessSamples($)
|
|
1126
1133
|
{
|
|
1127
1134
|
my $et = shift;
|
|
1128
1135
|
my ($raf, $ee) = @$et{qw(RAF ee)};
|
|
1129
|
-
my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent);
|
|
1136
|
+
my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent, $md5);
|
|
1130
1137
|
|
|
1131
1138
|
return unless $ee;
|
|
1132
1139
|
delete $$et{ee}; # use only once
|
|
1133
1140
|
|
|
1134
|
-
|
|
1141
|
+
my $eeOpt = $et->Options('ExtractEmbedded');
|
|
1135
1142
|
my $type = $$et{HandlerType} || '';
|
|
1136
1143
|
if ($type eq 'vide') {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1144
|
+
# only process specific types of video streams
|
|
1145
|
+
$md5 = $$et{ImageDataMD5};
|
|
1146
|
+
# only process specific video types if ExtractEmbedded was used
|
|
1147
|
+
# (otherwise we are only here to calculate the audio/video MD5)
|
|
1148
|
+
if ($eeOpt) {
|
|
1149
|
+
if ($$ee{avcC}) { $type = 'avcC' }
|
|
1150
|
+
elsif ($$ee{JPEG}) { $type = 'JPEG' }
|
|
1151
|
+
else { return unless $md5 }
|
|
1152
|
+
}
|
|
1153
|
+
} elsif ($type eq 'soun') {
|
|
1154
|
+
$md5 = $$et{ImageDataMD5};
|
|
1155
|
+
return unless $md5;
|
|
1156
|
+
} else {
|
|
1157
|
+
return unless $eeOpt; # (don't do MD5 on other types)
|
|
1140
1158
|
}
|
|
1141
1159
|
|
|
1160
|
+
my $md5size = 0;
|
|
1142
1161
|
my ($start, $size) = @$ee{qw(start size)};
|
|
1143
1162
|
#
|
|
1144
1163
|
# determine sample start offsets from chunk offsets (stco) and sample-to-chunk table (stsc),
|
|
@@ -1157,13 +1176,16 @@ sub ProcessSamples($)
|
|
|
1157
1176
|
$timeDelta = shift @$stts;
|
|
1158
1177
|
}
|
|
1159
1178
|
my $ts = $$et{MediaTS} || 1;
|
|
1179
|
+
my @chunkSize; # total size of each chunk
|
|
1160
1180
|
foreach $chunkStart (@$stco) {
|
|
1161
1181
|
if ($iChunk >= $nextChunk and @$stsc) {
|
|
1162
1182
|
($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc};
|
|
1163
1183
|
$nextChunk = $$stsc[0][0] if @$stsc;
|
|
1164
1184
|
}
|
|
1165
1185
|
@$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), last;
|
|
1186
|
+
last unless defined $chunkStart and length $chunkStart;
|
|
1166
1187
|
my $sampleStart = $chunkStart;
|
|
1188
|
+
my $chunkSize = 0;
|
|
1167
1189
|
Sample: for ($i=0; ; ) {
|
|
1168
1190
|
push @$start, $sampleStart;
|
|
1169
1191
|
if (defined $time) {
|
|
@@ -1181,12 +1203,19 @@ Sample: for ($i=0; ; ) {
|
|
|
1181
1203
|
--$timeCount;
|
|
1182
1204
|
}
|
|
1183
1205
|
# (eventually should use the description indices: $descIdx)
|
|
1206
|
+
$chunkSize += $$size[$#$start];
|
|
1184
1207
|
last if ++$i >= $samplesPerChunk;
|
|
1185
1208
|
$sampleStart += $$size[$#$start];
|
|
1186
1209
|
}
|
|
1210
|
+
push @chunkSize, $chunkSize;
|
|
1187
1211
|
++$iChunk;
|
|
1188
1212
|
}
|
|
1189
1213
|
@$start == @$size or $et->WarnOnce('Incorrect sample start/size count'), return;
|
|
1214
|
+
# process as chunks if we are only interested in calculating MD5
|
|
1215
|
+
if ($type eq 'soun' or $type eq 'vide') {
|
|
1216
|
+
$start = $stco;
|
|
1217
|
+
$size = \@chunkSize;
|
|
1218
|
+
}
|
|
1190
1219
|
}
|
|
1191
1220
|
#
|
|
1192
1221
|
# extract and parse the sample data
|
|
@@ -1218,6 +1247,10 @@ Sample: for ($i=0; ; ) {
|
|
|
1218
1247
|
my $size = $$size[$i];
|
|
1219
1248
|
next unless $raf->Seek($$start[$i], 0) and $raf->Read($buff, $size) == $size;
|
|
1220
1249
|
|
|
1250
|
+
if ($md5) {
|
|
1251
|
+
$md5->add($buff);
|
|
1252
|
+
$md5size += length $buff;
|
|
1253
|
+
}
|
|
1221
1254
|
if ($type eq 'avcC') {
|
|
1222
1255
|
next if length($buff) <= $hdrLen;
|
|
1223
1256
|
# scan through all NAL units and send them to ParseH264Video()
|
|
@@ -1344,6 +1377,8 @@ Sample: for ($i=0; ; ) {
|
|
|
1344
1377
|
SetGPSDateTime($et, $tagTbl, $time[$i]) if $$et{FoundGPSLatitude} and not $$et{FoundGPSDateTime};
|
|
1345
1378
|
}
|
|
1346
1379
|
if ($verbose) {
|
|
1380
|
+
my $str = $type eq 'soun' ? 'Audio' : 'Video';
|
|
1381
|
+
$et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $md5size bytes of $str data)\n") if $md5size;
|
|
1347
1382
|
$$et{INDENT} = $oldIndent;
|
|
1348
1383
|
$et->VPrint(0, "--------------------------\n");
|
|
1349
1384
|
}
|
|
@@ -1485,7 +1520,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1485
1520
|
# Kenwood dashcam sometimes stores absolute year and local time
|
|
1486
1521
|
# (but sometimes year since 2000 and UTC time in same video!)
|
|
1487
1522
|
require Time::Local;
|
|
1488
|
-
my $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$yr
|
|
1523
|
+
my $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$yr);
|
|
1489
1524
|
($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
|
|
1490
1525
|
$yr += 1900;
|
|
1491
1526
|
++$mon;
|
|
@@ -2758,7 +2793,6 @@ sub ProcessInsta360($;$)
|
|
|
2758
2793
|
my ($id, $len) = unpack('vV', $buff);
|
|
2759
2794
|
($epos -= $len) + $trailerLen < 0 and last;
|
|
2760
2795
|
$raf->Seek($epos, 2) or last;
|
|
2761
|
-
my $dlen = $insvDataLen{$id};
|
|
2762
2796
|
if ($verbose) {
|
|
2763
2797
|
$et->VPrint(0, sprintf("Insta360 Record 0x%x (offset 0x%x, %d bytes):\n", $id, $fileEnd + $epos, $len));
|
|
2764
2798
|
}
|
|
@@ -2771,20 +2805,25 @@ sub ProcessInsta360($;$)
|
|
|
2771
2805
|
# 2. 20 byte records
|
|
2772
2806
|
# 0000: c1 d8 d9 0b 00 00 00 00 f5 83 14 80 df 7f fe 7f [................]
|
|
2773
2807
|
# 0010: fe 7f 01 80
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2808
|
+
my $dlen = $insvDataLen{$id};
|
|
2809
|
+
if (defined $dlen and not $dlen) {
|
|
2810
|
+
if ($id == 0x300) {
|
|
2811
|
+
if ($len % 20 and not $len % 56) {
|
|
2812
|
+
$dlen = 56;
|
|
2813
|
+
} elsif ($len % 56 and not $len % 20) {
|
|
2814
|
+
$dlen = 20;
|
|
2815
|
+
} else {
|
|
2816
|
+
if ($raf->Read($buff, 20) == 20) {
|
|
2817
|
+
if (substr($buff, 16, 3) eq "\0\0\0") {
|
|
2818
|
+
$dlen = 56;
|
|
2819
|
+
} else {
|
|
2820
|
+
$dlen = 20;
|
|
2821
|
+
}
|
|
2785
2822
|
}
|
|
2823
|
+
$raf->Seek($epos, 2) or last;
|
|
2786
2824
|
}
|
|
2787
|
-
|
|
2825
|
+
} elsif ($id == 0x200) {
|
|
2826
|
+
$dlen = $len;
|
|
2788
2827
|
}
|
|
2789
2828
|
}
|
|
2790
2829
|
# limit the number of records we read if necessary
|
|
@@ -2798,6 +2837,8 @@ sub ProcessInsta360($;$)
|
|
|
2798
2837
|
if ($dlen) {
|
|
2799
2838
|
if ($len % $dlen) {
|
|
2800
2839
|
$et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
|
|
2840
|
+
} elsif ($id == 0x200) {
|
|
2841
|
+
$et->FoundTag(PreviewImage => $buff);
|
|
2801
2842
|
} elsif ($id == 0x300) {
|
|
2802
2843
|
for ($p=0; $p<$len; $p+=$dlen) {
|
|
2803
2844
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
@@ -2915,6 +2956,7 @@ sub ProcessGarminGPS($$$)
|
|
|
2915
2956
|
my $epoch = (66 * 365 + 17) * 24 * 3600; # time is relative to Jan 1, 1904
|
|
2916
2957
|
my $scl = 180 / (32768 * 65536); # scaling factor for lat/lon
|
|
2917
2958
|
$et->VerboseDir('GarminGPS');
|
|
2959
|
+
$$et{SET_GROUP1} = 'Garmin';
|
|
2918
2960
|
while ($pos + 20 <= $dataLen) {
|
|
2919
2961
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
2920
2962
|
my $time = Image::ExifTool::ConvertUnixTime(Get32u($dataPt, $pos) - $epoch) . 'Z';
|
|
@@ -2929,6 +2971,7 @@ sub ProcessGarminGPS($$$)
|
|
|
2929
2971
|
$pos += 20;
|
|
2930
2972
|
}
|
|
2931
2973
|
delete $$et{DOC_NUM};
|
|
2974
|
+
delete $$et{SET_GROUP1};
|
|
2932
2975
|
return 1;
|
|
2933
2976
|
}
|
|
2934
2977
|
|
|
@@ -249,6 +249,13 @@ key:
|
|
|
249
249
|
within this atom. Currently used only for Canon CNTH atom,
|
|
250
250
|
which contains garbage after the first contained atom.
|
|
251
251
|
|
|
252
|
+
NIKON_OFFSETS [Nikon Encrypted tables only] Pointer to int32u NumberOffsets
|
|
253
|
+
for offset-type encrypted Nikon directories. When set,
|
|
254
|
+
directory and decryption lengths are calculated automatically.
|
|
255
|
+
|
|
256
|
+
ALLOW_REPROCESS Flag to allow reprocessing of another directory at this
|
|
257
|
+
same location in the file, bypassing recursion avoidance test.
|
|
258
|
+
|
|
252
259
|
DATAMEMBER : BinaryData tables only. A reference to a list of sorted tag ID's
|
|
253
260
|
which must be extracted as data members when writing. Must also list "var_"
|
|
254
261
|
format tags and tags with Hook so offsets are properly calculated if the table
|
|
@@ -404,6 +411,10 @@ numerical, and generated automatically otherwise.
|
|
|
404
411
|
|
|
405
412
|
'IsComposite' - flag set for Composite tags
|
|
406
413
|
|
|
414
|
+
'IsImageData' - flag set if this is an image data offset to
|
|
415
|
+
be included in ImageDataMD5 calculation. Must have an
|
|
416
|
+
OffsetPair entry which is the ID of the corresponding size.
|
|
417
|
+
|
|
407
418
|
'IsOffset' - flag set if the tag represents an offset to some
|
|
408
419
|
data, and causes value will be adjusted to an absolute file
|
|
409
420
|
offset. If set to 2, the offset base of the parent directory
|
|
@@ -465,6 +476,10 @@ numerical, and generated automatically otherwise.
|
|
|
465
476
|
documentation, padded to the number of digits given by the
|
|
466
477
|
PrintHex value.
|
|
467
478
|
|
|
479
|
+
'PrintInt' - remove decimal part of tag ID in HTML tag name
|
|
480
|
+
documentation. (To avoid confusing ExifTool users because
|
|
481
|
+
the LensType decimal numbers are for internal use only.)
|
|
482
|
+
|
|
468
483
|
'PrintSort' - causes PrintConv values to be sorted by value
|
|
469
484
|
rather than key in the HTML tag name documentation.
|
|
470
485
|
|
|
@@ -713,7 +728,7 @@ numerical, and generated automatically otherwise.
|
|
|
713
728
|
BitShift are applied before evaluating RawConv.
|
|
714
729
|
|
|
715
730
|
BitShift : [Mask tags only] Bit shift for Mask-ed values. If not
|
|
716
|
-
specified, set to the number of trailing bits in
|
|
731
|
+
specified, set to the number of trailing zero bits in Mask.
|
|
717
732
|
When reading, the value is shifted right by this number of
|
|
718
733
|
bits after the Mask is applied.
|
|
719
734
|
|
|
@@ -1003,7 +1018,9 @@ numerical, and generated automatically otherwise.
|
|
|
1003
1018
|
current Base. This is a Perl expression which may use
|
|
1004
1019
|
$valuePtr to represent the location of the tag value in the
|
|
1005
1020
|
file, or $val for the value itself. If not specified, a Start
|
|
1006
|
-
of '$valuePtr' is assumed.
|
|
1021
|
+
of '$valuePtr' is assumed. Subdirectories in BinaryData may
|
|
1022
|
+
also use $dirStart to represent the offset of the current
|
|
1023
|
+
directory start relative to the start of the data block.
|
|
1007
1024
|
|
|
1008
1025
|
OffsetPt : [EXIF directories only] If specified, this is a Perl
|
|
1009
1026
|
expression that gives the position of a 32-bit word in the
|
|
@@ -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.64';
|
|
34
34
|
|
|
35
35
|
sub ConvertTimecode($);
|
|
36
36
|
sub ProcessSGLT($$$);
|
|
@@ -38,6 +38,13 @@ sub ProcessSLLT($$$);
|
|
|
38
38
|
sub ProcessLucas($$$);
|
|
39
39
|
sub WriteRIFF($$);
|
|
40
40
|
|
|
41
|
+
# RIFF chunks containing image data (to include in ImageDataMD5 digest)
|
|
42
|
+
my %isImageData = (
|
|
43
|
+
LIST_movi => 1, # (AVI: contains ##db, ##dc, ##wb)
|
|
44
|
+
data => 1, # (WAV)
|
|
45
|
+
'VP8 '=>1, VP8L=>1, ANIM=>1, ANMF=>1, ALPH=>1, # (WebP)
|
|
46
|
+
);
|
|
47
|
+
|
|
41
48
|
# recognized RIFF variants
|
|
42
49
|
my %riffType = (
|
|
43
50
|
'WAVE' => 'WAV', 'AVI ' => 'AVI', 'WEBP' => 'WEBP',
|
|
@@ -1522,7 +1529,7 @@ my %code2charset = (
|
|
|
1522
1529
|
},
|
|
1523
1530
|
# (can't calculate duration like this for compressed audio types)
|
|
1524
1531
|
RawConv => q{
|
|
1525
|
-
return undef if $$self{
|
|
1532
|
+
return undef if $$self{FileType} =~ /^(LA|OFR|PAC|WV)$/;
|
|
1526
1533
|
return(($val[0] and not ($val[2] or $val[3])) ? $val[1] / $val[0] : undef);
|
|
1527
1534
|
},
|
|
1528
1535
|
PrintConv => 'ConvertDuration($val)',
|
|
@@ -1980,6 +1987,7 @@ sub ProcessRIFF($$)
|
|
|
1980
1987
|
my $unknown = $et->Options('Unknown');
|
|
1981
1988
|
my $validate = $et->Options('Validate');
|
|
1982
1989
|
my $ee = $et->Options('ExtractEmbedded');
|
|
1990
|
+
my $md5 = $$et{ImageDataMD5};
|
|
1983
1991
|
|
|
1984
1992
|
# verify this is a valid RIFF file
|
|
1985
1993
|
return 0 unless $raf->Read($buff, 12) == 12;
|
|
@@ -1996,7 +2004,7 @@ sub ProcessRIFF($$)
|
|
|
1996
2004
|
$$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode
|
|
1997
2005
|
$mime = $riffMimeType{$type} if $type;
|
|
1998
2006
|
$et->SetFileType($type, $mime);
|
|
1999
|
-
$$et{VALUE}{FileType} .= ' (RF64)' if $rf64;
|
|
2007
|
+
$$et{VALUE}{FileType} .= ' (RF64)' if $rf64 and $$et{VALUE}{FileType};
|
|
2000
2008
|
$$et{RIFFStreamType} = ''; # initialize stream type
|
|
2001
2009
|
$$et{RIFFStreamCodec} = []; # initialize codec array
|
|
2002
2010
|
SetByteOrder('II');
|
|
@@ -2059,6 +2067,10 @@ sub ProcessRIFF($$)
|
|
|
2059
2067
|
# (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
|
|
2060
2068
|
if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
|
|
2061
2069
|
$raf->Read($buff, $len2) == $len2 or $err=1, last;
|
|
2070
|
+
if ($md5 and $isImageData{$tag}) {
|
|
2071
|
+
$md5->add($buff);
|
|
2072
|
+
$et->VPrint(0, "$$et{INDENT}(ImageDataMD5: '${tag}' chunk, $len2 bytes)\n");
|
|
2073
|
+
}
|
|
2062
2074
|
my $setGroups;
|
|
2063
2075
|
if ($tagInfo and ref $tagInfo eq 'HASH' and $$tagInfo{SetGroups}) {
|
|
2064
2076
|
$setGroups = $$et{SET_GROUP0} = $$et{SET_GROUP1} = $$tagInfo{SetGroups};
|
|
@@ -2085,18 +2097,27 @@ sub ProcessRIFF($$)
|
|
|
2085
2097
|
# extract information from remaining file as an embedded file
|
|
2086
2098
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
2087
2099
|
next; # (must not increment $pos)
|
|
2088
|
-
} elsif ($tag eq 'LIST_movi' and $ee) {
|
|
2089
|
-
next; # parse into movi chunk
|
|
2090
2100
|
} else {
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2101
|
+
my $rewind;
|
|
2102
|
+
# do MD5 if required
|
|
2103
|
+
if ($md5 and $isImageData{$tag}) {
|
|
2104
|
+
$rewind = $raf->Tell();
|
|
2105
|
+
$et->ImageDataMD5($raf, $len2, "'${tag}' chunk");
|
|
2094
2106
|
}
|
|
2095
|
-
if ($
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2107
|
+
if ($tag eq 'LIST_movi' and $ee) {
|
|
2108
|
+
$raf->Seek($rewind, 0) or $err = 1, last if $rewind;
|
|
2109
|
+
next; # parse into movi chunk
|
|
2110
|
+
} elsif (not $rewind) {
|
|
2111
|
+
if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
|
|
2112
|
+
$et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
|
|
2113
|
+
last;
|
|
2114
|
+
}
|
|
2115
|
+
if ($validate and $len2) {
|
|
2116
|
+
# (must actually try to read something after seeking to detect error)
|
|
2117
|
+
$raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, last;
|
|
2118
|
+
} else {
|
|
2119
|
+
$raf->Seek($len2, 1) or $err=1, last;
|
|
2120
|
+
}
|
|
2100
2121
|
}
|
|
2101
2122
|
}
|
|
2102
2123
|
$pos += $len2;
|
|
@@ -14,7 +14,7 @@ use strict;
|
|
|
14
14
|
use vars qw($VERSION);
|
|
15
15
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
16
16
|
|
|
17
|
-
$VERSION = '1.
|
|
17
|
+
$VERSION = '1.06';
|
|
18
18
|
|
|
19
19
|
# currently support this version Rawzor images
|
|
20
20
|
my $implementedRawzorVersion = 199; # (up to version 1.99)
|
|
@@ -138,7 +138,7 @@ sub ProcessRWZ($$)
|
|
|
138
138
|
}
|
|
139
139
|
# set OriginalFileType from FileType of original file
|
|
140
140
|
# then change FileType and MIMEType to indicate a Rawzor image
|
|
141
|
-
my $origFileType = $$et{
|
|
141
|
+
my $origFileType = $$et{FileType};
|
|
142
142
|
if ($origFileType) {
|
|
143
143
|
$et->HandleTag($tagTablePtr, OriginalFileType => $origFileType);
|
|
144
144
|
$et->OverrideFileType('RWZ');
|
|
@@ -16,7 +16,7 @@ use vars qw($VERSION);
|
|
|
16
16
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
17
17
|
use Image::ExifTool::Canon;
|
|
18
18
|
|
|
19
|
-
$VERSION = '1.
|
|
19
|
+
$VERSION = '1.07';
|
|
20
20
|
|
|
21
21
|
sub ProcessRealMeta($$$);
|
|
22
22
|
sub ProcessRealProperties($$$);
|
|
@@ -608,7 +608,7 @@ sub ProcessReal($$)
|
|
|
608
608
|
} else {
|
|
609
609
|
last if $tag eq 'DATA'; # stop normal parsing at DATA tag
|
|
610
610
|
}
|
|
611
|
-
if ($size & 0x80000000) {
|
|
611
|
+
if ($size & 0x80000000 or $size < 10) {
|
|
612
612
|
$et->Warn('Bad chunk header');
|
|
613
613
|
last;
|
|
614
614
|
}
|
|
@@ -19,7 +19,7 @@ use vars qw($VERSION);
|
|
|
19
19
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
20
20
|
use Image::ExifTool::Exif;
|
|
21
21
|
|
|
22
|
-
$VERSION = '1.
|
|
22
|
+
$VERSION = '1.36';
|
|
23
23
|
|
|
24
24
|
sub ProcessRicohText($$$);
|
|
25
25
|
sub ProcessRicohRMETA($$$);
|
|
@@ -949,6 +949,7 @@ sub ProcessRicohText($$$)
|
|
|
949
949
|
|
|
950
950
|
my $data = substr($$dataPt, $dirStart, $dirLen);
|
|
951
951
|
return 1 if $data =~ /^\0/; # blank Ricoh maker notes
|
|
952
|
+
$et->VerboseDir('RicohText', undef, $dirLen);
|
|
952
953
|
# validate text maker notes
|
|
953
954
|
unless ($data =~ /^(Rev|Rv)/) {
|
|
954
955
|
$et->Warn('Bad Ricoh maker notes');
|
|
@@ -19,15 +19,13 @@ use strict;
|
|
|
19
19
|
use vars qw($VERSION %sigmaLensTypes);
|
|
20
20
|
use Image::ExifTool::Exif;
|
|
21
21
|
|
|
22
|
-
$VERSION = '1.
|
|
22
|
+
$VERSION = '1.34';
|
|
23
23
|
|
|
24
24
|
# sigma LensType lookup (ref IB)
|
|
25
25
|
%sigmaLensTypes = (
|
|
26
26
|
Notes => q{
|
|
27
27
|
Sigma LensType values are hexadecimal numbers stored as a string (without
|
|
28
|
-
the leading "0x").
|
|
29
|
-
which would otherwise have the same LensType, and are used by the Composite
|
|
30
|
-
LensID tag when attempting to identify the specific lens model.
|
|
28
|
+
the leading "0x").
|
|
31
29
|
},
|
|
32
30
|
# 0x0 => 'Sigma 50mm F2.8 EX Macro', (0x0 used for other lenses too)
|
|
33
31
|
# 0x8 - 18-125mm LENSARANGE@18mm=22-4
|
|
@@ -255,6 +253,7 @@ $VERSION = '1.32';
|
|
|
255
253
|
0x6023 => 'Sigma 20mm F2 DG DN | C', #IB
|
|
256
254
|
0x6025 => 'Sigma 20mm F1.4 DG DN | A', #IB
|
|
257
255
|
0x6026 => 'Sigma 24mm F1.4 DG DN | A', #IB
|
|
256
|
+
0x602c => "Sigma 50mm F1.4 DG DN | A (2023)", #IB
|
|
258
257
|
0x8005 => 'Sigma 35mm F1.4 DG HSM | A', #PH (012)
|
|
259
258
|
0x8009 => 'Sigma 18-35mm F1.8 DC HSM | A', #PH
|
|
260
259
|
0x8900 => 'Sigma 70-300mm F4-5.6 DG OS', #PH (SD15)
|
|
@@ -556,6 +555,7 @@ $VERSION = '1.32';
|
|
|
556
555
|
SeparateTable => 'LensType',
|
|
557
556
|
PrintHex => 1,
|
|
558
557
|
PrintConv => \%sigmaLensTypes,
|
|
558
|
+
PrintInt => 1,
|
|
559
559
|
},{ #PH
|
|
560
560
|
Name => 'LensType',
|
|
561
561
|
Condition => '$$self{MakerNoteSigmaVer} >= 3',
|
|
@@ -564,6 +564,7 @@ $VERSION = '1.32';
|
|
|
564
564
|
SeparateTable => 'LensType',
|
|
565
565
|
PrintHex => 1,
|
|
566
566
|
PrintConv => \%sigmaLensTypes,
|
|
567
|
+
PrintInt => 1,
|
|
567
568
|
}],
|
|
568
569
|
0x002a => { #PH
|
|
569
570
|
Name => 'LensFocalRange',
|
|
@@ -16,7 +16,7 @@ use vars qw($VERSION);
|
|
|
16
16
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
17
17
|
use Image::ExifTool::Sigma;
|
|
18
18
|
|
|
19
|
-
$VERSION = '1.
|
|
19
|
+
$VERSION = '1.30';
|
|
20
20
|
|
|
21
21
|
sub ProcessX3FHeader($$$);
|
|
22
22
|
sub ProcessX3FDirectory($$$);
|
|
@@ -545,10 +545,16 @@ sub ProcessX3FDirectory($$$)
|
|
|
545
545
|
if ($$tagInfo{Name} eq 'PreviewImage') {
|
|
546
546
|
# check image header to see if this is a JPEG preview image
|
|
547
547
|
$raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header';
|
|
548
|
-
# ignore all image data but JPEG compressed (version 2.0, type 2, format 18)
|
|
549
|
-
next unless $buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/;
|
|
550
548
|
$offset += 28;
|
|
551
549
|
$len -= 28;
|
|
550
|
+
# ignore all image data but JPEG compressed (version 2.0, type 2, format 18)
|
|
551
|
+
unless ($buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/) {
|
|
552
|
+
# do MD5 on non-preview data if requested
|
|
553
|
+
if ($$et{ImageDataMD5} and substr($buff,8,1) ne "\x02") {
|
|
554
|
+
$et->ImageDataMD5($raf, $len, 'SigmaRaw IMAG');
|
|
555
|
+
}
|
|
556
|
+
next;
|
|
557
|
+
}
|
|
552
558
|
$raf->Read($buff, $len) == $len or return "Error reading PreviewImage data";
|
|
553
559
|
# check fore EXIF segment, and extract this image as the JpgFromRaw
|
|
554
560
|
if ($buff =~ /^\xff\xd8\xff\xe1/) {
|