exiftool_vendored 12.25.0 → 12.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +114 -4
  3. data/bin/MANIFEST +11 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +44 -43
  7. data/bin/arg_files/xmp2exif.args +2 -1
  8. data/bin/config_files/convert_regions.config +25 -14
  9. data/bin/config_files/example.config +1 -1
  10. data/bin/exiftool +72 -56
  11. data/bin/fmt_files/gpx.fmt +1 -1
  12. data/bin/fmt_files/gpx_wpt.fmt +1 -1
  13. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +10 -2
  14. data/bin/lib/Image/ExifTool/CBOR.pm +277 -0
  15. data/bin/lib/Image/ExifTool/Canon.pm +25 -18
  16. data/bin/lib/Image/ExifTool/DPX.pm +13 -2
  17. data/bin/lib/Image/ExifTool/Exif.pm +11 -6
  18. data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
  19. data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
  20. data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
  21. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  22. data/bin/lib/Image/ExifTool/ID3.pm +15 -3
  23. data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
  24. data/bin/lib/Image/ExifTool/JSON.pm +4 -2
  25. data/bin/lib/Image/ExifTool/Jpeg2000.pm +58 -26
  26. data/bin/lib/Image/ExifTool/LIF.pm +153 -0
  27. data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
  28. data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
  29. data/bin/lib/Image/ExifTool/MIE.pm +2 -1
  30. data/bin/lib/Image/ExifTool/MRC.pm +1 -1
  31. data/bin/lib/Image/ExifTool/Nikon.pm +15 -4
  32. data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
  33. data/bin/lib/Image/ExifTool/Olympus.pm +5 -2
  34. data/bin/lib/Image/ExifTool/Other.pm +93 -0
  35. data/bin/lib/Image/ExifTool/PDF.pm +9 -12
  36. data/bin/lib/Image/ExifTool/PNG.pm +7 -6
  37. data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
  38. data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
  39. data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
  40. data/bin/lib/Image/ExifTool/QuickTime.pm +103 -24
  41. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
  42. data/bin/lib/Image/ExifTool/README +3 -0
  43. data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
  44. data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
  45. data/bin/lib/Image/ExifTool/Sony.pm +84 -33
  46. data/bin/lib/Image/ExifTool/TagLookup.pm +50 -3
  47. data/bin/lib/Image/ExifTool/TagNames.pod +135 -29
  48. data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
  49. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  50. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
  51. data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
  52. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +11 -4
  53. data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  54. data/bin/lib/Image/ExifTool/Writer.pl +3 -0
  55. data/bin/lib/Image/ExifTool/XMP.pm +17 -5
  56. data/bin/lib/Image/ExifTool/XMP2.pl +2 -1
  57. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  58. data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
  59. data/bin/lib/Image/ExifTool.pm +79 -37
  60. data/bin/lib/Image/ExifTool.pod +62 -60
  61. data/bin/perl-Image-ExifTool.spec +43 -42
  62. data/lib/exiftool_vendored/version.rb +1 -1
  63. metadata +6 -3
@@ -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.34';
59
+ $VERSION = '4.36';
60
60
 
61
61
  sub ProcessExif($$$);
62
62
  sub WriteExif($$$);
@@ -2581,7 +2581,7 @@ my %opcodeInfo = (
2581
2581
  0xa301 => {
2582
2582
  Name => 'SceneType',
2583
2583
  Writable => 'undef',
2584
- ValueConvInv => 'chr($val)',
2584
+ ValueConvInv => 'chr($val & 0xff)',
2585
2585
  PrintConv => {
2586
2586
  1 => 'Directly photographed',
2587
2587
  },
@@ -5918,7 +5918,7 @@ sub ProcessExif($$$)
5918
5918
  my $size = $count * $formatSize[$format];
5919
5919
  my $readSize = $size;
5920
5920
  if ($size > 4) {
5921
- if ($size > 0x7fffffff) {
5921
+ if ($size > 0x7fffffff and (not $tagInfo or not $$tagInfo{ReadFromRAF})) {
5922
5922
  $et->Warn(sprintf("Invalid size (%u) for %s %s",$size,$dir,TagName($tagID,$tagInfo)), $inMakerNotes);
5923
5923
  ++$warnCount;
5924
5924
  next;
@@ -6171,18 +6171,23 @@ sub ProcessExif($$$)
6171
6171
  unless ($bad) {
6172
6172
  # limit maximum length of data to reformat
6173
6173
  # (avoids long delays when processing some corrupted files)
6174
+ my $warned;
6174
6175
  if ($count > 100000 and $formatStr !~ /^(undef|string|binary)$/) {
6175
6176
  my $tagName = $tagInfo ? $$tagInfo{Name} : sprintf('tag 0x%.4x', $tagID);
6176
6177
  # (count of 196608 is typical for ColorMap)
6177
6178
  if ($tagName ne 'TransferFunction' or $count != 196608) {
6178
6179
  my $minor = $count > 2000000 ? 0 : 2;
6179
- next if $et->Warn("Ignoring $dirName $tagName with excessive count", $minor);
6180
+ if ($et->Warn("Ignoring $dirName $tagName with excessive count", $minor)) {
6181
+ next unless $$et{OPTIONS}{HtmlDump};
6182
+ $warned = 1;
6183
+ }
6180
6184
  }
6181
6185
  }
6182
6186
  if ($count > 500 and $formatStr !~ /^(undef|string|binary)$/ and
6183
- (not $tagInfo or $$tagInfo{LongBinary}) and not $$et{OPTIONS}{IgnoreMinorErrors})
6187
+ (not $tagInfo or $$tagInfo{LongBinary} or $warned) and not $$et{OPTIONS}{IgnoreMinorErrors})
6184
6188
  {
6185
- $et->WarnOnce('Not decoding some large array(s). Ignore minor errors to decode', 2);
6189
+ $et->WarnOnce('Not decoding some large array(s). Ignore minor errors to decode', 2) unless $warned;
6190
+ next if $$et{TAGS_FROM_FILE}; # don't generate bogus value when copying tags
6186
6191
  $val = "(large array of $count $formatStr values)";
6187
6192
  } else {
6188
6193
  # convert according to specified format
@@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
21
21
  use Image::ExifTool::Exif;
22
22
  use Image::ExifTool::ASF; # for GetGUID()
23
23
 
24
- $VERSION = '1.38';
24
+ $VERSION = '1.39';
25
25
 
26
26
  sub ProcessFPX($$);
27
27
  sub ProcessFPXR($$$);
@@ -1369,29 +1369,48 @@ sub ReadFPXValue($$$$$;$$)
1369
1369
  my $flags = $type & 0xf000;
1370
1370
  if ($flags) {
1371
1371
  if ($flags == VT_VECTOR) {
1372
- $noPad = 1; # values don't seem to be padded inside vectors
1372
+ $noPad = 1; # values sometimes aren't padded inside vectors!!
1373
1373
  my $size = $oleFormatSize{VT_VECTOR};
1374
- last if $valPos + $size > $dirEnd;
1374
+ if ($valPos + $size > $dirEnd) {
1375
+ $et->WarnOnce('Incorrect FPX VT_VECTOR size');
1376
+ last;
1377
+ }
1375
1378
  $count = Get32u($dataPt, $valPos);
1376
1379
  push @vals, '' if $count == 0; # allow zero-element vector
1377
1380
  $valPos += 4;
1378
1381
  } else {
1379
1382
  # can't yet handle this property flag
1383
+ $et->WarnOnce('Unknown FPX property');
1380
1384
  last;
1381
1385
  }
1382
1386
  }
1383
1387
  unless ($format =~ /^VT_/) {
1384
1388
  my $size = Image::ExifTool::FormatSize($format) * $count;
1385
- last if $valPos + $size > $dirEnd;
1389
+ if ($valPos + $size > $dirEnd) {
1390
+ $et->WarnOnce("Incorrect FPX $format size");
1391
+ last;
1392
+ }
1386
1393
  @vals = ReadValue($dataPt, $valPos, $format, $count, $size);
1387
1394
  # update position to end of value plus padding
1388
1395
  $valPos += ($count * $size + 3) & 0xfffffffc;
1389
1396
  last;
1390
1397
  }
1391
1398
  my $size = $oleFormatSize{$format};
1392
- my ($item, $val);
1399
+ my ($item, $val, $len);
1393
1400
  for ($item=0; $item<$count; ++$item) {
1394
- last if $valPos + $size > $dirEnd;
1401
+ if ($valPos + $size > $dirEnd) {
1402
+ $et->WarnOnce("Truncated FPX $format value");
1403
+ last;
1404
+ }
1405
+ # sometimes VT_VECTOR items are padded to even 4-byte boundaries, and sometimes they aren't
1406
+ if ($noPad and defined $len and $len & 0x03) {
1407
+ my $pad = 4 - ($len & 0x03);
1408
+ if ($valPos + $pad + $size <= $dirEnd) {
1409
+ # skip padding if all zeros
1410
+ $valPos += $pad if substr($$dataPt, $valPos, $pad) eq "\0" x $pad;
1411
+ }
1412
+ }
1413
+ undef $len;
1395
1414
  if ($format eq 'VT_VARIANT') {
1396
1415
  my $subType = Get32u($dataPt, $valPos);
1397
1416
  $valPos += $size;
@@ -1429,9 +1448,12 @@ sub ReadFPXValue($$$$$;$$)
1429
1448
  $val = ($val - 25569) * 24 * 3600 if $val != 0;
1430
1449
  $val = Image::ExifTool::ConvertUnixTime($val);
1431
1450
  } elsif ($format =~ /STR$/) {
1432
- my $len = Get32u($dataPt, $valPos);
1451
+ $len = Get32u($dataPt, $valPos);
1433
1452
  $len *= 2 if $format eq 'VT_LPWSTR'; # convert to byte count
1434
- last if $valPos + $len + 4 > $dirEnd;
1453
+ if ($valPos + $len + 4 > $dirEnd) {
1454
+ $et->WarnOnce("Truncated $format value");
1455
+ last;
1456
+ }
1435
1457
  $val = substr($$dataPt, $valPos + 4, $len);
1436
1458
  if ($format eq 'VT_LPWSTR') {
1437
1459
  # convert wide string from Unicode
@@ -1450,8 +1472,11 @@ sub ReadFPXValue($$$$$;$$)
1450
1472
  # on even 32-bit boundaries, but this isn't always the case)
1451
1473
  $valPos += $noPad ? $len : ($len + 3) & 0xfffffffc;
1452
1474
  } elsif ($format eq 'VT_BLOB' or $format eq 'VT_CF') {
1453
- my $len = Get32u($dataPt, $valPos);
1454
- last if $valPos + $len + 4 > $dirEnd;
1475
+ my $len = Get32u($dataPt, $valPos); # (use local $len because we always expect padding)
1476
+ if ($valPos + $len + 4 > $dirEnd) {
1477
+ $et->WarnOnce("Truncated $format value");
1478
+ last;
1479
+ }
1455
1480
  $val = substr($$dataPt, $valPos + 4, $len);
1456
1481
  # update position for data length plus padding
1457
1482
  # (does this padding disappear in arrays too?)
@@ -489,6 +489,7 @@ my %faceCategories = (
489
489
  3 => 'Electronic Front Curtain', #10
490
490
  },
491
491
  },
492
+ # 0x1100 - This may not work well for newer cameras (ref forum12682)
492
493
  0x1100 => [{
493
494
  Name => 'AutoBracketing',
494
495
  Condition => '$$self{Model} eq "X-T3"',
@@ -28,7 +28,7 @@ use vars qw($VERSION);
28
28
  use Image::ExifTool qw(:Public);
29
29
  use Image::ExifTool::GPS;
30
30
 
31
- $VERSION = '1.64';
31
+ $VERSION = '1.65';
32
32
 
33
33
  sub JITTER() { return 2 } # maximum time jitter
34
34
 
@@ -262,8 +262,10 @@ sub LoadTrackLog($$;$)
262
262
  $param = 'time';
263
263
  } elsif (/^(Pos)?Lat/i) {
264
264
  $param = 'lat';
265
+ /ref$/i and $param .= 'ref';
265
266
  } elsif (/^(Pos)?Lon/i) {
266
267
  $param = 'lon';
268
+ /ref$/i and $param .= 'ref';
267
269
  } elsif (/^(Pos)?Alt/i) {
268
270
  $param = 'alt';
269
271
  } elsif (/^(Angle)?(Heading|Track)/i) {
@@ -453,7 +455,7 @@ DoneFix: $isDate = 1;
453
455
  # (ExifTool enhancements allow for standard tag names or descriptions as the column headings,
454
456
  # add support for time zones and flexible coordinates, and allow new DateTime and Shift columns)
455
457
  #
456
- my ($param, $date, $secs);
458
+ my ($param, $date, $secs, %neg);
457
459
  foreach $param (@csvHeadings) {
458
460
  my $val = shift @vals;
459
461
  last unless defined $val;
@@ -479,6 +481,10 @@ DoneFix: $isDate = 1;
479
481
  }
480
482
  } elsif ($param eq 'lat' or $param eq 'lon') {
481
483
  $$fix{$param} = Image::ExifTool::GPS::ToDegrees($val, 1);
484
+ } elsif ($param eq 'latref') {
485
+ $neg{lat} = 1 if $val =~ /^S/i;
486
+ } elsif ($param eq 'lonref') {
487
+ $neg{lon} = 1 if $val =~ /^W/i;
482
488
  } elsif ($param eq 'runtime') {
483
489
  $date = $trackTime;
484
490
  $secs = $val;
@@ -486,6 +492,11 @@ DoneFix: $isDate = 1;
486
492
  $$fix{$param} = $val;
487
493
  }
488
494
  }
495
+ # make coordinate negative according to reference direction if necessary
496
+ foreach $param (keys %neg) {
497
+ next unless defined $$fix{$param};
498
+ $$fix{$param} = -abs($$fix{$param});
499
+ }
489
500
  if ($date and defined $secs and defined $$fix{lat} and defined $$fix{lon}) {
490
501
  $time = $date + $secs;
491
502
  $$has{alt} = 1 if defined $$fix{alt};
@@ -16,7 +16,7 @@ use vars qw($VERSION);
16
16
  use Image::ExifTool qw(:DataAccess :Utils);
17
17
  use Image::ExifTool::QuickTime;
18
18
 
19
- $VERSION = '1.06';
19
+ $VERSION = '1.07';
20
20
 
21
21
  sub ProcessGoPro($$$);
22
22
  sub ProcessString($$$);
@@ -386,6 +386,21 @@ my %addUnits = (
386
386
  Binary => 1,
387
387
  },
388
388
  # ZFOV (APP6,GPMF) - seen: 148.34, 0 (fmt f, Hero8, Max)
389
+ # the following ref forum12825
390
+ MUID => {
391
+ Name => 'MediaUniqueID',
392
+ PrintConv => q{
393
+ my @a = split ' ', $val;
394
+ $_ = sprintf('%.8x',$_) foreach @a;
395
+ return join('', @a);
396
+ },
397
+ },
398
+ EXPT => 'MaximumShutterAngle',
399
+ MTRX => 'AccelerometerMatrix',
400
+ ORIN => 'InputOrientation',
401
+ ORIO => 'OutputOrientation',
402
+ UNIF => 'InputUniformity',
403
+ SROT => 'SensorReadoutTime',
389
404
  );
390
405
 
391
406
  # GoPro GPS5 tags (ref 2) (Hero5,Hero6)
@@ -18,11 +18,12 @@ use strict;
18
18
  use vars qw($VERSION);
19
19
  use Image::ExifTool qw(:DataAccess :Utils);
20
20
 
21
- $VERSION = '1.55';
21
+ $VERSION = '1.57';
22
22
 
23
23
  sub ProcessID3v2($$$);
24
24
  sub ProcessPrivate($$$);
25
25
  sub ProcessSynText($$$);
26
+ sub ProcessID3Dir($$$);
26
27
  sub ConvertID3v1Text($$);
27
28
  sub ConvertTimeStamp($);
28
29
 
@@ -69,9 +70,10 @@ my %dateTimeConv = (
69
70
  # This table is just for documentation purposes
70
71
  %Image::ExifTool::ID3::Main = (
71
72
  VARS => { NO_ID => 1 },
73
+ PROCESS_PROC => \&ProcessID3Dir, # (used to process 'id3 ' chunk in WAV files)
72
74
  NOTES => q{
73
- ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, AIFF, OGG,
74
- FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple
75
+ ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, WAV, AIFF,
76
+ OGG, FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple
75
77
  languages (eg. Comment and Lyrics) are extracted by specifying the tag name,
76
78
  followed by a dash ('-'), then a 3-character ISO 639-2 language code (eg.
77
79
  "Comment-spa"). See L<http://www.id3.org/> for the official ID3
@@ -1570,6 +1572,16 @@ sub ProcessID3($$)
1570
1572
  return $rtnVal;
1571
1573
  }
1572
1574
 
1575
+ #------------------------------------------------------------------------------
1576
+ # Process ID3 directory
1577
+ # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) dummy tag table ref
1578
+ sub ProcessID3Dir($$$)
1579
+ {
1580
+ my ($et, $dirInfo, $tagTablePtr) = @_;
1581
+ $et->VerboseDir('ID3', undef, length ${$$dirInfo{DataPt}});
1582
+ return ProcessID3($et, $dirInfo);
1583
+ }
1584
+
1573
1585
  #------------------------------------------------------------------------------
1574
1586
  # Extract ID3 information from an MP3 audio file
1575
1587
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -11,7 +11,7 @@ use strict;
11
11
  use vars qw($VERSION);
12
12
  use Image::ExifTool qw(:DataAccess :Utils);
13
13
 
14
- $VERSION = '1.30';
14
+ $VERSION = '1.32';
15
15
 
16
16
  sub ProcessOcad($$$);
17
17
  sub ProcessJPEG_HDR($$$);
@@ -96,6 +96,10 @@ sub ProcessJPEG_HDR($$$);
96
96
  Name => 'Stim',
97
97
  Condition => '$$valPt =~ /^Stim\0/',
98
98
  SubDirectory => { TagTable => 'Image::ExifTool::Stim::Main' },
99
+ }, {
100
+ Name => 'JPS',
101
+ Condition => '$$valPt =~ /^_JPSJPS_/',
102
+ SubDirectory => { TagTable => 'Image::ExifTool::JPEG::JPS' },
99
103
  }, {
100
104
  Name => 'ThermalData', # (written by DJI FLIR models)
101
105
  Condition => '$$self{Make} eq "DJI"',
@@ -287,6 +291,68 @@ sub ProcessJPEG_HDR($$$);
287
291
  }],
288
292
  );
289
293
 
294
+ # JPS APP3 segment (ref http://paulbourke.net/stereographics/stereoimage/)
295
+ %Image::ExifTool::JPEG::JPS = (
296
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
297
+ GROUPS => { 0 => 'APP3', 1 => 'JPS', 2 => 'Image' },
298
+ NOTES => 'Tags found in JPEG Stereo (JPS) images.',
299
+ 0x0a => {
300
+ Name => 'JPSSeparation',
301
+ Format => 'int32u', # (just so we can look ahead to MediaType);
302
+ Notes => 'stereo only',
303
+ RawConv => q{
304
+ $$self{MediaType} = $val & 0xff;
305
+ return undef unless $$self{MediaType} == 1;
306
+ return(($val >> 24) & 0xff);
307
+ },
308
+ },
309
+ 0x08 => {
310
+ Name => 'HdrLength',
311
+ Format => 'int16u',
312
+ Hidden => 1,
313
+ RawConv => '$$self{HdrLength} = $val; undef',
314
+ },
315
+ 0x0b => {
316
+ Name => 'JPSFlags',
317
+ PrintConv => { BITMASK => {
318
+ 0 => 'Half height',
319
+ 1 => 'Half width',
320
+ 2 => 'Left field first',
321
+ }},
322
+ },
323
+ 0x0c => [{
324
+ Name => 'JPSLayout',
325
+ Condition => '$$self{MediaType} == 0',
326
+ Notes => 'mono',
327
+ PrintConv => {
328
+ 0 => 'Both Eyes',
329
+ 1 => 'Left Eye',
330
+ 2 => 'Right Eye',
331
+ },
332
+ },{
333
+ Name => 'JPSLayout',
334
+ Condition => '$$self{MediaType} == 1',
335
+ Notes => 'stereo',
336
+ PrintConv => {
337
+ 1 => 'Interleaved',
338
+ 2 => 'Side By Side',
339
+ 3 => 'Over Under',
340
+ 4 => 'Anaglyph',
341
+ },
342
+ }],
343
+ 0x0d => {
344
+ Name => 'JPSType',
345
+ Hook => '$varSize += $$self{HdrLength} - 4', # comment starts after header block
346
+ PrintConv => { 0 => 'Mono', 1 => 'Stereo' },
347
+ },
348
+ # 0x0e - in16u comment length (ignored -- assume the remainder is all comment)
349
+ # (this is offset if we had a 4-byte JPS header block)
350
+ 0x10 => {
351
+ Name => 'JPSComment',
352
+ Format => 'string',
353
+ },
354
+ );
355
+
290
356
  # EPPIM APP6 (Toshiba PrintIM) segment (ref PH, from PDR-M700 samples)
291
357
  %Image::ExifTool::JPEG::EPPIM = (
292
358
  GROUPS => { 0 => 'APP6', 1 => 'EPPIM', 2 => 'Image' },
@@ -545,7 +611,7 @@ sub ProcessJPEG_HDR($$$);
545
611
  },
546
612
  2 => {
547
613
  Name => 'ImageFormat',
548
- ValueConv => 'chr($val)',
614
+ ValueConv => 'chr($val & 0xff)',
549
615
  PrintConv => { B => 'IMode B' },
550
616
  },
551
617
  3 => {
@@ -14,7 +14,7 @@ use vars qw($VERSION);
14
14
  use Image::ExifTool qw(:DataAccess :Utils);
15
15
  use Image::ExifTool::Import;
16
16
 
17
- $VERSION = '1.03';
17
+ $VERSION = '1.04';
18
18
 
19
19
  sub ProcessJSON($$);
20
20
  sub ProcessTag($$$$%);
@@ -83,7 +83,9 @@ sub ProcessTag($$$$%)
83
83
  FoundTag($et, $tagTablePtr, $tag, $val, %flags, Struct => 1);
84
84
  return unless $et->Options('Struct') > 1;
85
85
  }
86
- foreach (sort keys %$val) {
86
+ # support hashes with ordered keys
87
+ my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
88
+ foreach (@keys) {
87
89
  ProcessTag($et, $tagTablePtr, $tag . ucfirst, $$val{$_}, %flags, Flat => 1);
88
90
  }
89
91
  } elsif (ref $val eq 'ARRAY') {
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.29';
19
+ $VERSION = '1.31';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -116,9 +116,6 @@ my %j2cMarker = (
116
116
  0x76 => 'NLT', # non-linearity point transformation
117
117
  );
118
118
 
119
- my %jumbfTypes = (
120
- );
121
-
122
119
  # JPEG 2000 "box" (ie. atom) names
123
120
  # Note: only tags with a defined "Format" are extracted
124
121
  %Image::ExifTool::Jpeg2000::Main = (
@@ -127,10 +124,13 @@ my %jumbfTypes = (
127
124
  WRITE_PROC => \&ProcessJpeg2000Box,
128
125
  PREFERRED => 1, # always add these tags when writing
129
126
  NOTES => q{
130
- The tags below are extracted from JPEG 2000 images and the JUMBF metadata in
131
- JPEG images. Note that ExifTool currently writes only EXIF, IPTC and XMP
132
- tags in Jpeg2000 images.
127
+ The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG
128
+ images, but not all of these are extracted. Note that ExifTool currently
129
+ writes only EXIF, IPTC and XMP tags in Jpeg2000 images.
133
130
  },
131
+ #
132
+ # NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED!
133
+ #
134
134
  'jP ' => 'JP2Signature', # (ref 1)
135
135
  "jP\x1a\x1a" => 'JP2Signature', # (ref 2)
136
136
  prfl => 'Profile',
@@ -344,6 +344,14 @@ my %jumbfTypes = (
344
344
  Format => 'undef',
345
345
  ValueConv => 'substr($val,16)',
346
346
  },
347
+ {
348
+ Name => 'UUID-C2PAClaimSignature', # (seen in JUMB data of JPEG images)
349
+ Condition => '$$valPt=~/^c2cs\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
350
+ SubDirectory => {
351
+ TagTable => 'Image::ExifTool::CBOR::Main',
352
+ Start => '$valuePtr + 16',
353
+ },
354
+ },
347
355
  {
348
356
  Name => 'UUID-Unknown',
349
357
  },
@@ -386,6 +394,27 @@ my %jumbfTypes = (
386
394
  },
387
395
  SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
388
396
  },
397
+ cbor => {
398
+ Name => 'CBORData',
399
+ Flags => [ 'Binary', 'Protected' ],
400
+ SubDirectory => { TagTable => 'Image::ExifTool::CBOR::Main' },
401
+ },
402
+ bfdb => { # used in JUMBF (see # (used when tag is renamed according to JUMDLabel)
403
+ Name => 'BinaryDataType',
404
+ Notes => 'JUMBF, MIME type and optional file name',
405
+ Format => 'undef',
406
+ # (ignore "toggles" byte and just extract MIME type and file name)
407
+ ValueConv => '$_=substr($val,1); s/\0+$//; s/\0/, /; $_',
408
+ JUMBF_Suffix => 'Type', # (used when tag is renamed according to JUMDLabel)
409
+ },
410
+ bidb => { # used in JUMBF
411
+ Name => 'BinaryData',
412
+ Notes => 'JUMBF',
413
+ Groups => { 2 => 'Preview' },
414
+ Format => 'undef',
415
+ Binary => 1,
416
+ JUMBF_Suffix => 'Data', # (used when tag is renamed according to JUMDLabel)
417
+ },
389
418
  #
390
419
  # stuff seen in JPEG XL images:
391
420
  #
@@ -607,23 +636,24 @@ my %jumbfTypes = (
607
636
  PROCESS_PROC => \&ProcessJUMD,
608
637
  GROUPS => { 0 => 'JUMBF', 1 => 'JUMBF', 2 => 'Image' },
609
638
  NOTES => 'Information extracted from the JUMBF description box.',
610
- 'jumd-type' => {
639
+ 'type' => {
611
640
  Name => 'JUMDType',
612
641
  ValueConv => 'unpack "H*", $val',
613
642
  PrintConv => q{
614
643
  my @a = $val =~ /^(\w{8})(\w{4})(\w{4})(\w{16})$/;
615
644
  return $val unless @a;
616
645
  my $ascii = pack 'H*', $a[0];
617
- $a[0] = $ascii if $ascii =~ /^[a-zA-Z0-9]{4}$/;
646
+ $a[0] = "($ascii)" if $ascii =~ /^[a-zA-Z0-9]{4}$/;
618
647
  return join '-', @a;
619
648
  },
620
649
  # seen:
621
650
  # cacb/cast/caas/cacl/casg/json-00110010800000aa00389b71
622
651
  # 6579d6fbdba2446bb2ac1b82feeb89d1 - JPEG image
623
652
  },
624
- 'jumd-label' => { Name => 'JUMDLabel' },
625
- 'jumd-flags' => {
626
- Name => 'JUMDFlags',
653
+ 'label' => { Name => 'JUMDLabel' },
654
+ 'toggles' => {
655
+ Name => 'JUMDToggles',
656
+ Unknown => 1,
627
657
  PrintConv => { BITMASK => {
628
658
  0 => 'Requestable',
629
659
  1 => 'Label',
@@ -631,8 +661,8 @@ my %jumbfTypes = (
631
661
  3 => 'Signature',
632
662
  }},
633
663
  },
634
- 'jumd-id' => { Name => 'JUMDID', Description => 'JUMD ID' },
635
- 'jumd-sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
664
+ 'id' => { Name => 'JUMDID', Description => 'JUMD ID' },
665
+ 'sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
636
666
  );
637
667
 
638
668
  #------------------------------------------------------------------------------
@@ -675,20 +705,21 @@ sub ProcessJUMD($$$)
675
705
  delete $$et{JUMBFLabel};
676
706
  $$dirInfo{DirLen} < 17 and $et->Warn('Truncated JUMD directory'), return 0;
677
707
  my $type = substr($$dataPt, $pos, 4);
678
- $et->HandleTag($tagTablePtr, 'jumd-type', substr($$dataPt, $pos, 16));
708
+ $et->HandleTag($tagTablePtr, 'type', substr($$dataPt, $pos, 16));
679
709
  $pos += 16;
680
710
  my $flags = Get8u($dataPt, $pos++);
681
- $et->HandleTag($tagTablePtr, 'jumd-flags', $flags);
711
+ $et->HandleTag($tagTablePtr, 'toggles', $flags);
682
712
  if ($flags & 0x02) { # label exists?
683
713
  pos($$dataPt) = $pos;
684
714
  $$dataPt =~ /\0/g or $et->Warn('Missing JUMD label terminator'), return 0;
685
715
  my $len = pos($$dataPt) - $pos;
686
716
  my $name = substr($$dataPt, $pos, $len);
687
- $et->HandleTag($tagTablePtr, 'jumd-label', $name);
717
+ $et->HandleTag($tagTablePtr, 'label', $name);
688
718
  $pos += $len;
689
719
  if ($len) {
690
720
  $name =~ s/[^-_a-zA-Z0-9]([a-z])/\U$1/g; # capitalize characters after illegal characters
691
721
  $name =~ tr/-_a-zA-Z0-9//dc; # remove other illegal characters
722
+ $name =~ s/__/_/; # collapse double underlines
692
723
  $name = ucfirst $name; # capitalize first letter
693
724
  $name = "Tag$name" if length($name) < 2; # must at least 2 characters long
694
725
  $$et{JUMBFLabel} = $name;
@@ -696,12 +727,12 @@ sub ProcessJUMD($$$)
696
727
  }
697
728
  if ($flags & 0x04) { # ID exists?
698
729
  $pos + 4 > $end and $et->Warn('Missing JUMD ID'), return 0;
699
- $et->HandleTag($tagTablePtr, 'jumd-id', Get32u($dataPt, $pos));
730
+ $et->HandleTag($tagTablePtr, 'id', Get32u($dataPt, $pos));
700
731
  $pos += 4;
701
732
  }
702
733
  if ($flags & 0x08) { # signature exists?
703
734
  $pos + 32 > $end and $et->Warn('Missing JUMD signature'), return 0;
704
- $et->HandleTag($tagTablePtr, 'jumd-sig', substr($$dataPt, $pos, 32));
735
+ $et->HandleTag($tagTablePtr, 'sig', substr($$dataPt, $pos, 32));
705
736
  $pos += 32;
706
737
  }
707
738
  $pos == $end or $et->Warn('Extra data in JUMD box'." $pos $end", 1);
@@ -931,6 +962,14 @@ sub ProcessJpeg2000Box($$$)
931
962
  }
932
963
  }
933
964
  }
965
+ # create new tag for JUMBF data values with name corresponding to JUMBFLabel
966
+ if ($tagInfo and $$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) {
967
+ $tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} . ($$tagInfo{JUMBF_Suffix} || '') };
968
+ delete $$tagInfo{Description};
969
+ AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo);
970
+ delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data)
971
+ $$tagInfo{TagID} = $boxID;
972
+ }
934
973
  if ($verbose) {
935
974
  $et->VerboseInfo($boxID, $tagInfo,
936
975
  Table => $tagTablePtr,
@@ -941,13 +980,6 @@ sub ProcessJpeg2000Box($$$)
941
980
  );
942
981
  next unless $tagInfo;
943
982
  }
944
- # create new tag for JUMBF data values with name corresponding to JUMBFLabel
945
- if ($$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) {
946
- $tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} };
947
- AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo);
948
- delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data)
949
- $$tagInfo{TagID} = $boxID;
950
- }
951
983
  if ($$tagInfo{SubDirectory}) {
952
984
  my $subdir = $$tagInfo{SubDirectory};
953
985
  my $subdirStart = $valuePtr;