exiftool_vendored 12.34.0 → 12.35.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab3c45f9ea8ba8771084a357dc9e5b8deb7eef973b4edee129f974899a412bf2
4
- data.tar.gz: 12d0a164cf31c3283809dae4e5cccd9bb8b7e667216fe6b1f104c0247da3b62d
3
+ metadata.gz: 52e82f9009ab10204f4fcf27c5e257b9ef7d78a132dd3ff487f6f4057f0277cc
4
+ data.tar.gz: 43b4bed4388b6518e0350f69d9858dcd74c981851ac681ee0b0fdd1a2fba0052
5
5
  SHA512:
6
- metadata.gz: 57a16498bc569f83ec79e0ca6179b073ebe2b8c468ba93c397d44f90259d28a37390a1a2b06770b4ffc8c36c7e63abfa055e82771b6cddfac3f6e1de78c7f3b9
7
- data.tar.gz: 7eec435a6bd1a16cf49aa3324a0633cec6a319e9358ff5277c6601b509b9c967636092137237cfa9c265b28b0fd7209719f4b90432b8761c25d47d626b5f679d
6
+ metadata.gz: ea35dbefffadeb4fb7e3b8871acffbc2408ad1e63e7c2995ede7dc6baf7b4f98b1ff377d49677f0e36755ec643a6f12f2a31889106cb703c409128ca0af25a9e
7
+ data.tar.gz: a6f19417b3eed9bf9f8caaba0f84b100a05a968aded523453b865205cee7c7756da5d17f9a6b99d1bd3e7d1194c3a74247531c832dd88d40d6d468a5dba2861d
data/bin/Changes CHANGED
@@ -7,11 +7,31 @@ RSS feed: https://exiftool.org/rss.xml
7
7
  Note: The most recent production release is Version 12.30. (Other versions are
8
8
  considered development releases, and are not uploaded to MetaCPAN.)
9
9
 
10
+ Nov. 11, 2021 - Version 12.35
11
+
12
+ - Added ability to write ICC_Profile (and other color specifications) to
13
+ Jpeg2000 images
14
+ - Added %o code to -W option format string
15
+ - Added %f code to -d option for fractional seconds
16
+ - Added a couple of new Sony LensType values (thanks Jos Roost)
17
+ - Added a new Nikon LensID
18
+ - Added a new CanonModelID
19
+ - Decode more Nikon MakerNotes tags for some new models (thanks Warren Hatch)
20
+ - Extract ThumbnailImage from some DJI drone videos
21
+ - Enhanced -ee option to extract metadata from all frames in a SEQ file
22
+ - Patched to avoid possible "Use of uninitialized value" runtime warning
23
+ - Fixed a couple if misspelt new ICC_Profile tag names (thanks Herb)
24
+ - Fixed problem generating the correct file extension when extracting
25
+ OriginalRawImage from a DNG file using the -W option with the %s format code
26
+ - Fixed bug introduced in 11.91 where exiftool couldn't find its libraries
27
+ when running via a link. Also it was looking for the config file in the
28
+ directory of the link, and this was changed to the target directory
29
+
10
30
  Oct. 27, 2021 - Version 12.34
11
31
 
12
32
  - Added support for ICC.2:2019 (Profile version 5.0.0 - iccMAX) color profiles
13
33
  - Added ability to detect/delete a Windows Zone.Identifier alternate data
14
- stream (ADS) via the new ZoneIdentifier tag
34
+ stream (ADS) via the new ZoneIdentifier tag (thanks Alex Xu)
15
35
  - Added support for the Sony ILCE-7M4 (thanks Jos Roost)
16
36
  - Added a new Sony lens (thanks LibRaw and Jos Roost)
17
37
  - Added a new SonyModelID (thanks LibRaw)
@@ -19,7 +39,7 @@ Oct. 27, 2021 - Version 12.34
19
39
  - Improved handling of some SVG files
20
40
  - Patched -overwrite_original_in_place option to open the output file in
21
41
  update mode rather than write mode (to allow some write optimizations on
22
- certain filesystems)
42
+ certain filesystems) (thanks Joel Low)
23
43
  - Fixed case of tag ID for new XMP-iptcExt:EventID (thanks Michael Steidl)
24
44
  - Fixed problem extracting ICC_Profile information from some PDF files
25
45
  - API Changes:
@@ -635,6 +655,7 @@ Mar. 19, 2020 - Version 11.92
635
655
 
636
656
  Mar. 5, 2020 - Version 11.91
637
657
 
658
+ - Added undocumented -xpath option for use by alternate Windows version
638
659
  - Decode a couple of new Panasonic tags
639
660
  - Documented -ec option (available since version 11.54)
640
661
  - Reverted -htmlDump fix of 11.90 because it broke more than it fixed, and
data/bin/META.json CHANGED
@@ -47,5 +47,5 @@
47
47
  }
48
48
  },
49
49
  "release_status" : "stable",
50
- "version" : "12.34"
50
+ "version" : "12.35"
51
51
  }
data/bin/META.yml CHANGED
@@ -28,4 +28,4 @@ recommends:
28
28
  Time::HiRes: 0
29
29
  requires:
30
30
  perl: 5.004
31
- version: 12.34
31
+ version: 12.35
data/bin/README CHANGED
@@ -107,8 +107,8 @@ your home directory, then you would type the following commands in a
107
107
  terminal window to extract and run ExifTool:
108
108
 
109
109
  cd ~/Desktop
110
- gzip -dc Image-ExifTool-12.34.tar.gz | tar -xf -
111
- cd Image-ExifTool-12.34
110
+ gzip -dc Image-ExifTool-12.35.tar.gz | tar -xf -
111
+ cd Image-ExifTool-12.35
112
112
  ./exiftool t/images/ExifTool.jpg
113
113
 
114
114
  Note: These commands extract meta information from one of the test images.
data/bin/exiftool CHANGED
@@ -10,24 +10,26 @@
10
10
  use strict;
11
11
  require 5.004;
12
12
 
13
- my $version = '12.34';
13
+ my $version = '12.35';
14
14
 
15
15
  # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
16
- my $exeDir;
17
16
  BEGIN {
18
17
  # (undocumented -xpath option added in 11.91, must come before other options)
19
- $Image::ExifTool::exePath = @ARGV && lc($ARGV[0]) eq '-xpath' && shift() ? $^X : $0;
18
+ my $exePath = @ARGV && lc($ARGV[0]) eq '-xpath' && shift() ? $^X : $0;
20
19
  # get exe directory
21
- $exeDir = ($Image::ExifTool::exePath =~ /(.*)[\\\/]/) ? $1 : '.';
20
+ my $exeDir = ($exePath =~ /(.*)[\\\/]/) ? $1 : '.';
21
+ my $incDir = ($0 =~ /(.*)[\\\/]/) ? "$1/lib" : './lib';
22
22
  if (-l $0) {
23
23
  my $lnk = eval { readlink $0 };
24
24
  if (defined $lnk) {
25
25
  my $lnkDir = ($lnk =~ /(.*)[\\\/]/) ? $1 : '.';
26
26
  $exeDir = (($lnk =~ m(^/)) ? '' : $exeDir . '/') . $lnkDir;
27
+ $incDir = "$exeDir/lib";
27
28
  }
28
29
  }
30
+ $Image::ExifTool::exeDir = $exeDir; # use our exeDir for loading config file
29
31
  # add lib directory at start of include path
30
- unshift @INC, ($0 =~ /(.*)[\\\/]/) ? "$1/lib" : './lib';
32
+ unshift @INC, $incDir;
31
33
  # load or disable config file if specified
32
34
  if (@ARGV and lc($ARGV[0]) eq '-config') {
33
35
  shift;
@@ -757,7 +759,7 @@ for (;;) {
757
759
  }
758
760
  my $fp = ($stayOpen == 1 ? \*STAYOPEN : \*ARGFILE);
759
761
  unless ($mt->Open($fp, $argFile)) {
760
- unless ($argFile !~ /^\// and $mt->Open($fp, "$exeDir/$argFile")) {
762
+ unless ($argFile !~ /^\// and $mt->Open($fp, "$Image::ExifTool::exeDir/$argFile")) {
761
763
  Error "Error opening arg file $argFile\n";
762
764
  $badCmd = 1;
763
765
  next
@@ -1235,7 +1237,7 @@ for (;;) {
1235
1237
  $textOverwrite += 2 if $t2 =~ /\+/; # append
1236
1238
  if ($t1 ne 'W' and lc($t1) ne 'tagout') {
1237
1239
  undef $tagOut;
1238
- } elsif ($textOverwrite >= 2 and $textOut !~ /%[-+]?\d*[.:]?\d*[lu]?[tgs]/) {
1240
+ } elsif ($textOverwrite >= 2 and $textOut !~ /%[-+]?\d*[.:]?\d*[lu]?[tgso]/) {
1239
1241
  $tagOut = 0; # append tags to one file
1240
1242
  } else {
1241
1243
  $tagOut = 1; # separate file for each tag
@@ -2365,7 +2367,8 @@ TAG: foreach $tag (@foundTags) {
2365
2367
  }
2366
2368
  my @groups = $et->GetGroup($tag);
2367
2369
  $outfile and close($fp), undef($tmpText); # (shouldn't happen)
2368
- ($fp, $outfile, $append) = OpenOutputFile($orig, $tagName, \@groups, $ext);
2370
+ my $org = $et->GetValue('OriginalRawFileName') || $et->GetValue('OriginalFileName');
2371
+ ($fp, $outfile, $append) = OpenOutputFile($orig, $tagName, \@groups, $ext, $org);
2369
2372
  $fp or ++$countBad, next TAG;
2370
2373
  $tmpText = $outfile unless $append;
2371
2374
  }
@@ -3943,7 +3946,7 @@ sub SuggestedExtension($$$)
3943
3946
  $ext = 'xml';
3944
3947
  } elsif ($$valPt =~ /^RIFF....WAVE/s) {
3945
3948
  $ext = 'wav';
3946
- } elsif ($tag eq 'OriginalRawFileData' and defined($ext = $et->GetValue('OriginalRawFileName'))) {
3949
+ } elsif ($tag eq 'OriginalRawImage' and defined($ext = $et->GetValue('OriginalRawFileName'))) {
3947
3950
  $ext =~ s/^.*\.//s;
3948
3951
  $ext = $ext ? lc($ext) : 'raw';
3949
3952
  } elsif ($tag eq 'EXIF') {
@@ -3995,14 +3998,15 @@ sub LoadPrintFormat($)
3995
3998
  # A sort of sprintf for filenames
3996
3999
  # Inputs: 0) format string (%d=dir, %f=file name, %e=ext),
3997
4000
  # 1) source filename or undef to test format string
3998
- # 2-4) [%t %g %s only] tag name, ref to array of group names, suggested extension
4001
+ # 2-4) [%t %g %s %o only] tag name, ref to array of group names,
4002
+ # suggested extension, original raw file name
3999
4003
  # Returns: new filename or undef on error (or if no file and fmt contains token)
4000
4004
  sub FilenameSPrintf($;$@)
4001
4005
  {
4002
4006
  my ($fmt, $file, @extra) = @_;
4003
4007
  local $_;
4004
4008
  # return format string straight away if no tokens
4005
- return $fmt unless $fmt =~ /%[-+]?\d*[.:]?\d*[lu]?[dDfFeEtgs]/;
4009
+ return $fmt unless $fmt =~ /%[-+]?\d*[.:]?\d*[lu]?[dDfFeEtgso]/;
4006
4010
  return undef unless defined $file;
4007
4011
  CleanFilename($file); # make sure we are using forward slashes
4008
4012
  # split filename into directory, file, extension
@@ -4016,9 +4020,9 @@ sub FilenameSPrintf($;$@)
4016
4020
  }
4017
4021
  $part{F} = $part{f} . $part{E};
4018
4022
  ($part{D} = $part{d}) =~ s{/+$}{};
4019
- @part{qw(t g s)} = @extra;
4023
+ @part{qw(t g s o)} = @extra;
4020
4024
  my ($filename, $pos) = ('', 0);
4021
- while ($fmt =~ /(%([-+]?)(\d*)([.:]?)(\d*)([lu]?)([dDfFeEtgs]))/g) {
4025
+ while ($fmt =~ /(%([-+]?)(\d*)([.:]?)(\d*)([lu]?)([dDfFeEtgso]))/g) {
4022
4026
  $filename .= substr($fmt, $pos, pos($fmt) - $pos - length($1));
4023
4027
  $pos = pos($fmt);
4024
4028
  my ($sign, $wid, $dot, $skip, $mod, $code) = ($2, $3, $4, $5 || 0, $6, $7);
@@ -4181,7 +4185,7 @@ sub OpenOutputFile($;@)
4181
4185
  if ($textOut) {
4182
4186
  $outfile = $file;
4183
4187
  CleanFilename($outfile);
4184
- if ($textOut =~ /%[-+]?\d*[.:]?\d*[lun]?[dDfFeEtgscC]/ or defined $tagOut) {
4188
+ if ($textOut =~ /%[-+]?\d*[.:]?\d*[lun]?[dDfFeEtgsocC]/ or defined $tagOut) {
4185
4189
  # make filename from printf-like $textOut
4186
4190
  $outfile = FilenameSPrintf($textOut, $file, @args);
4187
4191
  return () unless defined $outfile;
@@ -5167,9 +5171,11 @@ various components of a date/time value. The specifics of the I<FMT> syntax
5167
5171
  are system dependent -- consult the C<strftime> man page on your system for
5168
5172
  details. The default format is equivalent to "%Y:%m:%d %H:%M:%S". This
5169
5173
  option has no effect on date-only or time-only tags and ignores timezone
5170
- information if present. Only one B<-d> option may be used per command.
5171
- Requires POSIX::strptime or Time::Piece for the inversion conversion when
5172
- writing.
5174
+ information if present. ExifTool adds a C<%f> format code to represent
5175
+ fractional seconds, and supports an optional width to specify the number of
5176
+ digits after the decimal point (eg. C<%3f> would give something like
5177
+ C<.437>). Only one B<-d> option may be used per command. Requires
5178
+ POSIX::strptime or Time::Piece for the inversion conversion when writing.
5173
5179
 
5174
5180
  =item B<-D> (B<-decimal>)
5175
5181
 
@@ -5410,7 +5416,7 @@ with this command:
5410
5416
 
5411
5417
  produces output like this:
5412
5418
 
5413
- -- Generated by ExifTool 12.34 --
5419
+ -- Generated by ExifTool 12.35 --
5414
5420
  File: a.jpg - 2003:10:31 15:44:19
5415
5421
  (f/5.6, 1/60s, ISO 100)
5416
5422
  File: b.jpg - 2006:05:23 11:57:38
@@ -5665,12 +5671,14 @@ between B<-W> and B<-w>:
5665
5671
 
5666
5672
  1) With B<-W>, a new output file is created for each extracted tag.
5667
5673
 
5668
- 2) B<-W> supports three additional format codes: %t, %g and %s represent
5669
- the tag name, group name, and suggested extension for the output file (based
5670
- on the format of the data). The %g code may be followed by a single digit
5671
- to specify the group family number (eg. %g1), otherwise family 0 is assumed.
5672
- The substring width/position/case specifiers may be used with these format
5673
- codes in exactly the same way as with %f and %e.
5674
+ 2) B<-W> supports four additional format codes: %t, %g and %s represent the
5675
+ tag name, group name, and suggested extension for the output file (based on
5676
+ the format of the data), and %o represents the value of the
5677
+ OriginalRawFileName or OriginalFileName tag from the input file (including
5678
+ extension). The %g code may be followed by a single digit to specify the
5679
+ group family number (eg. %g1), otherwise family 0 is assumed. The substring
5680
+ width/position/case specifiers may be used with these format codes in
5681
+ exactly the same way as with %f and %e.
5674
5682
 
5675
5683
  3) The argument for B<-W> is interpreted as a file name if it contains no
5676
5684
  format codes. (For B<-w>, this would be a file extension.) This change
@@ -5690,7 +5698,7 @@ example, the following pairs of commands give the same result:
5690
5698
  4) Adding the B<-v> option to B<-W> sends a list of the tags and output file
5691
5699
  names to the console instead of giving a verbose dump of the entire file.
5692
5700
  (Unless appending all output to one file for each source file by using
5693
- B<-W+> with an output file I<FMT> that does not contain %t, $g or %s.)
5701
+ B<-W+> with an output file I<FMT> that does not contain %t, $g, %s or %o.)
5694
5702
 
5695
5703
  5) Individual list items are stored in separate files when B<-W> is combined
5696
5704
  with B<-b>, but note that for separate files to be created %c or %C must be
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '4.53';
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)
@@ -954,6 +954,7 @@ $VERSION = '4.53';
954
954
  0x80000435 => 'EOS Rebel T8i / 850D / X10i', #JR/PH
955
955
  0x80000436 => 'EOS SL3 / 250D / Kiss X10', #25
956
956
  0x80000437 => 'EOS 90D', #IB
957
+ 0x80000450 => 'EOS R3', #42
957
958
  0x80000453 => 'EOS R6', #PH
958
959
  0x80000467 => 'PowerShot ZOOM',
959
960
  0x80000468 => 'EOS M50 Mark II / Kiss M2', #IB
@@ -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
  #------------------------------------------------------------------------------
@@ -25,7 +25,7 @@ use strict;
25
25
  use vars qw($VERSION);
26
26
  use Image::ExifTool qw(:DataAccess :Utils);
27
27
 
28
- $VERSION = '1.37';
28
+ $VERSION = '1.38';
29
29
 
30
30
  sub ProcessICC($$);
31
31
  sub ProcessICC_Profile($$$);
@@ -549,7 +549,7 @@ my %manuSig = ( #6
549
549
  A2B3 => 'AToB3',
550
550
  A2M0 => 'AToM0',
551
551
  B2A3 => 'BToA3',
552
- bcp0 => 'BRDFColorimetricParameter3Tag',
552
+ bcp0 => 'BRDFColorimetricParam0',
553
553
  bcp1 => 'BRDFColorimetricParam1',
554
554
  bcp2 => 'BRDFColorimetricParam2',
555
555
  bcp3 => 'BRDFColorimetricParam3',
@@ -602,7 +602,7 @@ my %manuSig = ( #6
602
602
  gdb2 => 'GamutBoundaryDescription2',
603
603
  gdb3 => 'GamutBoundaryDescription3',
604
604
  'mdv '=> 'MultiplexDefaultValues',
605
- mcta => 'MultiplixTypeArray',
605
+ mcta => 'MultiplexTypeArray',
606
606
  minf => 'MeasurementInfo',
607
607
  miin => 'MeasurementInputInfo',
608
608
  M2A0 => 'MToA0',
@@ -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.31';
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',
@@ -560,11 +561,31 @@ my %j2cMarker = (
560
561
 
561
562
  %Image::ExifTool::Jpeg2000::ColorSpec = (
562
563
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
564
+ WRITE_PROC => \&Image::ExifTool::WriteBinaryData, # (we don't actually call this)
563
565
  GROUPS => { 2 => 'Image' },
564
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
+ },
565
581
  0 => {
566
582
  Name => 'ColorSpecMethod',
567
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
+ },
568
589
  PrintConv => {
569
590
  1 => 'Enumerated',
570
591
  2 => 'Restricted ICC',
@@ -572,9 +593,15 @@ my %j2cMarker = (
572
593
  4 => 'Vendor Color',
573
594
  },
574
595
  },
575
- 1 => 'ColorSpecPrecedence',
596
+ 1 => {
597
+ Name => 'ColorSpecPrecedence',
598
+ Notes => 'default for writing is 0',
599
+ Protected => 1,
600
+ },
576
601
  2 => {
577
602
  Name => 'ColorSpecApproximation',
603
+ Notes => 'default for writing is 0',
604
+ Protected => 1,
578
605
  PrintConv => {
579
606
  0 => 'Not Specified',
580
607
  1 => 'Accurate',
@@ -599,6 +626,7 @@ my %j2cMarker = (
599
626
  Name => 'ColorSpace',
600
627
  Condition => '$$self{ColorSpecMethod} == 1',
601
628
  Format => 'int32u',
629
+ Protected => 1,
602
630
  PrintConv => { # ref 15444-2 2002-05-15
603
631
  0 => 'Bi-level',
604
632
  1 => 'YCbCr(1)',
@@ -628,6 +656,8 @@ my %j2cMarker = (
628
656
  {
629
657
  Name => 'ColorSpecData',
630
658
  Format => 'undef[$size-3]',
659
+ Writable => 'undef',
660
+ Protected => 1,
631
661
  Binary => 1,
632
662
  },
633
663
  ],
@@ -817,6 +847,48 @@ sub CreateNewBoxes($$)
817
847
  return 1;
818
848
  }
819
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
+
820
892
  #------------------------------------------------------------------------------
821
893
  # Process JPEG 2000 box
822
894
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) Pointer to tag table
@@ -834,7 +906,7 @@ sub ProcessJpeg2000Box($$$)
834
906
  my $raf = $$dirInfo{RAF};
835
907
  my $outfile = $$dirInfo{OutFile};
836
908
  my $dirEnd = $dirStart + $dirLen;
837
- my ($err, $outBuff, $verbose);
909
+ my ($err, $outBuff, $verbose, $doColour);
838
910
 
839
911
  if ($outfile) {
840
912
  unless ($raf) {
@@ -842,13 +914,19 @@ sub ProcessJpeg2000Box($$$)
842
914
  $outBuff = '';
843
915
  $outfile = \$outBuff;
844
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
+ }
845
923
  } else {
846
924
  # (must not set verbose flag when writing!)
847
925
  $verbose = $$et{OPTIONS}{Verbose};
848
926
  $et->VerboseDir($$dirInfo{DirName}) if $verbose;
849
927
  }
850
928
  # loop through all contained boxes
851
- my ($pos, $boxLen);
929
+ my ($pos, $boxLen, $lastBox);
852
930
  for ($pos=$dirStart; ; $pos+=$boxLen) {
853
931
  my ($boxID, $buff, $valuePtr);
854
932
  my $hdrLen = 8; # the box header length
@@ -857,9 +935,7 @@ sub ProcessJpeg2000Box($$$)
857
935
  my $n = $raf->Read($buff,$hdrLen);
858
936
  unless ($n == $hdrLen) {
859
937
  $n and $err = '', last;
860
- if ($outfile) {
861
- CreateNewBoxes($et, $outfile) or $err = 1;
862
- }
938
+ CreateNewBoxes($et, $outfile) or $err = 1 if $outfile;
863
939
  last;
864
940
  }
865
941
  $dataPt = \$buff;
@@ -871,6 +947,17 @@ sub ProcessJpeg2000Box($$$)
871
947
  }
872
948
  $boxLen = unpack("x$pos N",$$dataPt); # (length includes header and data)
873
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;
874
961
  $pos += $hdrLen; # move to end of box header
875
962
  if ($boxLen == 1) {
876
963
  # box header contains an additional 8-byte integer for length
@@ -1009,8 +1096,10 @@ sub ProcessJpeg2000Box($$$)
1009
1096
  # remove this directory from our create list
1010
1097
  delete $$et{AddJp2Dirs}{$$tagInfo{Name}};
1011
1098
  my $newdir;
1012
- # only edit writable UUID and Exif boxes
1013
- 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
+ {
1014
1103
  $newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
1015
1104
  next if defined $newdir and not length $newdir; # next if deleting the box
1016
1105
  } elsif (defined $uuid) {
@@ -1022,6 +1111,11 @@ sub ProcessJpeg2000Box($$$)
1022
1111
  my $boxhdr = pack('N', length($newdir) + 8 + $prefixLen) . $boxID;
1023
1112
  $boxhdr .= substr($$dataPt, $valuePtr, $prefixLen) if $prefixLen;
1024
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
+ }
1025
1119
  } else {
1026
1120
  # extract as a block if specified
1027
1121
  $subdirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract};