exiftool-vendored.exe 12.69.0 → 12.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/bin/exiftool_files/Changes +43 -12
  2. package/bin/exiftool_files/README +2 -2
  3. package/bin/exiftool_files/exiftool.pl +13 -13
  4. package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +18 -2
  5. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +63 -16
  6. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +3 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +54 -6
  8. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +82 -3
  9. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +142 -20
  10. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
  11. package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +70 -7
  12. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +1 -1
  13. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +1 -1
  14. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  15. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +2 -2
  16. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +45 -12
  17. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +7 -1
  18. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +8 -13
  19. package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +10 -1
  20. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +31 -4
  21. package/bin/exiftool_files/lib/Image/ExifTool/README +7 -2
  22. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +53 -9
  23. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +95 -34
  24. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6927 -6856
  25. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +435 -304
  26. package/bin/exiftool_files/lib/Image/ExifTool/Text.pm +4 -5
  27. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +6 -5
  28. package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  29. package/bin/exiftool_files/lib/Image/ExifTool/WriteRIFF.pl +9 -3
  30. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +21 -36
  31. package/bin/exiftool_files/lib/Image/ExifTool.pm +59 -33
  32. package/bin/exiftool_files/lib/Image/ExifTool.pod +9 -3
  33. package/package.json +3 -3
@@ -31,10 +31,11 @@ use vars qw($VERSION);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
  use Image::ExifTool::Exif;
33
33
 
34
- $VERSION = '1.90';
34
+ $VERSION = '1.91';
35
35
 
36
36
  sub ProcessFujiDir($$$);
37
37
  sub ProcessFaceRec($$$);
38
+ sub ProcessMRAW($$$);
38
39
 
39
40
  # the following RAF version numbers have been tested for writing:
40
41
  # (as of ExifTool 11.70, this lookup is no longer used if the version number is numerical)
@@ -42,11 +43,12 @@ my %testedRAF = (
42
43
  '0100' => 'E550, E900, F770, S5600, S6000fd, S6500fd, HS10/HS11, HS30, S200EXR, X100, XF1, X-Pro1, X-S1, XQ2 Ver1.00, X-T100, GFX 50R, XF10',
43
44
  '0101' => 'X-E1, X20 Ver1.01, X-T3',
44
45
  '0102' => 'S100FS, X10 Ver1.02',
45
- '0103' => 'IS Pro Ver1.03',
46
+ '0103' => 'IS Pro and X-T5 Ver1.03',
46
47
  '0104' => 'S5Pro Ver1.04',
47
48
  '0106' => 'S5Pro Ver1.06',
48
49
  '0111' => 'S5Pro Ver1.11',
49
50
  '0114' => 'S9600 Ver1.00',
51
+ '0120' => 'X-T4 Ver1.20',
50
52
  '0132' => 'X-T2 Ver1.32',
51
53
  '0144' => 'X100T Ver1.44',
52
54
  '0159' => 'S2Pro Ver1.00',
@@ -1454,6 +1456,27 @@ my %faceCategories = (
1454
1456
  },
1455
1457
  );
1456
1458
 
1459
+ # tags in RAF M-RAW header (ref PH)
1460
+ %Image::ExifTool::FujiFilm::MRAW = (
1461
+ PROCESS_PROC => \&ProcessMRAW,
1462
+ GROUPS => { 0 => 'RAF', 1 => 'M-RAW', 2 => 'Image' },
1463
+ FORMAT => 'int32u',
1464
+ TAG_PREFIX => 'MRAW',
1465
+ NOTES => q{
1466
+ Tags extracted from the M-RAW header of multi-image RAF files. The family 1
1467
+ group name for these tags is "M-RAW".
1468
+ },
1469
+ 1 => { Name => 'RawImageNumber', Format => 'int32u' },
1470
+ # 3 - seen "0 100", "-300 100" and "300 100" for a sequence of 3 images
1471
+ 3 => { Name => 'MRAW_0x0003', Format => 'rational32s', Unknown => 1, Hidden => 1, PrintConv => 'sprintf("%+.2f",$val)' },
1472
+ # 4 - (same value as 3 in all my samples)
1473
+ 4 => { Name => 'MRAW_0x0004', Format => 'rational32s', Unknown => 1, Hidden => 1, PrintConv => 'sprintf("%+.2f",$val)' },
1474
+ # 5 - seen "10 1600", "10 6800", "10 200", "10 35000" etc
1475
+ # 6 - seen "450 100", "400 100" (all images in RAF have same value)
1476
+ # 7 - seen 200, 125, 250, 2000
1477
+ # 8 - seen 0
1478
+ );
1479
+
1457
1480
  #------------------------------------------------------------------------------
1458
1481
  # decode information from FujiFilm face recognition information
1459
1482
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
@@ -1525,7 +1548,7 @@ sub ProcessFujiDir($$$)
1525
1548
  $raf->Read($buff, 4) or return 0;
1526
1549
  my $entries = unpack 'N', $buff;
1527
1550
  $entries < 256 or return 0;
1528
- $et->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
1551
+ $et->VerboseDir('Fuji', $entries);
1529
1552
  SetByteOrder('MM');
1530
1553
  my $pos = $offset + 4;
1531
1554
  for ($index=0; $index<$entries; ++$index) {
@@ -1557,6 +1580,51 @@ sub ProcessFujiDir($$$)
1557
1580
  return 1;
1558
1581
  }
1559
1582
 
1583
+ #------------------------------------------------------------------------------
1584
+ # get information from FujiFilm M-RAW header
1585
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
1586
+ # Returns: 1 if this was a valid M-RAW headerx
1587
+ sub ProcessMRAW($$$)
1588
+ {
1589
+ my ($et, $dirInfo, $tagTablePtr) = @_;
1590
+ my $dataPt = $$dirInfo{DataPt};
1591
+ my $dataPos = $$dirInfo{DataPos};
1592
+ my $dataLen = length $$dataPt;
1593
+ $dataLen < 44 and $et->Warn('Short M-RAW header'), return 0;
1594
+ $$dataPt =~ /^FUJIFILMM-RAW / or $et->Warn('Bad M-RAW header'), return 0;
1595
+ my $ver = substr($$dataPt, 16, 4);
1596
+ $et->VerboseDir("M-RAW $ver", undef, $dataLen);
1597
+ SetByteOrder('MM');
1598
+ my $size = Get16u($dataPt, 40); # (these are just a guess - PH)
1599
+ my $num = Get16u($dataPt, 42);
1600
+ my $pos = 44;
1601
+ my ($i, $n);
1602
+ for ($n=0; ; ++$n) {
1603
+ $pos += 16; # skip offset/size fields
1604
+ my $end = $pos + $size;
1605
+ last if $end > $dataLen;
1606
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT} if $pos > 60;
1607
+ $et->VPrint(0, "$$et{INDENT}(Raw image $n parameters: $size bytes, $num entries)\n");
1608
+ for ($i=0; $i<$num; ++$i) {
1609
+ last if $pos + 4 > $end;
1610
+ # (don't know what the byte at the current $pos is for, value = 0x20)
1611
+ my $tag = Get8u($dataPt, $pos+1);
1612
+ my $size = Get16u($dataPt, $pos+2);
1613
+ $pos += 4;
1614
+ last if $pos + $size > $end;
1615
+ $et->HandleTag($tagTablePtr, $tag, undef,
1616
+ DataPt => $dataPt,
1617
+ DataPos => $dataPos,
1618
+ Start => $pos,
1619
+ Size => $size,
1620
+ );
1621
+ $pos += $size;
1622
+ }
1623
+ }
1624
+ delete $$et{DOC_NUM};
1625
+ return 1;
1626
+ }
1627
+
1560
1628
  #------------------------------------------------------------------------------
1561
1629
  # write information to FujiFilm RAW file (RAF)
1562
1630
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -1572,10 +1640,12 @@ sub WriteRAF($$)
1572
1640
  my $ver = substr($hdr, 0x3c, 4);
1573
1641
  $ver =~ /^\d{4}$/ or $testedRAF{$ver} or return 0;
1574
1642
 
1643
+ # get position and size of M-RAW header
1644
+ my ($mpos, $mlen) = unpack('x72NN', $hdr);
1575
1645
  # get the position and size of embedded JPEG
1576
1646
  my ($jpos, $jlen) = unpack('x84NN', $hdr);
1577
1647
  # check to be sure the JPEG starts in the expected location
1578
- if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
1648
+ if (($mpos > 0x94 or $jpos > 0x94 + $mlen) or $jpos < 0x68 or $jpos & 0x03) {
1579
1649
  $et->Error("Unsupported or corrupted RAF image (version $ver)");
1580
1650
  return 1;
1581
1651
  }
@@ -1589,6 +1659,27 @@ sub WriteRAF($$)
1589
1659
  $et->Error('Error reading RAF meta information');
1590
1660
  return 1;
1591
1661
  }
1662
+ if ($mpos) {
1663
+ if ($mlen != 0x11c) {
1664
+ $et->Error('Unsupported M-RAW header (please submit sample for testing)');
1665
+ return 1;
1666
+ }
1667
+ # read M-RAW header and add to file header
1668
+ my $mraw;
1669
+ unless ($raf->Seek($mpos, 0) and $raf->Read($mraw, $mlen) == $mlen) {
1670
+ $et->Error('Error reading M-RAW header');
1671
+ return 1;
1672
+ }
1673
+ $hdr .= $mraw;
1674
+ # verify that the 1st raw image offset is zero, and that the 1st raw image
1675
+ # length is the same as the 2nd raw image offset
1676
+ unless (substr($hdr, 0xc0, 8) eq "\0\0\0\0\0\0\0\0" and
1677
+ substr($hdr, 0xc8, 8) eq substr($hdr, 0x110, 8))
1678
+ {
1679
+ $et->Error('Unexpected layout of M-RAW header');
1680
+ return 1;
1681
+ }
1682
+ }
1592
1683
  # use same write directories as JPEG
1593
1684
  $et->InitWriteDirs('JPEG');
1594
1685
  # rewrite the embedded JPEG in memory
@@ -1633,12 +1724,28 @@ sub WriteRAF($$)
1633
1724
  }
1634
1725
  # calculate offset difference due to change in JPEG size
1635
1726
  my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
1636
- # update necessary pointers in header
1637
- foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1727
+ # update necessary pointers in header (0xcc and higher in M-RAW header)
1728
+ foreach $offset (0x5c, 0x64, 0x78, 0x80, 0xcc, 0x114, 0x164) {
1638
1729
  last if $offset >= $jpos; # some versions have a short header
1639
1730
  my $oldPtr = Get32u(\$hdr, $offset);
1640
1731
  next unless $oldPtr; # don't update if pointer is zero
1641
- Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
1732
+ my $newPtr = $oldPtr + $ptrDiff;
1733
+ if ($newPtr < 0 or $newPtr > 0xffffffff) {
1734
+ $offset < 0xcc and $et->Error('Invalid offset in RAF header'), return 1;
1735
+ # assume values at 0xcc and greater are 8-byte integers (NC)
1736
+ # and adjust high word if necessary
1737
+ my $high = Get32u(\$hdr, $offset-4);
1738
+ if ($newPtr < 0) {
1739
+ $high -= 1;
1740
+ $newPtr += 0xffffffff + 1;
1741
+ $high < 0 and $et->Error('RAF header offset error'), return 1;
1742
+ } else {
1743
+ $high += 1;
1744
+ $newPtr -= 0xffffffff + 1;
1745
+ }
1746
+ Set32u($high, \$hdr, $offset-4);
1747
+ }
1748
+ Set32u($newPtr, \$hdr, $offset);
1642
1749
  }
1643
1750
  # write the new header
1644
1751
  my $outfile = $$dirInfo{OutFile};
@@ -1668,11 +1775,14 @@ sub ProcessRAF($$)
1668
1775
  my $raf = $$dirInfo{RAF};
1669
1776
  $raf->Read($buff,0x5c) == 0x5c or return 0;
1670
1777
  $buff =~ /^FUJIFILM/ or return 0;
1778
+ # get position and size of M-RAW header and jpeg preview
1779
+ my ($mpos, $mlen) = unpack('x72NN', $buff);
1671
1780
  my ($jpos, $jlen) = unpack('x84NN', $buff);
1672
1781
  $jpos & 0x8000 and return 0;
1673
- $raf->Seek($jpos, 0) or return 0;
1674
- $raf->Read($jpeg, $jlen) == $jlen or return 0;
1675
-
1782
+ if ($jpos) {
1783
+ $raf->Seek($jpos, 0) or return 0;
1784
+ $raf->Read($jpeg, $jlen) == $jlen or return 0;
1785
+ }
1676
1786
  $et->SetFileType();
1677
1787
  $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
1678
1788
 
@@ -1681,15 +1791,16 @@ sub ProcessRAF($$)
1681
1791
  Parent => 'RAF',
1682
1792
  RAF => new File::RandomAccess(\$jpeg),
1683
1793
  );
1684
- $$et{BASE} += $jpos;
1685
- my $rtnVal = $et->ProcessJPEG(\%dirInfo);
1686
- $$et{BASE} -= $jpos;
1687
- $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
1688
-
1794
+ if ($jpos) {
1795
+ $$et{BASE} += $jpos;
1796
+ my $ok = $et->ProcessJPEG(\%dirInfo);
1797
+ $$et{BASE} -= $jpos;
1798
+ $et->FoundTag('PreviewImage', \$jpeg) if $ok;
1799
+ }
1689
1800
  # extract information from Fuji RAF and TIFF directories
1690
1801
  my ($rafNum, $ifdNum) = ('','');
1691
- foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1692
- last if $offset >= $jpos;
1802
+ foreach $offset (0x48, 0x5c, 0x64, 0x78, 0x80) {
1803
+ last if $jpos and $offset >= $jpos;
1693
1804
  unless ($raf->Seek($offset, 0) and $raf->Read($buff, 8)) {
1694
1805
  $warn = 1;
1695
1806
  last;
@@ -1711,6 +1822,14 @@ sub ProcessRAF($$)
1711
1822
  }
1712
1823
  delete $$et{SET_GROUP1};
1713
1824
  $ifdNum = ($ifdNum || 1) + 1;
1825
+ } elsif ($offset == 0x48) {
1826
+ $$et{VALUE}{FileType} .= ' (M-RAW)';
1827
+ if ($raf->Seek($start, 0) and $raf->Read($buff, $mlen) == $mlen) {
1828
+ my $tbl = GetTagTable('Image::ExifTool::FujiFilm::MRAW');
1829
+ $et->ProcessDirectory({ DataPt => \$buff, DataPos => $start, DirName => 'M-RAW' }, $tbl);
1830
+ } else {
1831
+ $et->Warn('Error reading M-RAW header');
1832
+ }
1714
1833
  } else {
1715
1834
  # parse RAF directory
1716
1835
  %dirInfo = (
@@ -1719,14 +1838,17 @@ sub ProcessRAF($$)
1719
1838
  );
1720
1839
  $$et{SET_GROUP1} = "RAF$rafNum";
1721
1840
  my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
1722
- $et->ProcessDirectory(\%dirInfo, $tagTablePtr) or $warn = 1;
1841
+ if ($et->ProcessDirectory(\%dirInfo, $tagTablePtr)) {
1842
+ $rafNum = ($rafNum || 1) + 1;
1843
+ } else {
1844
+ $warn = 1;
1845
+ }
1723
1846
  delete $$et{SET_GROUP1};
1724
- $rafNum = ($rafNum || 1) + 1;
1725
1847
  }
1726
1848
  }
1727
1849
  $warn and $et->Warn('Possibly corrupt RAF information');
1728
1850
 
1729
- return $rtnVal;
1851
+ return 1;
1730
1852
  }
1731
1853
 
1732
1854
  1; # end
@@ -20,7 +20,7 @@ use strict;
20
20
  use vars qw($VERSION);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
 
23
- $VERSION = '1.19';
23
+ $VERSION = '1.20';
24
24
 
25
25
  # road map of directory locations in GIF images
26
26
  my %gifMap = (
@@ -85,6 +85,10 @@ my %gifMap = (
85
85
  Groups => { 2 => 'Audio' },
86
86
  Binary => 1,
87
87
  },
88
+ 'C2PA_GIF/' => { #https://c2pa.org/specifications/ (NC) (authentication code is 0x010000 binary, so removed from tag ID)
89
+ Name => 'JUMBF',
90
+ SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
91
+ },
88
92
  );
89
93
 
90
94
  # GIF locical screen descriptor
@@ -18,12 +18,13 @@ use strict;
18
18
  use vars qw($VERSION);
19
19
  use Image::ExifTool qw(:DataAccess :Utils);
20
20
 
21
- $VERSION = '1.58';
21
+ $VERSION = '1.59';
22
22
 
23
23
  sub ProcessID3v2($$$);
24
24
  sub ProcessPrivate($$$);
25
25
  sub ProcessSynText($$$);
26
26
  sub ProcessID3Dir($$$);
27
+ sub ProcessGEOB($$$);
27
28
  sub ConvertID3v1Text($$);
28
29
  sub ConvertTimeStamp($);
29
30
 
@@ -419,7 +420,7 @@ my %genre = (
419
420
 
420
421
  # Tags for ID2v2.2
421
422
  %Image::ExifTool::ID3::v2_2 = (
422
- PROCESS_PROC => \&Image::ExifTool::ID3::ProcessID3v2,
423
+ PROCESS_PROC => \&ProcessID3v2,
423
424
  GROUPS => { 1 => 'ID3v2_2', 2 => 'Audio' },
424
425
  NOTES => q{
425
426
  ExifTool extracts mainly text-based tags from ID3v2 information. The tags
@@ -511,6 +512,9 @@ my %genre = (
511
512
  TSC => 'ComposerSortOrder',
512
513
  ITU => { Name => 'iTunesU', Description => 'iTunes U', Binary => 1, Unknown => 1 },
513
514
  PCS => { Name => 'Podcast', Binary => 1, Unknown => 1 },
515
+ GP1 => 'Grouping', #github142 (NC)
516
+ MVN => 'MovementName', #github142 (NC)
517
+ MVI => 'MovementNumber', #github142 (NC)
514
518
  );
515
519
 
516
520
  # tags common to ID3v2.3 and ID3v2.4
@@ -534,7 +538,10 @@ my %id3v2_common = (
534
538
  # COMR => 'Commercial',
535
539
  # ENCR => 'EncryptionMethod',
536
540
  # ETCO => 'EventTimingCodes',
537
- # GEOB => 'GeneralEncapsulatedObject',
541
+ GEOB => {
542
+ Name => 'GeneralEncapsulatedObject',
543
+ SubDirectory => { TagTable => 'Image::ExifTool::ID3::GEOB' },
544
+ },
538
545
  # GRID => 'GroupIdentification',
539
546
  # LINK => 'LinkedInformation',
540
547
  MCDI => { Name => 'MusicCDIdentifier', Binary => 1 },
@@ -640,9 +647,25 @@ my %id3v2_common = (
640
647
  MVIN => 'MovementNumber', # (NC)
641
648
  );
642
649
 
650
+ %Image::ExifTool::ID3::GEOB = (
651
+ GROUPS => { 1 => 'ID3v2_3', 2 => 'Other' },
652
+ PROCESS_PROC => \&ProcessGEOB,
653
+ 'application/x-c2pa-manifest-store' => {
654
+ Name => 'JUMBF',
655
+ SubDirectory => {
656
+ TagTable => 'Image::ExifTool::Jpeg2000::Main',
657
+ ByteOrder => 'BigEndian',
658
+ },
659
+ },
660
+ 'GEOB-Mime' => { },
661
+ 'GEOB-File' => { },
662
+ 'GEOB-Desc' => { },
663
+ 'GEOB-Data' => { },
664
+ );
665
+
643
666
  # Tags for ID3v2.3 (http://www.id3.org/id3v2.3.0)
644
667
  %Image::ExifTool::ID3::v2_3 = (
645
- PROCESS_PROC => \&Image::ExifTool::ID3::ProcessID3v2,
668
+ PROCESS_PROC => \&ProcessID3v2,
646
669
  GROUPS => { 1 => 'ID3v2_3', 2 => 'Audio' },
647
670
  NOTES => q{
648
671
  ID3 version 2.3 tags. Includes some non-standard tags written by other
@@ -662,7 +685,7 @@ my %id3v2_common = (
662
685
 
663
686
  # Tags for ID3v2.4 (http://www.id3.org/id3v2.4.0-frames)
664
687
  %Image::ExifTool::ID3::v2_4 = (
665
- PROCESS_PROC => \&Image::ExifTool::ID3::ProcessID3v2,
688
+ PROCESS_PROC => \&ProcessID3v2,
666
689
  GROUPS => { 1 => 'ID3v2_4', 2 => 'Audio' },
667
690
  NOTES => q{
668
691
  ID3 version 2.4 tags. Includes some non-standard tags written by other
@@ -1101,7 +1124,11 @@ sub ProcessID3v2($$$)
1101
1124
  my $oldLen = $len;
1102
1125
  $len = UnSyncSafe($len);
1103
1126
  if (not defined $len or $offset + $len + 10 > $size) {
1104
- $et->Warn('Invalid ID3 frame size');
1127
+ if ($offset + $len == $size) {
1128
+ $et->Warn('Missing ID3 terminating frame', 1);
1129
+ } else {
1130
+ $et->Warn('Invalid ID3 frame size');
1131
+ }
1105
1132
  last;
1106
1133
  }
1107
1134
  # check next ID to see if it makes sense
@@ -1218,7 +1245,7 @@ sub ProcessID3v2($$$)
1218
1245
  my @vals = DecodeString($et, $val);
1219
1246
  foreach (0..1) { $vals[$_] = '' unless defined $vals[$_]; }
1220
1247
  ($val = "($vals[0]) $vals[1]") =~ s/^\(\) //;
1221
- } elsif ($id =~ /^T/ or $id =~ /^(IPL|IPLS)$/) {
1248
+ } elsif ($id =~ /^T/ or $id =~ /^(IPL|IPLS|GP1|MVI|MVN)$/) {
1222
1249
  $val = DecodeString($et, $val);
1223
1250
  } elsif ($id =~ /^(WXX|WXXX)$/) {
1224
1251
  # one encoded string and one Latin string separated by a null
@@ -1582,6 +1609,42 @@ sub ProcessID3Dir($$$)
1582
1609
  return ProcessID3($et, $dirInfo);
1583
1610
  }
1584
1611
 
1612
+ #------------------------------------------------------------------------------
1613
+ # Process ID3 General Encapsulated Object
1614
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
1615
+ # Returns: 1 on success
1616
+ sub ProcessGEOB($$$)
1617
+ {
1618
+ my ($et, $dirInfo, $tagTablePtr) = @_;
1619
+ $et->VerboseDir('GEOB', undef, length ${$$dirInfo{DataPt}});
1620
+ my $dataPt = $$dirInfo{DataPt};
1621
+ my $len = length $$dataPt;
1622
+ $len >= 4 or $et->Warn("Short GEOB frame"), return 0;
1623
+ my ($hdr, $attr);
1624
+ my $enc = unpack('C', $$dataPt);
1625
+ if ($enc == 1 or $enc == 2) {
1626
+ $hdr = ".(.*?)\0((?:..)*?)\0\0((?:..)*?)\0\0";
1627
+ } else {
1628
+ $hdr = ".(.*?)\0(.*?)\0(.*?)\0";
1629
+ }
1630
+ # remove header (encoding, mime, filename, description)
1631
+ $$dataPt =~ s/^$hdr//s or $et->Warn("Invalid GEOB frame"), return 0;
1632
+ my ($mime, $file, $desc) = ($1, DecodeString($et, $2, $enc), DecodeString($et, $3, $enc));
1633
+ $et->HandleTag($tagTablePtr, 'GEOB-Mime', $mime) if length $mime;
1634
+ $et->HandleTag($tagTablePtr, 'GEOB-File', $file) if length $file;
1635
+ $et->HandleTag($tagTablePtr, 'GEOB-Desc', $desc) if length $desc;
1636
+ if ($$tagTablePtr{$mime}) {
1637
+ $et->HandleTag($tagTablePtr, $mime, undef,
1638
+ DataPt => $dataPt,
1639
+ Start => 0,
1640
+ Size => length($$dataPt),
1641
+ );
1642
+ } else {
1643
+ $et->HandleTag($tagTablePtr, 'GEOB-Data', $dataPt);
1644
+ }
1645
+ return 1;
1646
+ }
1647
+
1585
1648
  #------------------------------------------------------------------------------
1586
1649
  # Extract ID3 information from an MP3 audio file
1587
1650
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -122,7 +122,7 @@ sub ProcessIND($$)
122
122
  # memory troubles (with its apparent 1 GB limit) if the XMP is larger
123
123
  # than about 400 MB, so guard against this
124
124
  if ($len > 300 * 1024 * 1024) {
125
- my $msg = sprintf('Insanely large XMP (%.0f MB)', $len / (1024 * 1024));
125
+ my $msg = sprintf('Insanely large XMP (%.0f MiB)', $len / (1024 * 1024));
126
126
  if ($outfile) {
127
127
  $et->Error($msg, 2) and $err = 1, last;
128
128
  } elsif ($et->Options('IgnoreMinorErrors')) {
@@ -251,7 +251,7 @@ sub ProcessJPEG_HDR($$$);
251
251
  Name => 'JUMBF',
252
252
  Condition => '$$valPt =~ /^JP/',
253
253
  SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
254
- # Note: The recommended options for reading C2PA JUMBF metadata are "-G3 -b -j -u"
254
+ # Note: The suggested options for reading C2PA CAI JUMBF metadata are "-G3 -b -j -u"
255
255
  }],
256
256
  APP12 => [{
257
257
  Name => 'PictureInfo',
@@ -89,12 +89,14 @@ my %uuid = (
89
89
  # JPEG2000 codestream markers (ref ISO/IEC FCD15444-1/2)
90
90
  my %j2cMarker = (
91
91
  0x4f => 'SOC', # start of codestream
92
+ # 0x50 - seen in JPH codestream
92
93
  0x51 => 'SIZ', # image and tile size
93
94
  0x52 => 'COD', # coding style default
94
95
  0x53 => 'COC', # coding style component
95
96
  0x55 => 'TLM', # tile-part lengths
96
97
  0x57 => 'PLM', # packet length, main header
97
98
  0x58 => 'PLT', # packet length, tile-part header
99
+ # 0x59 - seen in JPH codestream
98
100
  0x5c => 'QCD', # quantization default
99
101
  0x5d => 'QCC', # quantization component
100
102
  0x5e => 'RGN', # region of interest
@@ -128,12 +130,21 @@ my %j2cMarker = (
128
130
  WRITE_PROC => \&ProcessJpeg2000Box,
129
131
  PREFERRED => 1, # always add these tags when writing
130
132
  NOTES => q{
131
- The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG
132
- images, but not all of these are extracted. Note that ExifTool currently
133
- writes only EXIF, IPTC and XMP tags in Jpeg2000 images, and EXIF and XMP in
134
- JXL images. ExifTool will read/write Brotli-compressed EXIF and XMP in JXL
135
- images, but the API L<Compress|../ExifTool.html#Compress> option must be set to create new EXIF and XMP
136
- in compressed format.
133
+ The tags below are found in JPEG 2000 images and the C2PA CAI JUMBF metadata
134
+ in various file types (see below). Note that ExifTool currently writes only
135
+ EXIF, IPTC and XMP tags in Jpeg2000 images, and EXIF and XMP in JXL images.
136
+ ExifTool will read/write Brotli-compressed EXIF and XMP in JXL images, but
137
+ the API L<Compress|../ExifTool.html#Compress> option must be set to create new EXIF and XMP in compressed
138
+ format.
139
+
140
+ C2PA (Coalition for Content Provenance and Authenticity) CAI (Content
141
+ Authenticity Initiative) JUMBF (JPEG Universal Metadata Box Format) metdata
142
+ is currently extracted from JPEG, PNG, TIFF-based (eg. TIFF, DNG),
143
+ QuickTime-based (eg. MP4, MOV, HEIF, AVIF), RIFF-based (eg. WAV, AVI, WebP),
144
+ GIF files and ID3v2 metadata. The suggested ExifTool command-line arguments
145
+ for reading C2PA metadata are C<-jumbf:all -G3 -b -j -u -struct>. This
146
+ metadata may be deleted from writable JPEG, PNG, WebP, TIFF-based, and
147
+ QuickTime-based files by deleting the JUMBF group with C<-jumbf:all=>.
137
148
  },
138
149
  #
139
150
  # NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED!
@@ -345,13 +356,6 @@ my %j2cMarker = (
345
356
  Start => '$valuePtr + 16',
346
357
  },
347
358
  },
348
- {
349
- Name => 'UUID-Signature', # (seen in JUMB data of JPEG images)
350
- # (may be able to remove this when JUMBF specification is finalized)
351
- Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
352
- Format => 'undef',
353
- ValueConv => 'substr($val,16)',
354
- },
355
359
  {
356
360
  Name => 'UUID-C2PAClaimSignature', # (seen in incorrectly-formatted JUMB data of JPEG images)
357
361
  # (may be able to remove this when JUMBF specification is finalized)
@@ -361,6 +365,13 @@ my %j2cMarker = (
361
365
  Start => '$valuePtr + 16',
362
366
  },
363
367
  },
368
+ {
369
+ Name => 'UUID-Signature', # (seen in JUMB data of JPEG images)
370
+ # (may be able to remove this when JUMBF specification is finalized)
371
+ Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
372
+ Format => 'undef',
373
+ ValueConv => 'substr($val,16)',
374
+ },
364
375
  {
365
376
  Name => 'UUID-Unknown',
366
377
  },
@@ -549,6 +560,7 @@ my %j2cMarker = (
549
560
  'jpm ' => 'JPEG 2000 Compound Image (.JPM)', # image/jpm
550
561
  'jpx ' => 'JPEG 2000 with extensions (.JPX)', # image/jpx
551
562
  'jxl ' => 'JPEG XL Image (.JXL)', # image/jxl
563
+ 'jph ' => 'High-throughput JPEG 2000 (.JPH)', # image/jph
552
564
  },
553
565
  },
554
566
  1 => {
@@ -993,10 +1005,12 @@ sub ProcessJpeg2000Box($$$)
993
1005
  my $dirLen = $$dirInfo{DirLen} || 0;
994
1006
  my $dirStart = $$dirInfo{DirStart} || 0;
995
1007
  my $base = $$dirInfo{Base} || 0;
996
- my $raf = $$dirInfo{RAF};
997
1008
  my $outfile = $$dirInfo{OutFile};
998
1009
  my $dirEnd = $dirStart + $dirLen;
999
- my ($err, $outBuff, $verbose, $doColour, $hash);
1010
+ my ($err, $outBuff, $verbose, $doColour, $hash, $raf);
1011
+
1012
+ # read from RAF unless reading from buffer
1013
+ $raf = $$dirInfo{RAF} unless $dataPt;
1000
1014
 
1001
1015
  if ($outfile) {
1002
1016
  unless ($raf) {
@@ -1516,6 +1530,7 @@ sub ProcessJP2($$)
1516
1530
  $fileType = 'JPX' if $1 eq 'jpx ';
1517
1531
  $fileType = 'JPM' if $1 eq 'jpm ';
1518
1532
  $fileType = 'JXL' if $1 eq 'jxl ';
1533
+ $fileType = 'JPH' if $1 eq 'jph ';
1519
1534
  }
1520
1535
  $raf->Seek(-length($buff), 1) if defined $buff;
1521
1536
  $et->SetFileType($fileType);
@@ -21,7 +21,7 @@ sub ProcessKodakPatch($$$);
21
21
  sub WriteUnknownOrPreview($$$);
22
22
  sub FixLeicaBase($$;$);
23
23
 
24
- $VERSION = '2.14';
24
+ $VERSION = '2.15';
25
25
 
26
26
  my $debug; # set to 1 to enable debugging code
27
27
 
@@ -694,7 +694,7 @@ my $debug; # set to 1 to enable debugging code
694
694
  Name => 'MakerNoteLeica8', # used by the Q (Type 116)
695
695
  # (Q (Typ 116) starts with "LEICA\0\x08\0", Make is "LEICA CAMERA AG")
696
696
  # (SL (Typ 601) and CL start with "LEICA\0\x09\0", Make is "LEICA CAMERA AG")
697
- Condition => '$$valPt =~ /^LEICA\0[\x08\x09]\0/',
697
+ Condition => '$$valPt =~ /^LEICA\0[\x08\x09\x0a]\0/',
698
698
  SubDirectory => {
699
699
  TagTable => 'Image::ExifTool::Panasonic::Leica5',
700
700
  Start => '$valuePtr + 8',