exiftool_vendored 12.25.0 → 12.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +174 -7
  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 +118 -92
  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 +16 -3
  14. data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
  15. data/bin/lib/Image/ExifTool/Canon.pm +52 -20
  16. data/bin/lib/Image/ExifTool/Charset.pm +2 -0
  17. data/bin/lib/Image/ExifTool/DPX.pm +13 -2
  18. data/bin/lib/Image/ExifTool/Exif.pm +107 -8
  19. data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
  20. data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
  21. data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
  22. data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
  23. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  24. data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
  25. data/bin/lib/Image/ExifTool/ID3.pm +15 -3
  26. data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
  27. data/bin/lib/Image/ExifTool/JSON.pm +7 -3
  28. data/bin/lib/Image/ExifTool/Jpeg2000.pm +164 -36
  29. data/bin/lib/Image/ExifTool/LIF.pm +153 -0
  30. data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
  31. data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
  32. data/bin/lib/Image/ExifTool/MIE.pm +2 -1
  33. data/bin/lib/Image/ExifTool/MRC.pm +1 -1
  34. data/bin/lib/Image/ExifTool/MacOS.pm +2 -2
  35. data/bin/lib/Image/ExifTool/Nikon.pm +50 -6
  36. data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
  37. data/bin/lib/Image/ExifTool/Olympus.pm +9 -2
  38. data/bin/lib/Image/ExifTool/Other.pm +93 -0
  39. data/bin/lib/Image/ExifTool/PDF.pm +11 -12
  40. data/bin/lib/Image/ExifTool/PNG.pm +7 -6
  41. data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
  42. data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
  43. data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
  44. data/bin/lib/Image/ExifTool/QuickTime.pm +123 -25
  45. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
  46. data/bin/lib/Image/ExifTool/README +9 -2
  47. data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
  48. data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
  49. data/bin/lib/Image/ExifTool/Sony.pm +113 -42
  50. data/bin/lib/Image/ExifTool/TagLookup.pm +4599 -4451
  51. data/bin/lib/Image/ExifTool/TagNames.pod +276 -41
  52. data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
  53. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  54. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
  55. data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
  56. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -4
  57. data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  58. data/bin/lib/Image/ExifTool/Writer.pl +47 -2
  59. data/bin/lib/Image/ExifTool/XMP.pm +32 -12
  60. data/bin/lib/Image/ExifTool/XMP2.pl +5 -2
  61. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  62. data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
  63. data/bin/lib/Image/ExifTool.pm +153 -52
  64. data/bin/lib/Image/ExifTool.pod +70 -60
  65. data/bin/perl-Image-ExifTool.spec +43 -42
  66. data/lib/exiftool_vendored/version.rb +1 -1
  67. metadata +6 -3
@@ -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.05';
18
18
 
19
19
  sub ProcessJSON($$);
20
20
  sub ProcessTag($$$$%);
@@ -83,8 +83,12 @@ 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) {
87
- ProcessTag($et, $tagTablePtr, $tag . ucfirst, $$val{$_}, %flags, Flat => 1);
86
+ # support hashes with ordered keys
87
+ my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
88
+ foreach (@keys) {
89
+ my $tg = $tag . ((/^\d/ and $tag =~ /\d$/) ? '_' : '') . ucfirst;
90
+ $tg =~ s/([^a-zA-Z])([a-z])/$1\U$2/g;
91
+ ProcessTag($et, $tagTablePtr, $tg, $$val{$_}, %flags, Flat => 1);
88
92
  }
89
93
  } elsif (ref $val eq 'ARRAY') {
90
94
  foreach (@$val) {
@@ -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.32';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -42,8 +42,9 @@ my %jp2Map = (
42
42
  'UUID-IPTC' => 'JP2',
43
43
  'UUID-EXIF' => 'JP2',
44
44
  'UUID-XMP' => 'JP2',
45
- # jp2h => 'JP2', (not yet functional)
46
- # ICC_Profile => 'jp2h', (not yet functional)
45
+ jp2h => 'JP2',
46
+ colr => 'jp2h',
47
+ ICC_Profile => 'colr',
47
48
  IFD1 => 'IFD0',
48
49
  EXIF => 'IFD0', # to write EXIF as a block
49
50
  ExifIFD => 'IFD0',
@@ -116,9 +117,6 @@ my %j2cMarker = (
116
117
  0x76 => 'NLT', # non-linearity point transformation
117
118
  );
118
119
 
119
- my %jumbfTypes = (
120
- );
121
-
122
120
  # JPEG 2000 "box" (ie. atom) names
123
121
  # Note: only tags with a defined "Format" are extracted
124
122
  %Image::ExifTool::Jpeg2000::Main = (
@@ -127,10 +125,13 @@ my %jumbfTypes = (
127
125
  WRITE_PROC => \&ProcessJpeg2000Box,
128
126
  PREFERRED => 1, # always add these tags when writing
129
127
  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.
128
+ The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG
129
+ images, but not all of these are extracted. Note that ExifTool currently
130
+ writes only EXIF, IPTC and XMP tags in Jpeg2000 images.
133
131
  },
132
+ #
133
+ # NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED!
134
+ #
134
135
  'jP ' => 'JP2Signature', # (ref 1)
135
136
  "jP\x1a\x1a" => 'JP2Signature', # (ref 2)
136
137
  prfl => 'Profile',
@@ -340,10 +341,20 @@ my %jumbfTypes = (
340
341
  },
341
342
  {
342
343
  Name => 'UUID-Signature', # (seen in JUMB data of JPEG images)
344
+ # (may be able to remove this when JUMBF specification is finalized)
343
345
  Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
344
346
  Format => 'undef',
345
347
  ValueConv => 'substr($val,16)',
346
348
  },
349
+ {
350
+ Name => 'UUID-C2PAClaimSignature', # (seen in incorrectly-formatted JUMB data of JPEG images)
351
+ # (may be able to remove this when JUMBF specification is finalized)
352
+ Condition => '$$valPt=~/^c2cs\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
353
+ SubDirectory => {
354
+ TagTable => 'Image::ExifTool::CBOR::Main',
355
+ Start => '$valuePtr + 16',
356
+ },
357
+ },
347
358
  {
348
359
  Name => 'UUID-Unknown',
349
360
  },
@@ -386,6 +397,27 @@ my %jumbfTypes = (
386
397
  },
387
398
  SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
388
399
  },
400
+ cbor => {
401
+ Name => 'CBORData',
402
+ Flags => [ 'Binary', 'Protected' ],
403
+ SubDirectory => { TagTable => 'Image::ExifTool::CBOR::Main' },
404
+ },
405
+ bfdb => { # used in JUMBF (see # (used when tag is renamed according to JUMDLabel)
406
+ Name => 'BinaryDataType',
407
+ Notes => 'JUMBF, MIME type and optional file name',
408
+ Format => 'undef',
409
+ # (ignore "toggles" byte and just extract MIME type and file name)
410
+ ValueConv => '$_=substr($val,1); s/\0+$//; s/\0/, /; $_',
411
+ JUMBF_Suffix => 'Type', # (used when tag is renamed according to JUMDLabel)
412
+ },
413
+ bidb => { # used in JUMBF
414
+ Name => 'BinaryData',
415
+ Notes => 'JUMBF',
416
+ Groups => { 2 => 'Preview' },
417
+ Format => 'undef',
418
+ Binary => 1,
419
+ JUMBF_Suffix => 'Data', # (used when tag is renamed according to JUMDLabel)
420
+ },
389
421
  #
390
422
  # stuff seen in JPEG XL images:
391
423
  #
@@ -529,11 +561,31 @@ my %jumbfTypes = (
529
561
 
530
562
  %Image::ExifTool::Jpeg2000::ColorSpec = (
531
563
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
564
+ WRITE_PROC => \&Image::ExifTool::WriteBinaryData, # (we don't actually call this)
532
565
  GROUPS => { 2 => 'Image' },
533
566
  FORMAT => 'int8s',
567
+ WRITABLE => 1,
568
+ WRITE_GROUP => 'colr',
569
+ DATAMEMBER => [ 0 ],
570
+ IS_SUBDIR => [ 3 ],
571
+ NOTES => q{
572
+ The table below contains tags in the color specification (colr) box. This
573
+ box may be rewritten by writing either ICC_Profile, ColorSpace or
574
+ ColorSpecData. When writing, any existing colr boxes are replaced with the
575
+ newly created colr box.
576
+
577
+ B<NOTE>: Care must be taken when writing this color specification because
578
+ writing a specification that is incompatible with the image data may make
579
+ the image undisplayable.
580
+ },
534
581
  0 => {
535
582
  Name => 'ColorSpecMethod',
536
583
  RawConv => '$$self{ColorSpecMethod} = $val',
584
+ Protected => 1,
585
+ Notes => q{
586
+ default for writing is 2 when writing ICC_Profile, 1 when writing
587
+ ColorSpace, or 4 when writing ColorSpecData
588
+ },
537
589
  PrintConv => {
538
590
  1 => 'Enumerated',
539
591
  2 => 'Restricted ICC',
@@ -541,9 +593,15 @@ my %jumbfTypes = (
541
593
  4 => 'Vendor Color',
542
594
  },
543
595
  },
544
- 1 => 'ColorSpecPrecedence',
596
+ 1 => {
597
+ Name => 'ColorSpecPrecedence',
598
+ Notes => 'default for writing is 0',
599
+ Protected => 1,
600
+ },
545
601
  2 => {
546
602
  Name => 'ColorSpecApproximation',
603
+ Notes => 'default for writing is 0',
604
+ Protected => 1,
547
605
  PrintConv => {
548
606
  0 => 'Not Specified',
549
607
  1 => 'Accurate',
@@ -568,6 +626,7 @@ my %jumbfTypes = (
568
626
  Name => 'ColorSpace',
569
627
  Condition => '$$self{ColorSpecMethod} == 1',
570
628
  Format => 'int32u',
629
+ Protected => 1,
571
630
  PrintConv => { # ref 15444-2 2002-05-15
572
631
  0 => 'Bi-level',
573
632
  1 => 'YCbCr(1)',
@@ -597,6 +656,8 @@ my %jumbfTypes = (
597
656
  {
598
657
  Name => 'ColorSpecData',
599
658
  Format => 'undef[$size-3]',
659
+ Writable => 'undef',
660
+ Protected => 1,
600
661
  Binary => 1,
601
662
  },
602
663
  ],
@@ -607,23 +668,24 @@ my %jumbfTypes = (
607
668
  PROCESS_PROC => \&ProcessJUMD,
608
669
  GROUPS => { 0 => 'JUMBF', 1 => 'JUMBF', 2 => 'Image' },
609
670
  NOTES => 'Information extracted from the JUMBF description box.',
610
- 'jumd-type' => {
671
+ 'type' => {
611
672
  Name => 'JUMDType',
612
673
  ValueConv => 'unpack "H*", $val',
613
674
  PrintConv => q{
614
675
  my @a = $val =~ /^(\w{8})(\w{4})(\w{4})(\w{16})$/;
615
676
  return $val unless @a;
616
677
  my $ascii = pack 'H*', $a[0];
617
- $a[0] = $ascii if $ascii =~ /^[a-zA-Z0-9]{4}$/;
678
+ $a[0] = "($ascii)" if $ascii =~ /^[a-zA-Z0-9]{4}$/;
618
679
  return join '-', @a;
619
680
  },
620
681
  # seen:
621
682
  # cacb/cast/caas/cacl/casg/json-00110010800000aa00389b71
622
683
  # 6579d6fbdba2446bb2ac1b82feeb89d1 - JPEG image
623
684
  },
624
- 'jumd-label' => { Name => 'JUMDLabel' },
625
- 'jumd-flags' => {
626
- Name => 'JUMDFlags',
685
+ 'label' => { Name => 'JUMDLabel' },
686
+ 'toggles' => {
687
+ Name => 'JUMDToggles',
688
+ Unknown => 1,
627
689
  PrintConv => { BITMASK => {
628
690
  0 => 'Requestable',
629
691
  1 => 'Label',
@@ -631,8 +693,8 @@ my %jumbfTypes = (
631
693
  3 => 'Signature',
632
694
  }},
633
695
  },
634
- 'jumd-id' => { Name => 'JUMDID', Description => 'JUMD ID' },
635
- 'jumd-sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
696
+ 'id' => { Name => 'JUMDID', Description => 'JUMD ID' },
697
+ 'sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
636
698
  );
637
699
 
638
700
  #------------------------------------------------------------------------------
@@ -675,20 +737,21 @@ sub ProcessJUMD($$$)
675
737
  delete $$et{JUMBFLabel};
676
738
  $$dirInfo{DirLen} < 17 and $et->Warn('Truncated JUMD directory'), return 0;
677
739
  my $type = substr($$dataPt, $pos, 4);
678
- $et->HandleTag($tagTablePtr, 'jumd-type', substr($$dataPt, $pos, 16));
740
+ $et->HandleTag($tagTablePtr, 'type', substr($$dataPt, $pos, 16));
679
741
  $pos += 16;
680
742
  my $flags = Get8u($dataPt, $pos++);
681
- $et->HandleTag($tagTablePtr, 'jumd-flags', $flags);
743
+ $et->HandleTag($tagTablePtr, 'toggles', $flags);
682
744
  if ($flags & 0x02) { # label exists?
683
745
  pos($$dataPt) = $pos;
684
746
  $$dataPt =~ /\0/g or $et->Warn('Missing JUMD label terminator'), return 0;
685
747
  my $len = pos($$dataPt) - $pos;
686
748
  my $name = substr($$dataPt, $pos, $len);
687
- $et->HandleTag($tagTablePtr, 'jumd-label', $name);
749
+ $et->HandleTag($tagTablePtr, 'label', $name);
688
750
  $pos += $len;
689
751
  if ($len) {
690
752
  $name =~ s/[^-_a-zA-Z0-9]([a-z])/\U$1/g; # capitalize characters after illegal characters
691
753
  $name =~ tr/-_a-zA-Z0-9//dc; # remove other illegal characters
754
+ $name =~ s/__/_/; # collapse double underlines
692
755
  $name = ucfirst $name; # capitalize first letter
693
756
  $name = "Tag$name" if length($name) < 2; # must at least 2 characters long
694
757
  $$et{JUMBFLabel} = $name;
@@ -696,12 +759,12 @@ sub ProcessJUMD($$$)
696
759
  }
697
760
  if ($flags & 0x04) { # ID exists?
698
761
  $pos + 4 > $end and $et->Warn('Missing JUMD ID'), return 0;
699
- $et->HandleTag($tagTablePtr, 'jumd-id', Get32u($dataPt, $pos));
762
+ $et->HandleTag($tagTablePtr, 'id', Get32u($dataPt, $pos));
700
763
  $pos += 4;
701
764
  }
702
765
  if ($flags & 0x08) { # signature exists?
703
766
  $pos + 32 > $end and $et->Warn('Missing JUMD signature'), return 0;
704
- $et->HandleTag($tagTablePtr, 'jumd-sig', substr($$dataPt, $pos, 32));
767
+ $et->HandleTag($tagTablePtr, 'sig', substr($$dataPt, $pos, 32));
705
768
  $pos += 32;
706
769
  }
707
770
  $pos == $end or $et->Warn('Extra data in JUMD box'." $pos $end", 1);
@@ -784,6 +847,48 @@ sub CreateNewBoxes($$)
784
847
  return 1;
785
848
  }
786
849
 
850
+ #------------------------------------------------------------------------------
851
+ # Create Color Specification Box
852
+ # Inputs: 0) ExifTool object ref, 1) Output file or scalar ref
853
+ # Returns: 1 on success
854
+ sub CreateColorSpec($$)
855
+ {
856
+ my ($et, $outfile) = @_;
857
+ my $meth = $et->GetNewValue('Jpeg2000:ColorSpecMethod');
858
+ my $prec = $et->GetNewValue('Jpeg2000:ColorSpecPrecedence') || 0;
859
+ my $approx = $et->GetNewValue('Jpeg2000:ColorSpecApproximation') || 0;
860
+ my $icc = $et->GetNewValue('ICC_Profile');
861
+ my $space = $et->GetNewValue('Jpeg2000:ColorSpace');
862
+ my $cdata = $et->GetNewValue('Jpeg2000:ColorSpecData');
863
+ unless ($meth) {
864
+ if ($icc) {
865
+ $meth = 2;
866
+ } elsif (defined $space) {
867
+ $meth = 1;
868
+ } elsif (defined $cdata) {
869
+ $meth = 4;
870
+ } else {
871
+ $et->Warn('Color space not defined'), return 0;
872
+ }
873
+ }
874
+ if ($meth eq '1') {
875
+ defined $space or $et->Warn('Must specify ColorSpace'), return 0;
876
+ $cdata = pack('N', $space);
877
+ } elsif ($meth eq '2' or $meth eq '3') {
878
+ defined $icc or $et->Warn('Must specify ICC_Profile'), return 0;
879
+ $cdata = $icc;
880
+ } elsif ($meth eq '4') {
881
+ defined $cdata or $et->Warn('Must specify ColorSpecData'), return 0;
882
+ } else {
883
+ $et->Warn('Unknown ColorSpecMethod'), return 0;
884
+ }
885
+ my $boxhdr = pack('N', length($cdata) + 11) . 'colr';
886
+ Write($outfile, $boxhdr, pack('CCC',$meth,$prec,$approx), $cdata) or return 0;
887
+ ++$$et{CHANGED};
888
+ $et->VPrint(1, " + Jpeg2000:ColorSpec\n");
889
+ return 1;
890
+ }
891
+
787
892
  #------------------------------------------------------------------------------
788
893
  # Process JPEG 2000 box
789
894
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) Pointer to tag table
@@ -801,7 +906,7 @@ sub ProcessJpeg2000Box($$$)
801
906
  my $raf = $$dirInfo{RAF};
802
907
  my $outfile = $$dirInfo{OutFile};
803
908
  my $dirEnd = $dirStart + $dirLen;
804
- my ($err, $outBuff, $verbose);
909
+ my ($err, $outBuff, $verbose, $doColour);
805
910
 
806
911
  if ($outfile) {
807
912
  unless ($raf) {
@@ -809,13 +914,19 @@ sub ProcessJpeg2000Box($$$)
809
914
  $outBuff = '';
810
915
  $outfile = \$outBuff;
811
916
  }
917
+ # determine if we will be writing colr box
918
+ if ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'JP2Header') {
919
+ $doColour = 2 if defined $et->GetNewValue('ColorSpecMethod') or $et->GetNewValue('ICC_Profile') or
920
+ defined $et->GetNewValue('ColorSpecPrecedence') or defined $et->GetNewValue('ColorSpace') or
921
+ defined $et->GetNewValue('ColorSpecApproximation') or defined $et->GetNewValue('ColorSpecData');
922
+ }
812
923
  } else {
813
924
  # (must not set verbose flag when writing!)
814
925
  $verbose = $$et{OPTIONS}{Verbose};
815
926
  $et->VerboseDir($$dirInfo{DirName}) if $verbose;
816
927
  }
817
928
  # loop through all contained boxes
818
- my ($pos, $boxLen);
929
+ my ($pos, $boxLen, $lastBox);
819
930
  for ($pos=$dirStart; ; $pos+=$boxLen) {
820
931
  my ($boxID, $buff, $valuePtr);
821
932
  my $hdrLen = 8; # the box header length
@@ -824,9 +935,7 @@ sub ProcessJpeg2000Box($$$)
824
935
  my $n = $raf->Read($buff,$hdrLen);
825
936
  unless ($n == $hdrLen) {
826
937
  $n and $err = '', last;
827
- if ($outfile) {
828
- CreateNewBoxes($et, $outfile) or $err = 1;
829
- }
938
+ CreateNewBoxes($et, $outfile) or $err = 1 if $outfile;
830
939
  last;
831
940
  }
832
941
  $dataPt = \$buff;
@@ -838,6 +947,17 @@ sub ProcessJpeg2000Box($$$)
838
947
  }
839
948
  $boxLen = unpack("x$pos N",$$dataPt); # (length includes header and data)
840
949
  $boxID = substr($$dataPt, $pos+4, 4);
950
+ # remove old colr boxes if necessary
951
+ if ($doColour and $boxID eq 'colr') {
952
+ if ($doColour == 1) { # did we successfully write the new colr box?
953
+ $et->VPrint(1," - Jpeg2000:ColorSpec\n");
954
+ ++$$et{CHANGED};
955
+ next;
956
+ }
957
+ $et->Warn('Out-of-order colr box encountered');
958
+ undef $doColour;
959
+ }
960
+ $lastBox = $boxID;
841
961
  $pos += $hdrLen; # move to end of box header
842
962
  if ($boxLen == 1) {
843
963
  # box header contains an additional 8-byte integer for length
@@ -931,6 +1051,14 @@ sub ProcessJpeg2000Box($$$)
931
1051
  }
932
1052
  }
933
1053
  }
1054
+ # create new tag for JUMBF data values with name corresponding to JUMBFLabel
1055
+ if ($tagInfo and $$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) {
1056
+ $tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} . ($$tagInfo{JUMBF_Suffix} || '') };
1057
+ delete $$tagInfo{Description};
1058
+ AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo);
1059
+ delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data)
1060
+ $$tagInfo{TagID} = $boxID;
1061
+ }
934
1062
  if ($verbose) {
935
1063
  $et->VerboseInfo($boxID, $tagInfo,
936
1064
  Table => $tagTablePtr,
@@ -941,13 +1069,6 @@ sub ProcessJpeg2000Box($$$)
941
1069
  );
942
1070
  next unless $tagInfo;
943
1071
  }
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
1072
  if ($$tagInfo{SubDirectory}) {
952
1073
  my $subdir = $$tagInfo{SubDirectory};
953
1074
  my $subdirStart = $valuePtr;
@@ -975,8 +1096,10 @@ sub ProcessJpeg2000Box($$$)
975
1096
  # remove this directory from our create list
976
1097
  delete $$et{AddJp2Dirs}{$$tagInfo{Name}};
977
1098
  my $newdir;
978
- # only edit writable UUID and Exif boxes
979
- if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL})) {
1099
+ # only edit writable UUID, Exif and jp2h boxes
1100
+ if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL}) or
1101
+ ($boxID eq 'jp2h' and $$et{EDIT_DIRS}{jp2h}))
1102
+ {
980
1103
  $newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
981
1104
  next if defined $newdir and not length $newdir; # next if deleting the box
982
1105
  } elsif (defined $uuid) {
@@ -988,6 +1111,11 @@ sub ProcessJpeg2000Box($$$)
988
1111
  my $boxhdr = pack('N', length($newdir) + 8 + $prefixLen) . $boxID;
989
1112
  $boxhdr .= substr($$dataPt, $valuePtr, $prefixLen) if $prefixLen;
990
1113
  Write($outfile, $boxhdr, $newdir) or $err = 1;
1114
+ # write new colr box immediately after ihdr
1115
+ if ($doColour and $boxID eq 'ihdr') {
1116
+ # (shouldn't be multiple ihdr boxes, but just in case, write only 1)
1117
+ $doColour = $doColour==2 ? CreateColorSpec($et, $outfile) : 0;
1118
+ }
991
1119
  } else {
992
1120
  # extract as a block if specified
993
1121
  $subdirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract};
@@ -0,0 +1,153 @@
1
+ #------------------------------------------------------------------------------
2
+ # File: LIF.pm
3
+ #
4
+ # Description: Read LIF (Leica Image File) files
5
+ #
6
+ # Revisions: 2021-06-21 - P. Harvey Created
7
+ #------------------------------------------------------------------------------
8
+
9
+ package Image::ExifTool::LIF;
10
+
11
+ use strict;
12
+ use vars qw($VERSION);
13
+ use Image::ExifTool qw(:DataAccess :Utils);
14
+ use Image::ExifTool::XMP;
15
+
16
+ $VERSION = '1.00';
17
+
18
+ %Image::ExifTool::LIF::Main = (
19
+ GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
20
+ PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP,
21
+ VARS => { NO_ID => 1 },
22
+ NOTES => q{
23
+ Tags extracted from Leica Image Format (LIF) imaging files. As well as the
24
+ tags listed below, all available information is extracted from the
25
+ XML-format metadata in the LIF header.
26
+ },
27
+ TimeStampList => {
28
+ Groups => { 2 => 'Time' },
29
+ ValueConv => q{
30
+ my $unixTimeZero = 134774 * 24 * 3600;
31
+ my @vals = split ' ', $val;
32
+ foreach (@vals) {
33
+ $_ = 1e-7 * hex($_);
34
+ # shift from Jan 1, 1601 to Jan 1, 1970
35
+ $_ = Image::ExifTool::ConvertUnixTime($_ - $unixTimeZero);
36
+ }
37
+ return \@vals;
38
+ },
39
+ },
40
+ );
41
+
42
+ #------------------------------------------------------------------------------
43
+ # Shorten obscenely long LIF tag names
44
+ # Inputs: Tag name
45
+ # Returns: Shortened tag name
46
+ sub ShortenTagNames($)
47
+ {
48
+ local $_;
49
+ $_ = shift;
50
+ s/DescriptionDimensionsDimensionDescription/Dimensions/;
51
+ s/DescriptionChannelsChannelDescription/Channel/;
52
+ s/ShutterListShutter/Shutter/;
53
+ s/SettingDefinition/Setting/;
54
+ s/AdditionalZPositionListAdditionalZPosition/AdditionalZPosition/;
55
+ s/LMSDataContainerHeader//g;
56
+ s/FilterWheelWheel/FilterWheel/;
57
+ s/FilterWheelFilter/FilterWheel/;
58
+ s/DetectorListDetector/Detector/;
59
+ s/OnlineDyeSeparationOnlineDyeSeparation/OnlineDyeSeparation/;
60
+ s/AotfListAotf/Aotf/;
61
+ s/SettingAotfLaserLineSetting/SettingAotfLaser/;
62
+ s/DataROISetROISet/DataROISet/;
63
+ s/AdditionalZPosition/AddZPos/;
64
+ s/FRAPplusBlock_FRAPBlock_FRAP_PrePost_Info/FRAP_/;
65
+ s/FRAPplusBlock_FRAPBlock_FRAP_(Master)?/FRAP_/;
66
+ s/LDM_Block_SequentialLDM_Block_Sequential_/LDM_/;
67
+ s/ATLConfocalSetting/ATLConfocal/;
68
+ s/LaserArrayLaser/Laser/;
69
+ s/LDM_Master/LDM_/;
70
+ s/(List)?ATLConfocal/ATL_/;
71
+ s/Separation/Sep/;
72
+ s/BleachPointsElement/BleachPoint/;
73
+ s/BeamPositionBeamPosition/BeamPosition/;
74
+ s/DataROISetPossible(ROI)?/DataROISet/;
75
+ s/RoiElementChildrenElementDataROISingle(Roi)?/Roi/;
76
+ s/InfoLaserLineSettingArrayLaserLineSetting/LastLineSetting/;
77
+ s/FilterWheelWheelNameFilterName/FilterWheelFilterName/;
78
+ s/LUT_ListLut/Lut/;
79
+ s/ROI_ListRoiRoidata/ROI_/;
80
+ s/LaserLineSettingArrayLaserLineSetting/LaserLineSetting/;
81
+ return $_;
82
+ }
83
+
84
+ #------------------------------------------------------------------------------
85
+ # Extract metadata from a LIF image
86
+ # Inputs: 0) ExifTool object reference, 1) dirInfo reference
87
+ # Returns: 1 on success, 0 if this wasn't a valid LIF file
88
+ sub ProcessLIF($$)
89
+ {
90
+ my ($et, $dirInfo) = @_;
91
+ my $raf = $$dirInfo{RAF};
92
+ my $buff;
93
+
94
+ # verify this is a valid LIF file
95
+ return 0 unless $raf->Read($buff, 15) == 15 and $buff =~ /^\x70\0{3}.{4}\x2a.{4}<\0/s;
96
+
97
+ $et->SetFileType();
98
+ SetByteOrder('II');
99
+
100
+ my $size = Get32u(\$buff, 4); # XML chunk size
101
+ my $len = Get32u(\$buff, 9) * 2; # XML data length
102
+
103
+ $size < $len and $et->Error('Corrupted LIF XML block'), return 1;
104
+ $size > 100000000 and $et->Error('LIF XML block too large'), return 1;
105
+
106
+ $raf->Seek(-2, 1) and $raf->Read($buff, $len) == $len or $et->Error('Truncated LIF XML block'), return 1;
107
+
108
+ my $tagTablePtr = GetTagTable('Image::ExifTool::LIF::Main');
109
+
110
+ # convert from UCS2 to UTF8
111
+ my $xml = Image::ExifTool::Decode($et, $buff, 'UCS2', 'II', 'UTF8');
112
+
113
+ my %dirInfo = ( DataPt => \$xml );
114
+
115
+ $$et{XmpIgnoreProps} = [ 'LMSDataContainerHeader', 'Element', 'Children', 'Data', 'Image', 'Attachment' ];
116
+ $$et{ShortenXmpTags} = \&ShortenTagNames;
117
+
118
+ $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
119
+
120
+ return 1;
121
+ }
122
+
123
+ 1; # end
124
+
125
+ __END__
126
+
127
+ =head1 NAME
128
+
129
+ Image::ExifTool::LIF - Read LIF meta information
130
+
131
+ =head1 SYNOPSIS
132
+
133
+ This module is used by Image::ExifTool
134
+
135
+ =head1 DESCRIPTION
136
+
137
+ This module contains definitions required by Image::ExifTool to read
138
+ metadata from Leica Image File (LIF) images.
139
+
140
+ =head1 AUTHOR
141
+
142
+ Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
143
+
144
+ This library is free software; you can redistribute it and/or modify it
145
+ under the same terms as Perl itself.
146
+
147
+ =head1 SEE ALSO
148
+
149
+ L<Image::ExifTool::TagNames/LIF Tags>,
150
+ L<Image::ExifTool(3pm)|Image::ExifTool>
151
+
152
+ =cut
153
+