exiftool_vendored 12.32.0 → 12.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +77 -3
  3. data/bin/META.json +1 -1
  4. data/bin/META.yml +1 -1
  5. data/bin/README +2 -2
  6. data/bin/exiftool +57 -39
  7. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +7 -2
  8. data/bin/lib/Image/ExifTool/CBOR.pm +85 -31
  9. data/bin/lib/Image/ExifTool/Canon.pm +28 -3
  10. data/bin/lib/Image/ExifTool/Charset.pm +2 -0
  11. data/bin/lib/Image/ExifTool/Exif.pm +109 -3
  12. data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
  13. data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
  14. data/bin/lib/Image/ExifTool/JSON.pm +4 -2
  15. data/bin/lib/Image/ExifTool/Jpeg2000.pm +111 -12
  16. data/bin/lib/Image/ExifTool/MacOS.pm +2 -2
  17. data/bin/lib/Image/ExifTool/Nikon.pm +637 -16
  18. data/bin/lib/Image/ExifTool/NikonCustom.pm +5 -1
  19. data/bin/lib/Image/ExifTool/NikonSettings.pm +67 -11
  20. data/bin/lib/Image/ExifTool/Olympus.pm +5 -1
  21. data/bin/lib/Image/ExifTool/PDF.pm +5 -3
  22. data/bin/lib/Image/ExifTool/QuickTime.pm +21 -2
  23. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +2 -2
  24. data/bin/lib/Image/ExifTool/README +6 -2
  25. data/bin/lib/Image/ExifTool/Sony.pm +31 -11
  26. data/bin/lib/Image/ExifTool/TagInfoXML.pm +9 -4
  27. data/bin/lib/Image/ExifTool/TagLookup.pm +5054 -4455
  28. data/bin/lib/Image/ExifTool/TagNames.pod +1185 -23
  29. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +10 -0
  30. data/bin/lib/Image/ExifTool/Writer.pl +45 -3
  31. data/bin/lib/Image/ExifTool/XMP.pm +111 -25
  32. data/bin/lib/Image/ExifTool/XMP2.pl +3 -1
  33. data/bin/lib/Image/ExifTool.pm +83 -19
  34. data/bin/lib/Image/ExifTool.pod +9 -1
  35. data/bin/perl-Image-ExifTool.spec +1 -1
  36. data/lib/exiftool_vendored/version.rb +1 -1
  37. metadata +2 -2
@@ -15,12 +15,12 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::JSON;
17
17
 
18
- $VERSION = '1.00';
18
+ $VERSION = '1.01';
19
19
 
20
20
  sub ProcessCBOR($$$);
21
21
  sub ReadCBORValue($$$$);
22
22
 
23
- # optional CBOR type codes
23
+ # optional CBOR type code
24
24
  my %cborType6 = (
25
25
  0 => 'date/time string',
26
26
  1 => 'epoch-based date/time',
@@ -78,6 +78,7 @@ sub ReadCBORValue($$$$)
78
78
  return(undef, 'Truncated CBOR data', $pos) if $pos >= $end;
79
79
  my $verbose = $$et{OPTIONS}{Verbose};
80
80
  my $indent = $$et{INDENT};
81
+ my $dumpStart = $pos;
81
82
  my $fmt = Get8u($dataPt, $pos++);
82
83
  my $dat = $fmt & 0x1f;
83
84
  my ($num, $val, $err, $size);
@@ -95,28 +96,22 @@ sub ReadCBORValue($$$$)
95
96
  $num = ReadValue($dataPt, $pos, $format, 1, $size);
96
97
  $pos += $size;
97
98
  }
98
- my ($pre, $opt) = ('', ':');
99
- if ($verbose and $fmt != 6) {
100
- if (defined $$et{cbor_pre}) {
101
- $pre = "$$et{cbor_pre}";
102
- delete $$et{cbor_pre};
103
- }
104
- if (defined $$et{cbor_opt}) {
105
- $opt = ", $$et{cbor_opt}:";
106
- delete $$et{cbor_opt};
107
- }
99
+ my $pre = '';
100
+ if (defined $$et{cbor_pre} and $fmt != 6) {
101
+ $pre = $$et{cbor_pre};
102
+ delete $$et{cbor_pre};
108
103
  }
109
104
  if ($fmt == 0) { # positive integer
110
105
  $val = $num;
111
- $et->VPrint(1, "$$et{INDENT} ${pre}int+$opt $val\n");
106
+ $et->VPrint(1, "$$et{INDENT} ${pre}int+: $val\n");
112
107
  } elsif ($fmt == 1) { # negative integer
113
108
  $val = -1 * $num;
114
- $et->VPrint(1, "$$et{INDENT} ${pre}int-$opt $val\n");
109
+ $et->VPrint(1, "$$et{INDENT} ${pre}int-: $val\n");
115
110
  } elsif ($fmt == 2 or $fmt == 3) { # byte/UTF8 string
116
111
  return(undef, 'Truncated CBOR string value', $pos) if $pos + $num > $end;
117
112
  if ($num < 0) { # (should not happen in C2PA)
118
113
  my $string = '';
119
- $$et{INDENT} .= ' ';
114
+ $$et{INDENT} .= ' ';
120
115
  for (;;) {
121
116
  ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end);
122
117
  return(undef, $err, $pos) if $err;
@@ -125,26 +120,34 @@ sub ReadCBORValue($$$$)
125
120
  $string .= $val;
126
121
  }
127
122
  $$et{INDENT} = $indent;
128
- return($string, undef, $pos); # return concatenated strings
123
+ return($string, undef, $pos); # return concatenated byte/text string
129
124
  } else {
130
125
  $val = substr($$dataPt, $pos, $num);
131
126
  }
132
127
  $pos += $num;
133
- if ($fmt == 2) {
134
- $et->VPrint(1, "$$et{INDENT} ${pre}byte$opt <binary data ".length($val)." bytes>\n");
135
- return(\$val, undef, $pos); # (byte string)
128
+ if ($fmt == 2) { # (byte string)
129
+ $et->VPrint(1, "$$et{INDENT} ${pre}byte: <binary data ".length($val)." bytes>\n");
130
+ my $dat = $val;
131
+ $val = \$dat; # use scalar reference for binary data
132
+ } else { # (text string)
133
+ $val = $et->Decode($val, 'UTF8');
134
+ $et->VPrint(1, "$$et{INDENT} ${pre}text: '${val}'\n");
136
135
  }
137
- $et->VPrint(1, "$$et{INDENT} ${pre}text$opt '${val}'\n");
138
136
  } elsif ($fmt == 4 or $fmt == 5) { # list/hash
139
137
  if ($fmt == 4) {
140
- $et->VPrint(1, "$$et{INDENT} ${pre}list$opt <$num elements>\n");
138
+ $et->VPrint(1, "$$et{INDENT} ${pre}list: <$num elements>\n");
141
139
  } else {
142
- $et->VPrint(1, "$$et{INDENT} ${pre}hash$opt <$num pairs>\n");
140
+ $et->VPrint(1, "$$et{INDENT} ${pre}hash: <$num pairs>\n");
143
141
  $num *= 2;
144
142
  }
145
- $$et{INDENT} .= ' ';
143
+ $$et{INDENT} .= ' ';
146
144
  my $i = 0;
147
145
  my @list;
146
+ Image::ExifTool::HexDump($dataPt, $pos - $dumpStart,
147
+ Start => $dumpStart,
148
+ DataPos => $$et{cbor_datapos},
149
+ Prefix => $$et{INDENT},
150
+ ) if $verbose > 2;
148
151
  while ($num) {
149
152
  $$et{cbor_pre} = "$i) ";
150
153
  if ($fmt == 4) {
@@ -162,6 +165,7 @@ sub ReadCBORValue($$$$)
162
165
  push @list, $val;
163
166
  --$num;
164
167
  }
168
+ $dumpStart = $pos;
165
169
  $$et{INDENT} = $indent;
166
170
  if ($fmt == 5) {
167
171
  my ($i, @keys);
@@ -174,9 +178,40 @@ sub ReadCBORValue($$$$)
174
178
  } else {
175
179
  $val = \@list;
176
180
  }
177
- } elsif ($fmt == 6) { # optional type
178
- $$et{cbor_opt} = $cborType6{$num} || "<unknown type $num>";
181
+ } elsif ($fmt == 6) { # optional tag
182
+ if ($verbose) {
183
+ my $str = "$num (" . ($cborType6{$num} || 'unknown') . ')';
184
+ my $spc = $$et{cbor_pre} ? (' ' x length $$et{cbor_pre}) : '';
185
+ $et->VPrint(1, "$$et{INDENT} $spc<CBOR optional type $str>\n");
186
+ Image::ExifTool::HexDump($dataPt, $pos - $dumpStart,
187
+ Start => $dumpStart,
188
+ DataPos => $$et{cbor_datapos},
189
+ Prefix => $$et{INDENT} . ' ',
190
+ ) if $verbose > 2;
191
+ }
192
+ # read next value (note: in the case of multiple tags,
193
+ # this nesting will apply the tags in the correct order)
179
194
  ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end);
195
+ $dumpStart = $pos;
196
+ # convert some values according to the optional tag number (untested)
197
+ if ($num == 0 and not ref $val) { # date/time string
198
+ require Image::ExifTool::XMP;
199
+ $val = Image::ExifTool::XMP::ConvertXMPDate($val);
200
+ } elsif ($num == 1 and not ref $val) { # epoch-based date/time
201
+ if (Image::ExifTool::IsFloat($val)) {
202
+ my $dec = ($val == int($val)) ? undef : 6;
203
+ $val = Image::ExifTool::ConvertUnixTime($val, 1, $dec);
204
+ }
205
+ } elsif (($num == 2 or $num == 3) and ref($val) eq 'SCALAR') { # pos/neg bignum
206
+ my $big = 0;
207
+ $big = 256 * $big + Get8u($val,$_) foreach 0..(length($$val) - 1);
208
+ $val = $num==2 ? $big : -$big;
209
+ } elsif (($num == 4 or $num == 5) and # decimal fraction or bigfloat
210
+ ref($val) eq 'ARRAY' and @$val == 2 and
211
+ Image::ExifTool::IsInt($$val[0]) and Image::ExifTool::IsInt($$val[1]))
212
+ {
213
+ $val = $$val[1] * ($num == 4 ? 10 : 2) ** $$val[0];
214
+ }
180
215
  } elsif ($fmt == 7) {
181
216
  if ($dat == 31) {
182
217
  undef $val; # "break" = end of indefinite array/hash (not used in C2PA)
@@ -202,10 +237,16 @@ sub ReadCBORValue($$$$)
202
237
  } else {
203
238
  return(undef, "Invalid CBOR type 7 variant $num", $pos);
204
239
  }
205
- $et->VPrint(1, "$$et{INDENT} ${pre}typ7$opt ".(defined $val ? $val : '<break>')."\n");
240
+ $et->VPrint(1, "$$et{INDENT} ${pre}typ7: ".(defined $val ? $val : '<break>')."\n");
206
241
  } else {
207
242
  return(undef, "Unknown CBOR format $fmt", $pos);
208
243
  }
244
+ Image::ExifTool::HexDump($dataPt, $pos - $dumpStart,
245
+ Start => $dumpStart,
246
+ DataPos => $$et{cbor_datapos},
247
+ Prefix => $$et{INDENT} . ' ',
248
+ MaxLen => $verbose < 5 ? ($verbose == 3 ? 96 : 2048) : undef,
249
+ ) if $verbose > 2;
209
250
  return($val, $err, $pos);
210
251
  }
211
252
 
@@ -219,15 +260,28 @@ sub ProcessCBOR($$$)
219
260
  my $dataPt = $$dirInfo{DataPt};
220
261
  my $pos = $$dirInfo{DirStart};
221
262
  my $end = $pos + $$dirInfo{DirLen};
263
+ my ($val, $err, $tag, $i);
264
+
222
265
  $et->VerboseDir('CBOR', undef, $$dirInfo{DirLen});
223
- my ($val, $err, $tag);
224
- require Image::ExifTool::CBOR;
266
+
267
+ $$et{cbor_datapos} = $$dirInfo{DataPos} + $$dirInfo{Base};
268
+
225
269
  while ($pos < $end) {
226
270
  ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end);
227
271
  $err and $et->Warn($err), last;
228
- ref $val eq 'HASH' or $et->VPrint(1, "$$et{INDENT} CBOR end: Non-hash encountered\n"), last;
229
- foreach $tag (@{$$val{_ordered_keys_}}) {
230
- Image::ExifTool::JSON::ProcessTag($et, $tagTablePtr, $tag, $$val{$tag});
272
+ if (ref $val eq 'HASH') {
273
+ foreach $tag (@{$$val{_ordered_keys_}}) {
274
+ Image::ExifTool::JSON::ProcessTag($et, $tagTablePtr, $tag, $$val{$tag});
275
+ }
276
+ } elsif (ref $val eq 'ARRAY') {
277
+ for ($i=0; $i<@$val; ++$i) {
278
+ Image::ExifTool::JSON::ProcessTag($et, $tagTablePtr, "Item$i", $$val[$i]);
279
+ }
280
+ } elsif ($val eq '0') {
281
+ $et->VPrint(1, "$$et{INDENT} <CBOR end>\n");
282
+ last; # (treat as padding)
283
+ } else {
284
+ $et->VPrint(1, "$$et{INDENT} Unknown value: $val\n");
231
285
  }
232
286
  }
233
287
  return 1;
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '4.51';
91
+ $VERSION = '4.54';
92
92
 
93
93
  # Note: Removed 'USM' from 'L' lenses since it is redundant - PH
94
94
  # (or is it? Ref 32 shows 5 non-USM L-type lenses)
@@ -187,7 +187,7 @@ $VERSION = '4.51';
187
187
  37.2 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro (A20)', #38
188
188
  37.3 => 'Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical [IF]', #34
189
189
  37.4 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical [IF] Macro', #forum2937
190
- 38 => 'Canon EF 80-200mm f/4.5-5.6', #32
190
+ 38 => 'Canon EF 80-200mm f/4.5-5.6 II', #32 (II added ref https://github.com/Exiv2/exiv2/issues/1906)
191
191
  39 => 'Canon EF 75-300mm f/4-5.6',
192
192
  40 => 'Canon EF 28-80mm f/3.5-5.6',
193
193
  41 => 'Canon EF 28-90mm f/4-5.6', #32
@@ -595,6 +595,10 @@ $VERSION = '4.51';
595
595
  '61182.21' => 'Canon RF 70-200mm F4L IS USM', #42
596
596
  '61182.22' => 'Canon RF 50mm F1.8 STM', #42
597
597
  '61182.23' => 'Canon RF 14-35mm F4L IS USM', #IB
598
+ '61182.24' => 'Canon RF 100-400mm F5.6-8 IS USM', #42
599
+ '61182.25' => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
600
+ '61182.26' => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
601
+ '61182.27' => 'Canon RF 16mm F2.8 STM', #42
598
602
  #'61182.xx' => 'Canon RF 100mm F2.8L MACRO IS USM',
599
603
  65535 => 'n/a',
600
604
  );
@@ -950,6 +954,7 @@ $VERSION = '4.51';
950
954
  0x80000435 => 'EOS Rebel T8i / 850D / X10i', #JR/PH
951
955
  0x80000436 => 'EOS SL3 / 250D / Kiss X10', #25
952
956
  0x80000437 => 'EOS 90D', #IB
957
+ 0x80000450 => 'EOS R3', #42
953
958
  0x80000453 => 'EOS R6', #PH
954
959
  0x80000467 => 'PowerShot ZOOM',
955
960
  0x80000468 => 'EOS M50 Mark II / Kiss M2', #IB
@@ -6731,7 +6736,17 @@ my %ciMaxFocal = (
6731
6736
  PrintConvInv => '$val =~ s/ ?m$//; IsFloat($val) ? $val : 655.35',
6732
6737
  },
6733
6738
  # 22 - values: 0, 1
6734
- # 23 - values: 0, 21, 22
6739
+ 23 => { #JohnMoyer (forum12925)
6740
+ Name => 'ShutterMode',
6741
+ PrintConv => {
6742
+ 0 => 'Mechanical',
6743
+ 1 => 'Electronic First Curtain',
6744
+ 2 => 'Electronic',
6745
+ # 3 => ?
6746
+ # 21 => ?
6747
+ # 22 => ?
6748
+ },
6749
+ },
6735
6750
  25 => { #PH
6736
6751
  Name => 'FlashExposureLock',
6737
6752
  PrintConv => \%offOn,
@@ -6765,6 +6780,10 @@ my %ciMaxFocal = (
6765
6780
  278 => 'Canon RF 70-200mm F4L IS USM', #42
6766
6781
  280 => 'Canon RF 50mm F1.8 STM', #42
6767
6782
  281 => 'Canon RF 14-35mm F4L IS USM', #42/IB
6783
+ 283 => 'Canon RF 100-400mm F5.6-8 IS USM', #42
6784
+ 284 => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
6785
+ 285 => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
6786
+ 288 => 'Canon RF 16mm F2.8 STM', #42
6768
6787
  #xxx => 'Canon RF 100mm F2.8L MACRO IS USM',
6769
6788
  # Note: add new RF lenses to %canonLensTypes with ID 61182
6770
6789
  },
@@ -8740,6 +8759,7 @@ my %filterConv = (
8740
8759
  # --> ignored when reading, but offsets are updated when writing
8741
8760
  CMT1 => { # (CR3 files)
8742
8761
  Name => 'IFD0',
8762
+ PreservePadding => 1,
8743
8763
  SubDirectory => {
8744
8764
  TagTable => 'Image::ExifTool::Exif::Main',
8745
8765
  ProcessProc => \&Image::ExifTool::ProcessTIFF,
@@ -8748,6 +8768,7 @@ my %filterConv = (
8748
8768
  },
8749
8769
  CMT2 => { # (CR3 files)
8750
8770
  Name => 'ExifIFD',
8771
+ PreservePadding => 1,
8751
8772
  SubDirectory => {
8752
8773
  TagTable => 'Image::ExifTool::Exif::Main',
8753
8774
  ProcessProc => \&Image::ExifTool::ProcessTIFF,
@@ -8756,6 +8777,7 @@ my %filterConv = (
8756
8777
  },
8757
8778
  CMT3 => { # (CR3 files)
8758
8779
  Name => 'MakerNoteCanon',
8780
+ PreservePadding => 1,
8759
8781
  SubDirectory => {
8760
8782
  TagTable => 'Image::ExifTool::Canon::Main',
8761
8783
  ProcessProc => \&ProcessCMT3,
@@ -8764,6 +8786,7 @@ my %filterConv = (
8764
8786
  },
8765
8787
  CMT4 => { # (CR3 files)
8766
8788
  Name => 'GPSInfo',
8789
+ PreservePadding => 1,
8767
8790
  SubDirectory => {
8768
8791
  TagTable => 'Image::ExifTool::GPS::Main',
8769
8792
  ProcessProc => \&Image::ExifTool::ProcessTIFF,
@@ -8774,6 +8797,7 @@ my %filterConv = (
8774
8797
  THMB => {
8775
8798
  Name => 'ThumbnailImage',
8776
8799
  Groups => { 2 => 'Preview' },
8800
+ PreservePadding => 1,
8777
8801
  RawConv => 'substr($val, 16)',
8778
8802
  Binary => 1,
8779
8803
  },
@@ -8788,6 +8812,7 @@ my %filterConv = (
8788
8812
  WRITE_PROC => 'Image::ExifTool::QuickTime::WriteQuickTime',
8789
8813
  CNOP => {
8790
8814
  Name => 'CanonVRD',
8815
+ PreservePadding => 1,
8791
8816
  SubDirectory => {
8792
8817
  TagTable => 'Image::ExifTool::CanonVRD::Main',
8793
8818
  WriteProc => 'Image::ExifTool::CanonVRD::WriteCanonDR4',
@@ -6,6 +6,8 @@
6
6
  # Revisions: 2009/08/28 - P. Harvey created
7
7
  # 2010/01/20 - P. Harvey complete re-write
8
8
  # 2010/07/16 - P. Harvey added UTF-16 support
9
+ #
10
+ # Notes: Charset lookups are generated using my convertCharset script
9
11
  #------------------------------------------------------------------------------
10
12
 
11
13
  package Image::ExifTool::Charset;
@@ -56,7 +56,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
56
56
  use Image::ExifTool qw(:DataAccess :Utils);
57
57
  use Image::ExifTool::MakerNotes;
58
58
 
59
- $VERSION = '4.36';
59
+ $VERSION = '4.38';
60
60
 
61
61
  sub ProcessExif($$$);
62
62
  sub WriteExif($$$);
@@ -265,6 +265,7 @@ sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; }
265
265
  32892 => 'Sequential Color Filter', #JR (Sony ARQ)
266
266
  34892 => 'Linear Raw', #2
267
267
  51177 => 'Depth Map', # (DNG 1.5)
268
+ 52527 => 'Semantic Mask', # (DNG 1.6)
268
269
  );
269
270
 
270
271
  %orientation = (
@@ -291,6 +292,7 @@ sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; }
291
292
  9 => 'Depth map of reduced-resolution image', # (DNG 1.5)
292
293
  16 => 'Enhanced image data', # (DNG 1.5)
293
294
  0x10001 => 'Alternate reduced-resolution image', # (DNG 1.2)
295
+ 0x10004 => 'Semantic Mask', # (DNG 1.6)
294
296
  0xffffffff => 'invalid', #(found in E5700 NEF's)
295
297
  BITMASK => {
296
298
  0 => 'Reduced resolution',
@@ -366,6 +368,7 @@ my %opcodeInfo = (
366
368
  11 => 'DeltaPerColumn',
367
369
  12 => 'ScalePerRow',
368
370
  13 => 'ScalePerColumn',
371
+ 14 => 'WarpRectilinear2', # (DNG 1.6)
369
372
  },
370
373
  PrintConvInv => undef, # (so the inverse conversion is not performed)
371
374
  );
@@ -3038,12 +3041,12 @@ my %opcodeInfo = (
3038
3041
  },
3039
3042
  },
3040
3043
  #
3041
- # DNG tags 0xc6XX and 0xc7XX (ref 2 unless otherwise stated)
3044
+ # DNG tags 0xc6XX, 0xc7XX and 0xcdXX (ref 2 unless otherwise stated)
3042
3045
  #
3043
3046
  0xc612 => {
3044
3047
  Name => 'DNGVersion',
3045
3048
  Notes => q{
3046
- tags 0xc612-0xc7b5 are defined by the DNG specification unless otherwise
3049
+ tags 0xc612-0xcd3b are defined by the DNG specification unless otherwise
3047
3050
  noted. See L<https://helpx.adobe.com/photoshop/digital-negative.html> for
3048
3051
  the specification
3049
3052
  },
@@ -4041,6 +4044,97 @@ my %opcodeInfo = (
4041
4044
  Protected => 1,
4042
4045
  WriteGroup => 'IFD0',
4043
4046
  },
4047
+ 0xcd2d => { # DNG 1.6
4048
+ Name => 'ProfileGainTableMap',
4049
+ Writable => 'undef',
4050
+ WriteGroup => 'SubIFD',
4051
+ Protected => 1,
4052
+ Binary => 1,
4053
+ },
4054
+ 0xcd2e => { # DNG 1.6
4055
+ Name => 'SemanticName',
4056
+ # Writable => 'string',
4057
+ WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4058
+ },
4059
+ 0xcd30 => { # DNG 1.6
4060
+ Name => 'SemanticInstanceIFD',
4061
+ # Writable => 'string',
4062
+ WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4063
+ },
4064
+ 0xcd31 => { # DNG 1.6
4065
+ Name => 'CalibrationIlluminant3',
4066
+ Writable => 'int16u',
4067
+ WriteGroup => 'IFD0',
4068
+ Protected => 1,
4069
+ SeparateTable => 'LightSource',
4070
+ PrintConv => \%lightSource,
4071
+ },
4072
+ 0xcd32 => { # DNG 1.6
4073
+ Name => 'CameraCalibration3',
4074
+ Writable => 'rational64s',
4075
+ WriteGroup => 'IFD0',
4076
+ Count => -1,
4077
+ Protected => 1,
4078
+ },
4079
+ 0xcd33 => { # DNG 1.6
4080
+ Name => 'ColorMatrix3',
4081
+ Writable => 'rational64s',
4082
+ WriteGroup => 'IFD0',
4083
+ Count => -1,
4084
+ Protected => 1,
4085
+ },
4086
+ 0xcd34 => { # DNG 1.6
4087
+ Name => 'ForwardMatrix3',
4088
+ Writable => 'rational64s',
4089
+ WriteGroup => 'IFD0',
4090
+ Count => -1,
4091
+ Protected => 1,
4092
+ },
4093
+ 0xcd35 => { # DNG 1.6
4094
+ Name => 'IlluminantData1',
4095
+ Writable => 'undef',
4096
+ WriteGroup => 'IFD0',
4097
+ Protected => 1,
4098
+ },
4099
+ 0xcd36 => { # DNG 1.6
4100
+ Name => 'IlluminantData2',
4101
+ Writable => 'undef',
4102
+ WriteGroup => 'IFD0',
4103
+ Protected => 1,
4104
+ },
4105
+ 0xcd37 => { # DNG 1.6
4106
+ Name => 'IlluminantData3',
4107
+ Writable => 'undef',
4108
+ WriteGroup => 'IFD0',
4109
+ Protected => 1,
4110
+ },
4111
+ 0xcd38 => { # DNG 1.6
4112
+ Name => 'MaskSubArea',
4113
+ # Writable => 'int32u',
4114
+ WriteGroup => 'SubIFD', #? (NC) Semantic Mask IFD (only for Validate)
4115
+ Count => 4,
4116
+ },
4117
+ 0xcd39 => { # DNG 1.6
4118
+ Name => 'ProfileHueSatMapData3',
4119
+ %longBin,
4120
+ Writable => 'float',
4121
+ WriteGroup => 'IFD0',
4122
+ Count => -1,
4123
+ Protected => 1,
4124
+ },
4125
+ 0xcd3a => { # DNG 1.6
4126
+ Name => 'ReductionMatrix3',
4127
+ Writable => 'rational64s',
4128
+ WriteGroup => 'IFD0',
4129
+ Count => -1,
4130
+ Protected => 1,
4131
+ },
4132
+ 0xcd3b => { # DNG 1.6
4133
+ Name => 'RGBTables',
4134
+ Writable => 'undef',
4135
+ WriteGroup => 'IFD0',
4136
+ Protected => 1,
4137
+ },
4044
4138
  0xea1c => { #13
4045
4139
  Name => 'Padding',
4046
4140
  Binary => 1,
@@ -4722,11 +4816,23 @@ my %subSecConv = (
4722
4816
  },
4723
4817
  GPSPosition => {
4724
4818
  Groups => { 2 => 'Location' },
4819
+ Writable => 1,
4820
+ WriteAlso => {
4821
+ GPSLatitude => '$val =~ /(.*?)( ?[NS])?,/ ? $1 : undef',
4822
+ GPSLatitudeRef => '$val =~ /(-?)(.*?) ?([NS]?),/ ? ($3 || ($1 ? "S" : "N")) : undef',
4823
+ GPSLongitude => '$val =~ /, ?(.*?)( ?[EW]?)$/ ? $1 : undef',
4824
+ GPSLongitudeRef => '$val =~ /, ?(-?)(.*?) ?([EW]?)$/ ? ($3 || ($1 ? "W" : "E")) : undef',
4825
+ },
4725
4826
  Require => {
4726
4827
  0 => 'GPSLatitude',
4727
4828
  1 => 'GPSLongitude',
4728
4829
  },
4729
4830
  Priority => 0,
4831
+ Notes => q{
4832
+ when written, writes GPSLatitude, GPSLatitudeRef, GPSLongitude and
4833
+ GPSLongitudeRef. This tag may be written using the same coordinate
4834
+ format as provided by Google Maps when right-clicking on a location
4835
+ },
4730
4836
  ValueConv => '(length($val[0]) or length($val[1])) ? "$val[0] $val[1]" : undef',
4731
4837
  PrintConv => '"$prt[0], $prt[1]"',
4732
4838
  },
@@ -24,7 +24,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
24
24
  use Image::ExifTool::Exif;
25
25
  use Image::ExifTool::GPS;
26
26
 
27
- $VERSION = '1.18';
27
+ $VERSION = '1.19';
28
28
 
29
29
  sub ProcessFLIR($$;$);
30
30
  sub ProcessFLIRText($$$);
@@ -99,7 +99,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' );
99
99
  NOTES => q{
100
100
  Information extracted from FLIR FFF images and the APP1 FLIR segment of JPEG
101
101
  images. These tags may also be extracted from the first frame of an FLIR
102
- SEQ file.
102
+ SEQ file, or all frames if the ExtractEmbedded option is used.
103
103
  },
104
104
  "_header" => {
105
105
  Name => 'FFFHeader',
@@ -1457,6 +1457,7 @@ sub ProcessFLIR($$;$)
1457
1457
  my $raf = $$dirInfo{RAF} || new File::RandomAccess($$dirInfo{DataPt});
1458
1458
  my $verbose = $et->Options('Verbose');
1459
1459
  my $out = $et->Options('TextOut');
1460
+ my $base = $raf->Tell();
1460
1461
  my ($i, $hdr, $buff, $rec);
1461
1462
 
1462
1463
  # read and verify FFF header
@@ -1485,15 +1486,18 @@ sub ProcessFLIR($$;$)
1485
1486
  my $ver = Get32u(\$hdr, 0x14);
1486
1487
  last if $ver >= 100 and $ver < 200; # (have seen 100 and 101 - PH)
1487
1488
  ToggleByteOrder();
1488
- $i and $et->Warn("Unsupported FLIR $type version"), return 1;
1489
+ next unless $i;
1490
+ return 0 if $$et{DOC_NUM};
1491
+ $et->Warn("Unsupported FLIR $type version");
1492
+ return 1;
1489
1493
  }
1490
1494
 
1491
1495
  # read the FLIR record directory
1492
1496
  my $pos = Get32u(\$hdr, 0x18);
1493
1497
  my $num = Get32u(\$hdr, 0x1c);
1494
- unless ($raf->Seek($pos) and $raf->Read($buff, $num * 0x20) == $num * 0x20) {
1498
+ unless ($raf->Seek($base+$pos) and $raf->Read($buff, $num * 0x20) == $num * 0x20) {
1495
1499
  $et->Warn('Truncated FLIR FFF directory');
1496
- return 1;
1500
+ return $$et{DOC_NUM} ? 0 : 1;
1497
1501
  }
1498
1502
 
1499
1503
  unless ($tagTablePtr) {
@@ -1504,6 +1508,7 @@ sub ProcessFLIR($$;$)
1504
1508
  # process the header data
1505
1509
  $et->HandleTag($tagTablePtr, '_header', $hdr);
1506
1510
 
1511
+ my $success = 1;
1507
1512
  my $oldIndent = $$et{INDENT};
1508
1513
  $$et{INDENT} .= '| ';
1509
1514
  $et->VerboseDir($type, $num);
@@ -1533,12 +1538,22 @@ sub ProcessFLIR($$;$)
1533
1538
  $verbose and printf $out "%s%d) FLIR Record 0x%.2x, offset 0x%.4x, length 0x%.4x\n",
1534
1539
  $$et{INDENT}, $i, $recType, $recPos, $recLen;
1535
1540
 
1536
- unless ($raf->Seek($recPos) and $raf->Read($rec, $recLen) == $recLen) {
1537
- $et->Warn('Invalid FLIR record');
1541
+ # skip RawData records for embedded documents
1542
+ if ($recType == 1 and $$et{DOC_NUM}) {
1543
+ $raf->Seek($base+$recPos+$recLen) or $success = 0, last;
1544
+ next;
1545
+ }
1546
+ unless ($raf->Seek($base+$recPos) and $raf->Read($rec, $recLen) == $recLen) {
1547
+ if ($$et{DOC_NUM}) {
1548
+ $success = 0; # abort processing more documents
1549
+ } else {
1550
+ $et->Warn('Invalid FLIR record');
1551
+ }
1538
1552
  last;
1539
1553
  }
1540
1554
  if ($$tagTablePtr{$recType}) {
1541
1555
  $et->HandleTag($tagTablePtr, $recType, undef,
1556
+ Base => $base,
1542
1557
  DataPt => \$rec,
1543
1558
  DataPos => $recPos,
1544
1559
  Start => 0,
@@ -1550,7 +1565,17 @@ sub ProcessFLIR($$;$)
1550
1565
  }
1551
1566
  delete $$et{SET_GROUP0};
1552
1567
  $$et{INDENT} = $oldIndent;
1553
- return 1;
1568
+
1569
+ # extract information from subsequent frames in SEQ file if ExtractEmbedded is used
1570
+ if ($$dirInfo{RAF} and $et->Options('ExtractEmbedded') and not $$et{DOC_NUM}) {
1571
+ for (;;) {
1572
+ $$et{DOC_NUM} = $$et{DOC_COUNT} + 1;
1573
+ last unless ProcessFLIR($et, $dirInfo, $tagTablePtr);
1574
+ # (DOC_COUNT will be incremented automatically if we extracted any tags)
1575
+ }
1576
+ delete $$et{DOC_NUM};
1577
+ }
1578
+ return $success;
1554
1579
  }
1555
1580
 
1556
1581
  #------------------------------------------------------------------------------