exiftool_vendored 12.86.0 → 12.89.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +59 -1
  3. data/bin/MANIFEST +1 -0
  4. data/bin/META.json +2 -2
  5. data/bin/META.yml +17 -17
  6. data/bin/README +3 -2
  7. data/bin/build_geolocation +6 -3
  8. data/bin/config_files/onone.config +28 -0
  9. data/bin/exiftool +20 -12
  10. data/bin/lib/Image/ExifTool/AIFF.pm +8 -4
  11. data/bin/lib/Image/ExifTool/ASF.pm +4 -1
  12. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +12 -7
  13. data/bin/lib/Image/ExifTool/Canon.pm +63 -4
  14. data/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  15. data/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +46 -4
  17. data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  18. data/bin/lib/Image/ExifTool/Geolocation.pm +6 -0
  19. data/bin/lib/Image/ExifTool/InDesign.pm +8 -4
  20. data/bin/lib/Image/ExifTool/Jpeg2000.pm +0 -1
  21. data/bin/lib/Image/ExifTool/Lang/de.pm +2 -2
  22. data/bin/lib/Image/ExifTool/Matroska.pm +66 -10
  23. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
  24. data/bin/lib/Image/ExifTool/Nikon.pm +3 -2
  25. data/bin/lib/Image/ExifTool/Panasonic.pm +1 -0
  26. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
  27. data/bin/lib/Image/ExifTool/Pentax.pm +80 -14
  28. data/bin/lib/Image/ExifTool/QuickTime.pm +45 -8
  29. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +24 -2
  30. data/bin/lib/Image/ExifTool/RIFF.pm +20 -10
  31. data/bin/lib/Image/ExifTool/Sony.pm +21 -11
  32. data/bin/lib/Image/ExifTool/TagLookup.pm +6800 -6784
  33. data/bin/lib/Image/ExifTool/TagNames.pod +83 -16
  34. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +84 -15
  35. data/bin/lib/Image/ExifTool/Writer.pl +7 -4
  36. data/bin/lib/Image/ExifTool/XMP.pm +8 -8
  37. data/bin/lib/Image/ExifTool/XMP2.pl +51 -30
  38. data/bin/lib/Image/ExifTool/ZIP.pm +8 -4
  39. data/bin/lib/Image/ExifTool.pm +22 -16
  40. data/bin/lib/Image/ExifTool.pod +15 -6
  41. data/bin/perl-Image-ExifTool.spec +1 -1
  42. data/lib/exiftool_vendored/version.rb +1 -1
  43. metadata +3 -2
@@ -31,7 +31,7 @@ use vars qw($VERSION);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
  use Image::ExifTool::Exif;
33
33
 
34
- $VERSION = '1.94';
34
+ $VERSION = '1.95';
35
35
 
36
36
  sub ProcessFujiDir($$$);
37
37
  sub ProcessFaceRec($$$);
@@ -1169,6 +1169,46 @@ my %faceCategories = (
1169
1169
  Face8Birthday => { },
1170
1170
  );
1171
1171
 
1172
+ # tags extracted from RAF header
1173
+ %Image::ExifTool::FujiFilm::RAFHeader = (
1174
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1175
+ GROUPS => { 0 => 'RAF', 1 => 'RAF', 2 => 'Image' },
1176
+ NOTES => 'Tags extracted from the header of RAF images.',
1177
+ # 0x00 - eg. "FUJIFILMCCD-RAW 0201FA392001FinePix S3Pro"
1178
+ 0x3c => { #PH
1179
+ Name => 'RAFVersion',
1180
+ Format => 'undef[4]',
1181
+ },
1182
+ # (all int32u values)
1183
+ # 0x40 - 1 for M-RAW, 0 otherwise?
1184
+ # 0x44 - high word of M-RAW offset? (only seen zero)
1185
+ # 0x48 - M-RAW header offset
1186
+ # 0x4c - M-RAW header length
1187
+ # 0x50 - ? (only seen zero)
1188
+ # 0x54 - JPEG offset
1189
+ # 0x58 - JPEG length
1190
+ # 0x5c - RAF directory offset
1191
+ # 0x60 - RAF directory length
1192
+ # 0x64 - FujiIFD dir offset
1193
+ # 0x68 - FujiIFD dir length
1194
+ # 0x6c - RAFCompression or JPEG start
1195
+ 0x6c => { #10
1196
+ Name => 'RAFCompression',
1197
+ Condition => '$$valPt =~ /^\0\0\0/', # (JPEG header is in this location for some RAF versions)
1198
+ Format => 'int32u',
1199
+ PrintConv => { 0 => 'Uncompressed', 2 => 'Lossless', 3 => 'Lossy' },
1200
+ },
1201
+ # 0x70 - ? same as 0x68?
1202
+ # 0x74 - ? usually 0, but have seen 0x1700
1203
+ # 0x78 - RAF1 dir offset
1204
+ # 0x7c - RAF1 dir length
1205
+ # 0x80 - FujiIFD1 dir offset
1206
+ # 0x84 - FujiIFD1 dir length
1207
+ # 0x88-0x8c - always zero?
1208
+ # 0x90 - ? same as 0x74?
1209
+ # 0x94 - JPEG or M-RAW start
1210
+ );
1211
+
1172
1212
  # tags in RAF images (ref 5)
1173
1213
  %Image::ExifTool::FujiFilm::RAF = (
1174
1214
  PROCESS_PROC => \&ProcessFujiDir,
@@ -1797,7 +1837,7 @@ sub ProcessRAF($$)
1797
1837
  my ($buff, $jpeg, $warn, $offset);
1798
1838
 
1799
1839
  my $raf = $$dirInfo{RAF};
1800
- $raf->Read($buff,0x5c) == 0x5c or return 0;
1840
+ $raf->Read($buff,0x70) == 0x70 or return 0;
1801
1841
  $buff =~ /^FUJIFILM/ or return 0;
1802
1842
  # get position and size of M-RAW header and jpeg preview
1803
1843
  my ($mpos, $mlen) = unpack('x72NN', $buff);
@@ -1807,9 +1847,11 @@ sub ProcessRAF($$)
1807
1847
  $raf->Seek($jpos, 0) or return 0;
1808
1848
  $raf->Read($jpeg, $jlen) == $jlen or return 0;
1809
1849
  }
1850
+ SetByteOrder('MM');
1810
1851
  $et->SetFileType();
1811
- $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
1812
-
1852
+ my $tbl = GetTagTable('Image::ExifTool::FujiFilm::RAFHeader');
1853
+ $et->ProcessDirectory({ DataPt => \$buff, DirName => 'RAFHeader' }, $tbl);
1854
+
1813
1855
  # extract information from embedded JPEG
1814
1856
  my %dirInfo = (
1815
1857
  Parent => 'RAF',
Binary file
@@ -509,6 +509,12 @@ sub Geolocate($;$)
509
509
  $city = '' unless defined $city;
510
510
  } elsif (/^[-+]?\d+(\.\d+)?$/) { # coordinate format
511
511
  push @coords, $_ if @coords < 2;
512
+ } elsif (/^([-+]?\d+(?:\.\d+)?) *(([NS])[A-Z]*)? +([-+]?\d+(?:\.\d+)?) *(([EW])[A-Z]*)?/i) { # "lat lon" format
513
+ next if @coords;
514
+ my ($lat, $lon) = ($1, $4);
515
+ $lat = -abs($lat) if $3 and uc($3) eq 'S';
516
+ $lon = -abs($lon) if $6 and uc($6) eq 'W';
517
+ push @coords, $lat, $lon;
512
518
  } elsif (lc $_ eq 'both') {
513
519
  $both = 1;
514
520
  } elsif ($_ =~ /^num=(\d+)$/i) {
@@ -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.06';
17
+ $VERSION = '1.07';
18
18
 
19
19
  # map for writing metadata to InDesign files (currently only write XMP)
20
20
  my %indMap = (
@@ -73,9 +73,13 @@ sub ProcessIND($$)
73
73
  my $pages = Get32u($curPage, 280);
74
74
  $pages < 2 and $err = 'Invalid page count', goto DONE;
75
75
  my $pos = $pages * 4096;
76
- if ($pos > 0x7fffffff and not $et->Options('LargeFileSupport')) {
77
- $err = 'InDesign files larger than 2 GB not supported (LargeFileSupport not set)';
78
- goto DONE;
76
+ if ($pos > 0x7fffffff) {
77
+ if (not $et->Options('LargeFileSupport')) {
78
+ $err = 'InDesign files larger than 2 GB not supported (LargeFileSupport not set)';
79
+ goto DONE;
80
+ } elsif ($et->Options('LargeFileSupport') eq '2') {
81
+ $et->WarnOnce('Processing large file (LargeFileSupport is 2)');
82
+ }
79
83
  }
80
84
  if ($outfile) {
81
85
  # make XMP the preferred group for writing
@@ -727,7 +727,6 @@ my %j2cMarker = (
727
727
  {
728
728
  Name => 'ColorSpecData',
729
729
  Format => 'undef[$size-3]',
730
- Writable => 'undef',
731
730
  Protected => 1,
732
731
  Binary => 1,
733
732
  },
@@ -11,7 +11,7 @@ package Image::ExifTool::Lang::de;
11
11
  use strict;
12
12
  use vars qw($VERSION);
13
13
 
14
- $VERSION = '1.36';
14
+ $VERSION = '1.37';
15
15
 
16
16
  %Image::ExifTool::Lang::de::Translate = (
17
17
  'AEAperture' => 'AE-Blende',
@@ -5118,7 +5118,7 @@ $VERSION = '1.36';
5118
5118
  'LensMake' => 'Objektivhersteller',
5119
5119
  'LensManufacturer' => 'Objektivhersteller',
5120
5120
  'LensMaxApertureRange' => 'Objektiv Blendenbereich',
5121
- 'LensModel' => 'Objektiv-Typ',
5121
+ 'LensModel' => 'Objektivmodell',
5122
5122
  'LensProfileDigest' => 'Kennwert des Objektivprofils',
5123
5123
  'LensProperties' => 'Objektivfunktionen?',
5124
5124
  'LensSerialNumber' => 'Objektiv-Seriennummer',
@@ -15,7 +15,7 @@ use strict;
15
15
  use vars qw($VERSION);
16
16
  use Image::ExifTool qw(:DataAccess :Utils);
17
17
 
18
- $VERSION = '1.15';
18
+ $VERSION = '1.16';
19
19
 
20
20
  sub HandleStruct($$;$$$$);
21
21
 
@@ -44,7 +44,8 @@ my %uidInfo = (
44
44
  NOTES => q{
45
45
  The following tags are extracted from Matroska multimedia container files.
46
46
  This container format is used by file types such as MKA, MKV, MKS and WEBM.
47
- For speed, by default ExifTool extracts tags only up to the first Cluster.
47
+ For speed, by default ExifTool extracts tags only up to the first Cluster
48
+ unless a Seek element specifies the position of a Tags element after this.
48
49
  However, the L<Verbose|../ExifTool.html#Verbose> (-v) and L<Unknown|../ExifTool.html#Unknown> = 2 (-U) options force processing of
49
50
  Cluster data, and the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option skips over Clusters to
50
51
  read subsequent tags. See
@@ -112,8 +113,25 @@ my %uidInfo = (
112
113
  Name => 'Seek',
113
114
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
114
115
  },
115
- 0x13ab => { Name => 'SeekID', Binary => 1, Unknown => 1 },
116
- 0x13ac => { Name => 'SeekPosition', Format => 'unsigned', Unknown => 1 },
116
+ 0x13ab => {
117
+ Name => 'SeekID',
118
+ Unknown => 1,
119
+ SeekInfo => 'ID', # save seek ID's
120
+ # (note: converted from VInt internally)
121
+ PrintConv => q{
122
+ my $tagInfo = $Image::ExifTool::Matroska::Main{$val};
123
+ $val = sprintf('0x%x', $val);
124
+ $val .= " ($$tagInfo{Name})" if ref $tagInfo eq 'HASH' and $$tagInfo{Name};
125
+ return $val;
126
+ },
127
+ },
128
+ 0x13ac => {
129
+ Name => 'SeekPosition',
130
+ Format => 'unsigned',
131
+ Unknown => 1,
132
+ SeekInfo => 'Position', # save seek positions
133
+ RawConv => '$val + $$self{SeekHeadOffset}',
134
+ },
117
135
  #
118
136
  # Segment Info
119
137
  #
@@ -350,8 +368,9 @@ my %uidInfo = (
350
368
  Name => 'VideoScanType',
351
369
  Format => 'unsigned',
352
370
  PrintConv => {
353
- 0 => 'Progressive',
371
+ 0 => 'Undetermined',
354
372
  1 => 'Interlaced',
373
+ 2 => 'Progressive',
355
374
  },
356
375
  },
357
376
  0x13b8 => {
@@ -893,6 +912,7 @@ sub HandleStruct($$;$$$$)
893
912
  # Inputs: 0) data buffer, 1) position in data
894
913
  # Returns: integer value and updates position, -1 for unknown/reserved value,
895
914
  # or undef if no data left
915
+ # Notes: Increments position pointer
896
916
  sub GetVInt($$)
897
917
  {
898
918
  return undef if $_[1] >= length $_[0];
@@ -929,7 +949,7 @@ sub ProcessMKV($$)
929
949
  {
930
950
  my ($et, $dirInfo) = @_;
931
951
  my $raf = $$dirInfo{RAF};
932
- my ($buff, $buf2, @dirEnd, $trackIndent, %trackTypes, $struct);
952
+ my ($buff, $buf2, @dirEnd, $trackIndent, %trackTypes, $struct, %seekInfo, %seek);
933
953
 
934
954
  $raf->Read($buff, 4) == 4 or return 0;
935
955
  return 0 unless $buff =~ /^\x1a\x45\xdf\xa3/;
@@ -952,6 +972,7 @@ sub ProcessMKV($$)
952
972
  my $processAll = ($verbose or $et->Options('Unknown') > 1) ? 2 : 0;
953
973
  ++$processAll if $et->Options('ExtractEmbedded');
954
974
  $$et{TrackTypes} = \%trackTypes; # store Track types reference
975
+ $$et{SeekHeadOffset} = 0;
955
976
  my $oldIndent = $$et{INDENT};
956
977
  my $chapterNum = 0;
957
978
  my $dirName = 'MKV';
@@ -960,6 +981,16 @@ sub ProcessMKV($$)
960
981
  for (;;) {
961
982
  while (@dirEnd) {
962
983
  if ($pos + $dataPos >= $dirEnd[-1][0]) {
984
+ if ($dirEnd[-1][1] eq 'Seek') {
985
+ # save seek info
986
+ if (defined $seekInfo{ID} and defined $seekInfo{Position}) {
987
+ my $seekTag = $$tagTablePtr{$seekInfo{ID}};
988
+ if (ref $seekTag eq 'HASH' and $$seekTag{Name}) {
989
+ $seek{$$seekTag{Name}} = $seekInfo{Position} + $$et{SeekHeadOffset};
990
+ }
991
+ }
992
+ undef %seekInfo;
993
+ }
963
994
  pop @dirEnd;
964
995
  if ($struct) {
965
996
  if (@dirEnd and $dirEnd[-1][2]) {
@@ -993,9 +1024,10 @@ sub ProcessMKV($$)
993
1024
  }
994
1025
  my $tag = GetVInt($buff, $pos);
995
1026
  last unless defined $tag and $tag >= 0;
1027
+ $$et{SeekHeadOffset} = $pos if $tag == 0x14d9b74; # save offset of seek head
996
1028
  my $size = GetVInt($buff, $pos);
997
1029
  last unless defined $size;
998
- my $unknownSize;
1030
+ my ($unknownSize, $seekInfoOnly);
999
1031
  $size < 0 and $unknownSize = 1, $size = 1e20;
1000
1032
  if (@dirEnd and $pos + $dataPos + $size > $dirEnd[-1][0]) {
1001
1033
  $et->Warn("Invalid or corrupted $dirEnd[-1][1] master element");
@@ -1010,14 +1042,28 @@ sub ProcessMKV($$)
1010
1042
  next;
1011
1043
  }
1012
1044
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1013
- # just fall through into the contained EBML elements
1045
+ if (not $tagInfo and ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{SeekInfo}) {
1046
+ $tagInfo = $$tagTablePtr{$tag};
1047
+ $seekInfoOnly = 1;
1048
+ }
1014
1049
  if ($tagInfo) {
1015
1050
  if ($$tagInfo{SubDirectory}) {
1016
1051
  # stop processing at first cluster unless we are using -v -U or -ee
1052
+ # or there are Tags after this
1017
1053
  if ($$tagInfo{Name} eq 'Cluster' and $processAll < 2) {
1018
- last unless $processAll;
1054
+ # jump to Tags if possible
1055
+ unless ($processAll) {
1056
+ if ($seek{Tags} and $seek{Tags} > $pos + $dataPos and $raf->Seek($seek{Tags},0)) {
1057
+ $buff = '';
1058
+ $dataPos = $seek{Tags};
1059
+ $pos = $dataLen = 0;
1060
+ next;
1061
+ }
1062
+ last;
1063
+ }
1019
1064
  undef $tagInfo; # just skip the Cluster when -ee is used
1020
1065
  } else {
1066
+ # just fall through into the contained EBML elements
1021
1067
  $$et{INDENT} .= '| ';
1022
1068
  $et->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size);
1023
1069
  $dirName = $$tagInfo{Name};
@@ -1040,7 +1086,12 @@ sub ProcessMKV($$)
1040
1086
  # just skip unknown and large data blocks
1041
1087
  if (not $tagInfo or $more > 10000000) {
1042
1088
  # don't try to skip very large blocks unless LargeFileSupport is enabled
1043
- last if $more >= 0x80000000 and not $et->Options('LargeFileSupport');
1089
+ if ($more >= 0x80000000) {
1090
+ last unless $et->Options('LargeFileSupport');
1091
+ if ($et->Options('LargeFileSupport') eq '2') {
1092
+ $et->WarnOnce('Processing large block (LargeFileSupport is 2)');
1093
+ }
1094
+ }
1044
1095
  $raf->Seek($more, 1) or last;
1045
1096
  $buff = '';
1046
1097
  $dataPos += $dataLen + $more;
@@ -1118,6 +1169,11 @@ sub ProcessMKV($$)
1118
1169
  if ($$tagInfo{NoSave} or $struct) {
1119
1170
  $et->VerboseInfo($tag, $tagInfo, Value => $val, %parms) if $verbose;
1120
1171
  $$struct{$$tagInfo{Name}} = $val if $struct;
1172
+ } elsif ($$tagInfo{SeekInfo}) {
1173
+ my $p = $pos;
1174
+ $val = GetVInt($buff, $p) unless defined $val;
1175
+ $seekInfo{$$tagInfo{SeekInfo}} = $val;
1176
+ $et->HandleTag($tagTablePtr, $tag, $val, %parms) unless $seekInfoOnly;
1121
1177
  } else {
1122
1178
  $et->HandleTag($tagTablePtr, $tag, $val, %parms);
1123
1179
  }
@@ -203,13 +203,13 @@ sub WriteMRW($$;$);
203
203
  Name => 'ColorMode',
204
204
  Condition => '$$self{Make} !~ /^SONY/',
205
205
  Priority => 0,
206
- Writable => 'int32u',
206
+ Writable => 1,
207
207
  PrintConv => \%Image::ExifTool::Minolta::minoltaColorMode,
208
208
  },
209
209
  { #3
210
210
  Name => 'ColorMode',
211
211
  Condition => '$$self{Model} eq "DSLR-A100"',
212
- Writable => 'int32u',
212
+ Writable => 1,
213
213
  Notes => 'Sony A100',
214
214
  Priority => 0,
215
215
  PrintHex => 1,
@@ -65,7 +65,7 @@ use Image::ExifTool::Exif;
65
65
  use Image::ExifTool::GPS;
66
66
  use Image::ExifTool::XMP;
67
67
 
68
- $VERSION = '4.34';
68
+ $VERSION = '4.35';
69
69
 
70
70
  sub LensIDConv($$$);
71
71
  sub ProcessNikonAVI($$$);
@@ -720,6 +720,7 @@ sub GetAFPointGrid($$;$);
720
720
  '9A 4C 50 50 14 14 9C 06' => 'Yongnuo YN50mm F1.8N',
721
721
  '9F 48 48 48 24 24 A1 06' => 'Yongnuo YN40mm F2.8N', #30
722
722
  '9F 54 68 68 18 18 A2 06' => 'Yongnuo YN100mm F2N', #30
723
+ '9F 4C 44 44 18 18 A1 06' => 'Yongnuo YN35mm F2', #30
723
724
  #
724
725
  '02 40 44 5C 2C 34 02 00' => 'Exakta AF 35-70mm 1:3.5-4.5 MC',
725
726
  #
@@ -11710,7 +11711,7 @@ my %nikonFocalConversions = (
11710
11711
  },
11711
11712
  10 => {
11712
11713
  Name => 'NEFCompression',
11713
- Writable => 'int16u',
11714
+ Format => 'int16u',
11714
11715
  SeparateTable => 'NEFCompression',
11715
11716
  PrintConv => \%nefCompression,
11716
11717
  },
@@ -366,6 +366,7 @@ my %shootingMode = (
366
366
  '32 1' => '3-area (left)?', # (DMC-L1 guess)
367
367
  '32 2' => '3-area (center)?', # (DMC-L1 guess)
368
368
  '32 3' => '3-area (right)?', # (DMC-L1 guess)
369
+ # '32 16' ? (DC-GH6)
369
370
  '64 0' => 'Face Detect',
370
371
  '64 1' => 'Face Detect (animal detect on)', #forum11194
371
372
  '64 2' => 'Face Detect (animal detect off)', #forum11194
@@ -218,6 +218,7 @@ my %panasonicWhiteBalance = ( #forum9396
218
218
  0x30 => { Name => 'CropLeft', Writable => 'int16u' },
219
219
  0x31 => { Name => 'CropBottom', Writable => 'int16u' },
220
220
  0x32 => { Name => 'CropRight', Writable => 'int16u' },
221
+ 0x37 => { Name => 'ISO', Writable => 'int32u' },
221
222
  # 0x44 - may contain another pointer to the raw data starting at byte 2 in this data (DC-GH6)
222
223
  0x10f => {
223
224
  Name => 'Make',
@@ -4697,7 +4697,7 @@ my %binaryDataAttrs = (
4697
4697
  3 => 'Grip Battery',
4698
4698
  4 => 'External Power Supply', #PH
4699
4699
  },
4700
- },{ #PH
4700
+ },{ #PH (forum15976)
4701
4701
  Name => 'PowerSource',
4702
4702
  Mask => 0x0f,
4703
4703
  Notes => 'K-3III',
@@ -4709,8 +4709,18 @@ my %binaryDataAttrs = (
4709
4709
  2 => 'Grip Battery',
4710
4710
  4 => 'External Power Supply',
4711
4711
  },
4712
- },{
4713
4712
  }],
4713
+ 0.2 => {
4714
+ Name => 'PowerAvailable',
4715
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4716
+ Notes => 'K-3III',
4717
+ Mask => 0xf0,
4718
+ PrintConv => { BITMASK => {
4719
+ 0 => 'Body Battery',
4720
+ 1 => 'Grip Battery',
4721
+ 3 => 'External Power Supply',
4722
+ }},
4723
+ },
4714
4724
  1.1 => [
4715
4725
  {
4716
4726
  Name => 'BodyBatteryState',
@@ -4735,11 +4745,6 @@ my %binaryDataAttrs = (
4735
4745
  4 => 'Close to Full',
4736
4746
  5 => 'Full',
4737
4747
  },
4738
- },{
4739
- Name => 'BodyBatteryState',
4740
- Notes => 'decoding unknown for some models',
4741
- Unknown => 1, # (doesn't appear to be valid for the K-3 III)
4742
- Mask => 0xf0,
4743
4748
  },
4744
4749
  ],
4745
4750
  1.2 => [
@@ -4754,11 +4759,6 @@ my %binaryDataAttrs = (
4754
4759
  3 => 'Running Low',
4755
4760
  4 => 'Full',
4756
4761
  },
4757
- },{
4758
- Name => 'GripBatteryState',
4759
- Notes => 'decoding unknown for other models',
4760
- Unknown => 1, # (doesn't appear to be valid for the K-5)
4761
- Mask => 0x0f,
4762
4762
  },
4763
4763
  ],
4764
4764
  # internal and grip battery voltage Analogue to Digital measurements,
@@ -4794,7 +4794,19 @@ my %binaryDataAttrs = (
4794
4794
  # BodyBatteryVoltage4 6.10 V 7.55 V 7.45 V
4795
4795
  # "Meas" open-circuit voltages with DVM: AB=0V, AC=+8.33V, BC=+8.22V
4796
4796
  # (terminal "C" is closest to edge of battery)
4797
- },
4797
+ },{
4798
+ Name => 'BodyBatteryState',
4799
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4800
+ Notes => 'K-3III',
4801
+ PrintConv => {
4802
+ 0 => 'Empty or Missing',
4803
+ 1 => 'Almost Empty',
4804
+ 2 => 'Running Low',
4805
+ 3 => 'Half Full',
4806
+ 4 => 'Close to Full',
4807
+ 5 => 'Full',
4808
+ },
4809
+ }
4798
4810
  ],
4799
4811
  3 => [
4800
4812
  {
@@ -4810,7 +4822,11 @@ my %binaryDataAttrs = (
4810
4822
  Name => 'BodyBatteryADLoad',
4811
4823
  Description => 'Body Battery A/D Load',
4812
4824
  Condition => '$$self{Model} =~ /(\*ist|K100D|K200D)\b/',
4813
- },
4825
+ },{
4826
+ Name => 'BodyBatteryPercent',
4827
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4828
+ Notes => 'K-3III',
4829
+ }
4814
4830
  ],
4815
4831
  4 => [
4816
4832
  {
@@ -4827,6 +4843,15 @@ my %binaryDataAttrs = (
4827
4843
  PrintConv => 'sprintf("%.2f V", $val)',
4828
4844
  PrintConvInv => '$val =~ s/\s*V$//',
4829
4845
  },
4846
+ {
4847
+ Name => 'BodyBatteryVoltage',
4848
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4849
+ Format => 'int32u',
4850
+ ValueConv => '$val * 4e-8 + 0.27219',
4851
+ ValueConvInv => '($val - 0.27219) / 4e-8',
4852
+ PrintConv => 'sprintf("%.2f V", $val)',
4853
+ PrintConvInv => '$val =~ s/\s*V$//',
4854
+ },
4830
4855
  ],
4831
4856
  5 => {
4832
4857
  Name => 'GripBatteryADLoad',
@@ -4853,6 +4878,34 @@ my %binaryDataAttrs = (
4853
4878
  PrintConv => 'sprintf("%.2f V", $val)',
4854
4879
  PrintConvInv => '$val =~ s/\s*V$//',
4855
4880
  },
4881
+ 16 => {
4882
+ Name => 'GripBatteryState',
4883
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4884
+ Notes => 'K-3III',
4885
+ PrintConv => {
4886
+ 0 => 'Empty or Missing',
4887
+ 1 => 'Almost Empty',
4888
+ 2 => 'Running Low',
4889
+ 3 => 'Half Full',
4890
+ 4 => 'Close to Full',
4891
+ 5 => 'Full',
4892
+ },
4893
+ },
4894
+ 17 => {
4895
+ Name => 'GripBatteryPercent',
4896
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4897
+ Notes => 'K-3III',
4898
+ },
4899
+ 18 => {
4900
+ Name => 'GripBatteryVoltage',
4901
+ Condition => '$$self{Model} =~ /K-3 Mark III/',
4902
+ Notes => 'K-3III',
4903
+ Format => 'int32u',
4904
+ ValueConv => '$val * 4e-8 + 0.27219',
4905
+ ValueConvInv => '($val - 0.27219) / 4e-8',
4906
+ PrintConv => 'sprintf("%.2f V", $val)',
4907
+ PrintConvInv => '$val =~ s/\s*V$//',
4908
+ },
4856
4909
  );
4857
4910
 
4858
4911
  # auto focus information
@@ -5521,14 +5574,27 @@ my %binaryDataAttrs = (
5521
5574
  GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
5522
5575
  FORMAT => 'int8s',
5523
5576
  NOTES => 'Tags decoded from the electronic level information for the K-3 III.',
5577
+ 1 => {
5578
+ Name => 'CameraOrientation',
5579
+ PrintConv => {
5580
+ 0 => 'Horizontal (normal)',
5581
+ 1 => 'Rotate 270 CW',
5582
+ 2 => 'Rotate 180',
5583
+ 3 => 'Rotate 90 CW',
5584
+ 4 => 'Upwards', # (to the sky)
5585
+ 5 => 'Downwards', # (to the ground)
5586
+ },
5587
+ },
5524
5588
  3 => {
5525
5589
  Name => 'RollAngle',
5590
+ Notes => 'converted to degrees of clockwise camera rotation',
5526
5591
  Format => 'int16s',
5527
5592
  ValueConv => '-$val / 2',
5528
5593
  ValueConvInv => '-$val * 2',
5529
5594
  },
5530
5595
  5 => {
5531
5596
  Name => 'PitchAngle',
5597
+ Notes => 'converted to degrees of upward camera tilt',
5532
5598
  Format => 'int16s',
5533
5599
  ValueConv => '-$val / 2',
5534
5600
  ValueConvInv => '-$val * 2',
@@ -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.97';
51
+ $VERSION = '2.98';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -238,7 +238,11 @@ my %useExt = ( GLV => 'MP4' );
238
238
 
239
239
  # information for int32u date/time tags (time zero is Jan 1, 1904)
240
240
  my %timeInfo = (
241
- Notes => 'converted from UTC to local time if the QuickTimeUTC option is set',
241
+ Notes => q{
242
+ converted from UTC to local time if the QuickTimeUTC option is set. This
243
+ tag is part of a binary data structure so it may not be deleted -- instead
244
+ the value is set to zero if the tag is deleted individually
245
+ },
242
246
  Shift => 'Time',
243
247
  Writable => 1,
244
248
  Permanent => 1,
@@ -8988,12 +8992,20 @@ sub HandleItemInfo($)
8988
8992
  if ($$item{Extents} and @{$$item{Extents}}) {
8989
8993
  $len += $$_[2] foreach @{$$item{Extents}};
8990
8994
  }
8991
- $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n");
8995
+ my $enc = $$item{ContentEncoding} ? ", $$item{ContentEncoding} encoded" : '';
8996
+ $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes$enc)\n");
8992
8997
  }
8993
8998
  # get ExifTool name for this item
8994
8999
  my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP', jpeg => 'PreviewImage' }->{$type} || '';
8995
9000
  my ($warn, $extent);
8996
- $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding};
9001
+ if ($$item{ContentEncoding}) {
9002
+ if ($$item{ContentEncoding} ne 'deflate') {
9003
+ # (other possible values are 'gzip' and 'compress', but I don't have samples of these)
9004
+ $warn = "Can't currently decode $$item{ContentEncoding} encoded $type metadata";
9005
+ } elsif (not eval { require Compress::Zlib }) {
9006
+ $warn = "Install Compress::Zlib to decode deflated $type metadata";
9007
+ }
9008
+ }
8997
9009
  $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex};
8998
9010
  $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod};
8999
9011
  $et->WarnOnce($warn) if $warn and $name;
@@ -9053,6 +9065,22 @@ sub HandleItemInfo($)
9053
9065
  next unless defined $buff;
9054
9066
  $buff = $val . $buff if length $val;
9055
9067
  next unless length $buff; # ignore empty directories
9068
+ if ($$item{ContentEncoding}) {
9069
+ my ($v2, $stat);
9070
+ my $inflate = Compress::Zlib::inflateInit();
9071
+ $inflate and ($v2, $stat) = $inflate->inflate($buff);
9072
+ if ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
9073
+ $buff = $v2;
9074
+ my $len = length $buff;
9075
+ $et->VPrint(0, "$$et{INDENT}Inflated Item $id) '${type}' ($len bytes)\n");
9076
+ $et->VerboseDump(\$buff);
9077
+ } else {
9078
+ $warn = "Error inflating $name metadata";
9079
+ $et->WarnOnce($warn);
9080
+ $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2;
9081
+ next;
9082
+ }
9083
+ }
9056
9084
  my ($start, $subTable, $proc);
9057
9085
  my $pos = $$item{Extents}[0][1] + $base;
9058
9086
  if ($name eq 'EXIF' and length $buff >= 4) {
@@ -9488,7 +9516,8 @@ sub ProcessMOV($$;$)
9488
9516
  my $dataPt = $$dirInfo{DataPt};
9489
9517
  my $verbose = $et->Options('Verbose');
9490
9518
  my $validate = $$et{OPTIONS}{Validate};
9491
- my $dataPos = $$dirInfo{Base} || 0;
9519
+ my $dirBase = $$dirInfo{Base} || 0;
9520
+ my $dataPos = $dirBase;
9492
9521
  my $dirID = $$dirInfo{DirID} || '';
9493
9522
  my $charsetQuickTime = $et->Options('CharsetQuickTime');
9494
9523
  my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
@@ -9573,6 +9602,7 @@ sub ProcessMOV($$;$)
9573
9602
  $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
9574
9603
  }
9575
9604
  my $lastTag = '';
9605
+ my $lastPos = 0;
9576
9606
  for (;;) {
9577
9607
  my ($eeTag, $ignore);
9578
9608
  last if defined $atomCount and --$atomCount < 0;
@@ -9611,6 +9641,8 @@ sub ProcessMOV($$;$)
9611
9641
  } elsif (not $et->Options('LargeFileSupport')) {
9612
9642
  $warnStr = 'End of processing at large atom (LargeFileSupport not enabled)';
9613
9643
  last;
9644
+ } elsif ($et->Options('LargeFileSupport') eq '2') {
9645
+ $et->WarnOnce('Processing large atom (LargeFileSupport is 2)');
9614
9646
  }
9615
9647
  }
9616
9648
  $size = $hi * 4294967296 + $lo - 16;
@@ -10085,14 +10117,15 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
10085
10117
  ) if $verbose;
10086
10118
  if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
10087
10119
  my $t = PrintableTagID($tag,2);
10088
- $warnStr = "Truncated '${t}' data";
10120
+ $warnStr = sprintf("Truncated '${t}' data at offset 0x%x", $lastPos);
10089
10121
  last;
10090
10122
  }
10091
10123
  }
10092
10124
  $dataPos += $size + 8; # point to start of next atom data
10093
10125
  last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
10126
+ $lastPos = $raf->Tell() + $dirBase;
10094
10127
  $raf->Read($buff, 8) == 8 or last;
10095
- $lastTag = $tag if $$tagTablePtr{$tag};
10128
+ $lastTag = $tag if $$tagTablePtr{$tag} and $tag ne 'free'; # (Insta360 sometimes puts free block before trailer)
10096
10129
  ($size, $tag) = unpack('Na4', $buff);
10097
10130
  ++$index if defined $index;
10098
10131
  }
@@ -10102,7 +10135,11 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
10102
10135
  if (($lastTag eq 'mdat' or $lastTag eq 'moov') and (not $$tagTablePtr{$tag} or
10103
10136
  ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
10104
10137
  {
10105
- $et->Warn('Unknown trailer with '.lcfirst($warnStr));
10138
+ if ($size == 0x1000000 - 8 and $tag =~ /^(\x94\xc0\x7e\0|\0\x02\0\0)/) {
10139
+ $et->Warn(sprintf('Insta360 trailer at offset 0x%x', $lastPos), 1);
10140
+ } else {
10141
+ $et->Warn('Unknown trailer with '.lcfirst($warnStr));
10142
+ }
10106
10143
  } else {
10107
10144
  $et->Warn($warnStr);
10108
10145
  }