exiftool-vendored.pl 12.69.0 → 12.72.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.
- package/bin/Changes +78 -12
- package/bin/MANIFEST +5 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +10 -10
- package/bin/exiftool +32 -25
- package/bin/lib/Image/ExifTool/AAC.pm +175 -0
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
- package/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- package/bin/lib/Image/ExifTool/Canon.pm +82 -20
- package/bin/lib/Image/ExifTool/DJI.pm +3 -2
- package/bin/lib/Image/ExifTool/EXE.pm +54 -6
- package/bin/lib/Image/ExifTool/Exif.pm +111 -11
- package/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
- package/bin/lib/Image/ExifTool/GIF.pm +5 -1
- package/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- package/bin/lib/Image/ExifTool/ID3.pm +76 -10
- package/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- package/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- package/bin/lib/Image/ExifTool/JSON.pm +4 -1
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- package/bin/lib/Image/ExifTool/M2TS.pm +21 -16
- package/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +203 -102
- package/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- package/bin/lib/Image/ExifTool/PNG.pm +8 -13
- package/bin/lib/Image/ExifTool/Panasonic.pm +10 -1
- package/bin/lib/Image/ExifTool/Pentax.pm +15 -6
- package/bin/lib/Image/ExifTool/QuickTime.pm +59 -13
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
- package/bin/lib/Image/ExifTool/README +7 -2
- package/bin/lib/Image/ExifTool/RIFF.pm +53 -9
- package/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
- package/bin/lib/Image/ExifTool/Samsung.pm +3 -2
- package/bin/lib/Image/ExifTool/Sony.pm +177 -37
- package/bin/lib/Image/ExifTool/TagLookup.pm +6961 -6856
- package/bin/lib/Image/ExifTool/TagNames.pod +580 -344
- package/bin/lib/Image/ExifTool/Text.pm +4 -5
- package/bin/lib/Image/ExifTool/Validate.pm +6 -5
- package/bin/lib/Image/ExifTool/WriteExif.pl +19 -4
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
- package/bin/lib/Image/ExifTool/WriteRIFF.pl +9 -3
- package/bin/lib/Image/ExifTool/Writer.pl +102 -50
- package/bin/lib/Image/ExifTool.pm +74 -36
- package/bin/lib/Image/ExifTool.pod +28 -17
- package/bin/perl-Image-ExifTool.spec +9 -9
- package/bin/pp_build_exe.args +5 -4
- package/package.json +4 -5
|
@@ -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.
|
|
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,30 @@ 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 => 'ExposureCompensation', Format => 'rational32s', Unknown => 1, Hidden => 1, PrintConv => 'sprintf("%+.2f",$val)' },
|
|
1472
|
+
# 4 - (same value as 3 in all my samples)
|
|
1473
|
+
4 => { Name => 'ExposureCompensation2', Format => 'rational32s', Unknown => 1, Hidden => 1, PrintConv => 'sprintf("%+.2f",$val)' },
|
|
1474
|
+
# 5 - seen "10 1600", "10 6800", "10 200", "10 35000" etc
|
|
1475
|
+
5 => { Name => 'ExposureTime', Format => 'rational64u', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)' },
|
|
1476
|
+
# 6 - seen "450 100", "400 100" (all images in RAF have same value)
|
|
1477
|
+
6 => { Name => 'FNumber', Format => 'rational64u', PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)' },
|
|
1478
|
+
# 7 - seen 200, 125, 250, 2000
|
|
1479
|
+
7 => 'ISO',
|
|
1480
|
+
# 8 - seen 0
|
|
1481
|
+
);
|
|
1482
|
+
|
|
1457
1483
|
#------------------------------------------------------------------------------
|
|
1458
1484
|
# decode information from FujiFilm face recognition information
|
|
1459
1485
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
|
|
@@ -1525,7 +1551,7 @@ sub ProcessFujiDir($$$)
|
|
|
1525
1551
|
$raf->Read($buff, 4) or return 0;
|
|
1526
1552
|
my $entries = unpack 'N', $buff;
|
|
1527
1553
|
$entries < 256 or return 0;
|
|
1528
|
-
$et->
|
|
1554
|
+
$et->VerboseDir('Fuji', $entries);
|
|
1529
1555
|
SetByteOrder('MM');
|
|
1530
1556
|
my $pos = $offset + 4;
|
|
1531
1557
|
for ($index=0; $index<$entries; ++$index) {
|
|
@@ -1557,6 +1583,51 @@ sub ProcessFujiDir($$$)
|
|
|
1557
1583
|
return 1;
|
|
1558
1584
|
}
|
|
1559
1585
|
|
|
1586
|
+
#------------------------------------------------------------------------------
|
|
1587
|
+
# get information from FujiFilm M-RAW header
|
|
1588
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
|
1589
|
+
# Returns: 1 if this was a valid M-RAW headerx
|
|
1590
|
+
sub ProcessMRAW($$$)
|
|
1591
|
+
{
|
|
1592
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
|
1593
|
+
my $dataPt = $$dirInfo{DataPt};
|
|
1594
|
+
my $dataPos = $$dirInfo{DataPos};
|
|
1595
|
+
my $dataLen = length $$dataPt;
|
|
1596
|
+
$dataLen < 44 and $et->Warn('Short M-RAW header'), return 0;
|
|
1597
|
+
$$dataPt =~ /^FUJIFILMM-RAW / or $et->Warn('Bad M-RAW header'), return 0;
|
|
1598
|
+
my $ver = substr($$dataPt, 16, 4);
|
|
1599
|
+
$et->VerboseDir("M-RAW $ver", undef, $dataLen);
|
|
1600
|
+
SetByteOrder('MM');
|
|
1601
|
+
my $size = Get16u($dataPt, 40); # (these are just a guess - PH)
|
|
1602
|
+
my $num = Get16u($dataPt, 42);
|
|
1603
|
+
my $pos = 44;
|
|
1604
|
+
my ($i, $n);
|
|
1605
|
+
for ($n=0; ; ++$n) {
|
|
1606
|
+
$pos += 16; # skip offset/size fields
|
|
1607
|
+
my $end = $pos + $size;
|
|
1608
|
+
last if $end > $dataLen;
|
|
1609
|
+
$$et{DOC_NUM} = ++$$et{DOC_COUNT} if $pos > 60;
|
|
1610
|
+
$et->VPrint(0, "$$et{INDENT}(Raw image $n parameters: $size bytes, $num entries)\n");
|
|
1611
|
+
for ($i=0; $i<$num; ++$i) {
|
|
1612
|
+
last if $pos + 4 > $end;
|
|
1613
|
+
# (don't know what the byte at the current $pos is for, value = 0x20)
|
|
1614
|
+
my $tag = Get8u($dataPt, $pos+1);
|
|
1615
|
+
my $size = Get16u($dataPt, $pos+2);
|
|
1616
|
+
$pos += 4;
|
|
1617
|
+
last if $pos + $size > $end;
|
|
1618
|
+
$et->HandleTag($tagTablePtr, $tag, undef,
|
|
1619
|
+
DataPt => $dataPt,
|
|
1620
|
+
DataPos => $dataPos,
|
|
1621
|
+
Start => $pos,
|
|
1622
|
+
Size => $size,
|
|
1623
|
+
);
|
|
1624
|
+
$pos += $size;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
delete $$et{DOC_NUM};
|
|
1628
|
+
return 1;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1560
1631
|
#------------------------------------------------------------------------------
|
|
1561
1632
|
# write information to FujiFilm RAW file (RAF)
|
|
1562
1633
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
|
@@ -1572,10 +1643,12 @@ sub WriteRAF($$)
|
|
|
1572
1643
|
my $ver = substr($hdr, 0x3c, 4);
|
|
1573
1644
|
$ver =~ /^\d{4}$/ or $testedRAF{$ver} or return 0;
|
|
1574
1645
|
|
|
1646
|
+
# get position and size of M-RAW header
|
|
1647
|
+
my ($mpos, $mlen) = unpack('x72NN', $hdr);
|
|
1575
1648
|
# get the position and size of embedded JPEG
|
|
1576
1649
|
my ($jpos, $jlen) = unpack('x84NN', $hdr);
|
|
1577
1650
|
# check to be sure the JPEG starts in the expected location
|
|
1578
|
-
if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
|
|
1651
|
+
if (($mpos > 0x94 or $jpos > 0x94 + $mlen) or $jpos < 0x68 or $jpos & 0x03) {
|
|
1579
1652
|
$et->Error("Unsupported or corrupted RAF image (version $ver)");
|
|
1580
1653
|
return 1;
|
|
1581
1654
|
}
|
|
@@ -1589,6 +1662,27 @@ sub WriteRAF($$)
|
|
|
1589
1662
|
$et->Error('Error reading RAF meta information');
|
|
1590
1663
|
return 1;
|
|
1591
1664
|
}
|
|
1665
|
+
if ($mpos) {
|
|
1666
|
+
if ($mlen != 0x11c) {
|
|
1667
|
+
$et->Error('Unsupported M-RAW header (please submit sample for testing)');
|
|
1668
|
+
return 1;
|
|
1669
|
+
}
|
|
1670
|
+
# read M-RAW header and add to file header
|
|
1671
|
+
my $mraw;
|
|
1672
|
+
unless ($raf->Seek($mpos, 0) and $raf->Read($mraw, $mlen) == $mlen) {
|
|
1673
|
+
$et->Error('Error reading M-RAW header');
|
|
1674
|
+
return 1;
|
|
1675
|
+
}
|
|
1676
|
+
$hdr .= $mraw;
|
|
1677
|
+
# verify that the 1st raw image offset is zero, and that the 1st raw image
|
|
1678
|
+
# length is the same as the 2nd raw image offset
|
|
1679
|
+
unless (substr($hdr, 0xc0, 8) eq "\0\0\0\0\0\0\0\0" and
|
|
1680
|
+
substr($hdr, 0xc8, 8) eq substr($hdr, 0x110, 8))
|
|
1681
|
+
{
|
|
1682
|
+
$et->Error('Unexpected layout of M-RAW header');
|
|
1683
|
+
return 1;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1592
1686
|
# use same write directories as JPEG
|
|
1593
1687
|
$et->InitWriteDirs('JPEG');
|
|
1594
1688
|
# rewrite the embedded JPEG in memory
|
|
@@ -1633,12 +1727,28 @@ sub WriteRAF($$)
|
|
|
1633
1727
|
}
|
|
1634
1728
|
# calculate offset difference due to change in JPEG size
|
|
1635
1729
|
my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
|
|
1636
|
-
# update necessary pointers in header
|
|
1637
|
-
foreach $offset (0x5c, 0x64, 0x78, 0x80) {
|
|
1730
|
+
# update necessary pointers in header (0xcc and higher in M-RAW header)
|
|
1731
|
+
foreach $offset (0x5c, 0x64, 0x78, 0x80, 0xcc, 0x114, 0x164) {
|
|
1638
1732
|
last if $offset >= $jpos; # some versions have a short header
|
|
1639
1733
|
my $oldPtr = Get32u(\$hdr, $offset);
|
|
1640
1734
|
next unless $oldPtr; # don't update if pointer is zero
|
|
1641
|
-
|
|
1735
|
+
my $newPtr = $oldPtr + $ptrDiff;
|
|
1736
|
+
if ($newPtr < 0 or $newPtr > 0xffffffff) {
|
|
1737
|
+
$offset < 0xcc and $et->Error('Invalid offset in RAF header'), return 1;
|
|
1738
|
+
# assume values at 0xcc and greater are 8-byte integers (NC)
|
|
1739
|
+
# and adjust high word if necessary
|
|
1740
|
+
my $high = Get32u(\$hdr, $offset-4);
|
|
1741
|
+
if ($newPtr < 0) {
|
|
1742
|
+
$high -= 1;
|
|
1743
|
+
$newPtr += 0xffffffff + 1;
|
|
1744
|
+
$high < 0 and $et->Error('RAF header offset error'), return 1;
|
|
1745
|
+
} else {
|
|
1746
|
+
$high += 1;
|
|
1747
|
+
$newPtr -= 0xffffffff + 1;
|
|
1748
|
+
}
|
|
1749
|
+
Set32u($high, \$hdr, $offset-4);
|
|
1750
|
+
}
|
|
1751
|
+
Set32u($newPtr, \$hdr, $offset);
|
|
1642
1752
|
}
|
|
1643
1753
|
# write the new header
|
|
1644
1754
|
my $outfile = $$dirInfo{OutFile};
|
|
@@ -1668,11 +1778,14 @@ sub ProcessRAF($$)
|
|
|
1668
1778
|
my $raf = $$dirInfo{RAF};
|
|
1669
1779
|
$raf->Read($buff,0x5c) == 0x5c or return 0;
|
|
1670
1780
|
$buff =~ /^FUJIFILM/ or return 0;
|
|
1781
|
+
# get position and size of M-RAW header and jpeg preview
|
|
1782
|
+
my ($mpos, $mlen) = unpack('x72NN', $buff);
|
|
1671
1783
|
my ($jpos, $jlen) = unpack('x84NN', $buff);
|
|
1672
1784
|
$jpos & 0x8000 and return 0;
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1785
|
+
if ($jpos) {
|
|
1786
|
+
$raf->Seek($jpos, 0) or return 0;
|
|
1787
|
+
$raf->Read($jpeg, $jlen) == $jlen or return 0;
|
|
1788
|
+
}
|
|
1676
1789
|
$et->SetFileType();
|
|
1677
1790
|
$et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
|
|
1678
1791
|
|
|
@@ -1681,15 +1794,16 @@ sub ProcessRAF($$)
|
|
|
1681
1794
|
Parent => 'RAF',
|
|
1682
1795
|
RAF => new File::RandomAccess(\$jpeg),
|
|
1683
1796
|
);
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1797
|
+
if ($jpos) {
|
|
1798
|
+
$$et{BASE} += $jpos;
|
|
1799
|
+
my $ok = $et->ProcessJPEG(\%dirInfo);
|
|
1800
|
+
$$et{BASE} -= $jpos;
|
|
1801
|
+
$et->FoundTag('PreviewImage', \$jpeg) if $ok;
|
|
1802
|
+
}
|
|
1689
1803
|
# extract information from Fuji RAF and TIFF directories
|
|
1690
1804
|
my ($rafNum, $ifdNum) = ('','');
|
|
1691
|
-
foreach $offset (0x5c, 0x64, 0x78, 0x80) {
|
|
1692
|
-
last if $offset >= $jpos;
|
|
1805
|
+
foreach $offset (0x48, 0x5c, 0x64, 0x78, 0x80) {
|
|
1806
|
+
last if $jpos and $offset >= $jpos;
|
|
1693
1807
|
unless ($raf->Seek($offset, 0) and $raf->Read($buff, 8)) {
|
|
1694
1808
|
$warn = 1;
|
|
1695
1809
|
last;
|
|
@@ -1711,6 +1825,14 @@ sub ProcessRAF($$)
|
|
|
1711
1825
|
}
|
|
1712
1826
|
delete $$et{SET_GROUP1};
|
|
1713
1827
|
$ifdNum = ($ifdNum || 1) + 1;
|
|
1828
|
+
} elsif ($offset == 0x48) {
|
|
1829
|
+
$$et{VALUE}{FileType} .= ' (M-RAW)';
|
|
1830
|
+
if ($raf->Seek($start, 0) and $raf->Read($buff, $mlen) == $mlen) {
|
|
1831
|
+
my $tbl = GetTagTable('Image::ExifTool::FujiFilm::MRAW');
|
|
1832
|
+
$et->ProcessDirectory({ DataPt => \$buff, DataPos => $start, DirName => 'M-RAW' }, $tbl);
|
|
1833
|
+
} else {
|
|
1834
|
+
$et->Warn('Error reading M-RAW header');
|
|
1835
|
+
}
|
|
1714
1836
|
} else {
|
|
1715
1837
|
# parse RAF directory
|
|
1716
1838
|
%dirInfo = (
|
|
@@ -1719,14 +1841,17 @@ sub ProcessRAF($$)
|
|
|
1719
1841
|
);
|
|
1720
1842
|
$$et{SET_GROUP1} = "RAF$rafNum";
|
|
1721
1843
|
my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
|
|
1722
|
-
$et->ProcessDirectory(\%dirInfo, $tagTablePtr)
|
|
1844
|
+
if ($et->ProcessDirectory(\%dirInfo, $tagTablePtr)) {
|
|
1845
|
+
$rafNum = ($rafNum || 1) + 1;
|
|
1846
|
+
} else {
|
|
1847
|
+
$warn = 1;
|
|
1848
|
+
}
|
|
1723
1849
|
delete $$et{SET_GROUP1};
|
|
1724
|
-
$rafNum = ($rafNum || 1) + 1;
|
|
1725
1850
|
}
|
|
1726
1851
|
}
|
|
1727
1852
|
$warn and $et->Warn('Possibly corrupt RAF information');
|
|
1728
1853
|
|
|
1729
|
-
return
|
|
1854
|
+
return 1;
|
|
1730
1855
|
}
|
|
1731
1856
|
|
|
1732
1857
|
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.
|
|
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
|
|
@@ -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.
|
|
19
|
+
$VERSION = '1.08';
|
|
20
20
|
|
|
21
21
|
sub ProcessGoPro($$$);
|
|
22
22
|
sub ProcessString($$$);
|
|
@@ -401,6 +401,21 @@ my %addUnits = (
|
|
|
401
401
|
ORIO => 'OutputOrientation',
|
|
402
402
|
UNIF => 'InputUniformity',
|
|
403
403
|
SROT => 'SensorReadoutTime',
|
|
404
|
+
# the following are ref https://exiftool.org/forum/index.php?topic=15517.0
|
|
405
|
+
CORI => { Name => 'CameraOrientation', Binary => 1, Notes => 'quaternions 0-1' },
|
|
406
|
+
AALP => { Name => 'AudioLevel', Notes => 'dBFS' },
|
|
407
|
+
GPSA => 'GPSAltitudeSystem', # (eg. 'MSLV')
|
|
408
|
+
GRAV => { Name => 'GravityVector', Binary => 1 },
|
|
409
|
+
HUES => 'PrediminantHue',
|
|
410
|
+
IORI => { Name => 'ImageOrientation', Binary => 1, Notes => 'quaternions 0-1' },
|
|
411
|
+
# LRVO - ? Part of LRV Frame Skip
|
|
412
|
+
# LRVS - ? Part of LRV Frame Skip
|
|
413
|
+
# LSKP - LRV Frame Skip
|
|
414
|
+
# MSKP - MRV Frame Skip
|
|
415
|
+
MWET => 'MicrophoneWet',
|
|
416
|
+
SCEN => 'SceneClassification', # (SNOW,URBA,INDO,WATR,VEGE,BEAC + probability)
|
|
417
|
+
WNDM => 'WindProcessing',
|
|
418
|
+
YAVG => 'LumaAverage',
|
|
404
419
|
);
|
|
405
420
|
|
|
406
421
|
# GoPro GPS5 tags (ref 2) (Hero5,Hero6)
|
|
@@ -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.
|
|
21
|
+
$VERSION = '1.60';
|
|
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 => \&
|
|
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
|
-
|
|
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 => \&
|
|
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 => \&
|
|
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
|
|
@@ -802,8 +825,8 @@ my %id3v2_common = (
|
|
|
802
825
|
|
|
803
826
|
# lookup to check for existence of tags in other ID3 versions
|
|
804
827
|
my %otherTable = (
|
|
805
|
-
\%Image::ExifTool::ID3::v2_4 =>
|
|
806
|
-
\%Image::ExifTool::ID3::v2_3 =>
|
|
828
|
+
\%Image::ExifTool::ID3::v2_4 => 'Image::ExifTool::ID3::v2_3',
|
|
829
|
+
\%Image::ExifTool::ID3::v2_3 => 'Image::ExifTool::ID3::v2_4',
|
|
807
830
|
);
|
|
808
831
|
|
|
809
832
|
# ID3 Composite tags
|
|
@@ -1075,6 +1098,7 @@ sub ProcessID3v2($$$)
|
|
|
1075
1098
|
my $vers = $$dirInfo{Version};
|
|
1076
1099
|
my $verbose = $et->Options('Verbose');
|
|
1077
1100
|
my $len; # frame data length
|
|
1101
|
+
my $otherTable;
|
|
1078
1102
|
|
|
1079
1103
|
$et->VerboseDir($tagTablePtr->{GROUPS}->{1}, 0, $size);
|
|
1080
1104
|
$et->VerboseDump($dataPt, Len => $size, Start => $offset);
|
|
@@ -1101,7 +1125,11 @@ sub ProcessID3v2($$$)
|
|
|
1101
1125
|
my $oldLen = $len;
|
|
1102
1126
|
$len = UnSyncSafe($len);
|
|
1103
1127
|
if (not defined $len or $offset + $len + 10 > $size) {
|
|
1104
|
-
$
|
|
1128
|
+
if ($offset + $len == $size) {
|
|
1129
|
+
$et->Warn('Missing ID3 terminating frame', 1);
|
|
1130
|
+
} else {
|
|
1131
|
+
$et->Warn('Invalid ID3 frame size');
|
|
1132
|
+
}
|
|
1105
1133
|
last;
|
|
1106
1134
|
}
|
|
1107
1135
|
# check next ID to see if it makes sense
|
|
@@ -1117,7 +1145,9 @@ sub ProcessID3v2($$$)
|
|
|
1117
1145
|
last if $offset + $len > $size;
|
|
1118
1146
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, $id);
|
|
1119
1147
|
unless ($tagInfo) {
|
|
1120
|
-
|
|
1148
|
+
if (not $otherTable and $otherTable{$tagTablePtr}) {
|
|
1149
|
+
$otherTable = GetTagTable($otherTable{$tagTablePtr});
|
|
1150
|
+
}
|
|
1121
1151
|
$tagInfo = $et->GetTagInfo($otherTable, $id) if $otherTable;
|
|
1122
1152
|
if ($tagInfo) {
|
|
1123
1153
|
$et->WarnOnce("Frame '${id}' is not valid for this ID3 version", 1);
|
|
@@ -1218,7 +1248,7 @@ sub ProcessID3v2($$$)
|
|
|
1218
1248
|
my @vals = DecodeString($et, $val);
|
|
1219
1249
|
foreach (0..1) { $vals[$_] = '' unless defined $vals[$_]; }
|
|
1220
1250
|
($val = "($vals[0]) $vals[1]") =~ s/^\(\) //;
|
|
1221
|
-
} elsif ($id =~ /^T/ or $id =~ /^(IPL|IPLS)$/) {
|
|
1251
|
+
} elsif ($id =~ /^T/ or $id =~ /^(IPL|IPLS|GP1|MVI|MVN)$/) {
|
|
1222
1252
|
$val = DecodeString($et, $val);
|
|
1223
1253
|
} elsif ($id =~ /^(WXX|WXXX)$/) {
|
|
1224
1254
|
# one encoded string and one Latin string separated by a null
|
|
@@ -1582,6 +1612,42 @@ sub ProcessID3Dir($$$)
|
|
|
1582
1612
|
return ProcessID3($et, $dirInfo);
|
|
1583
1613
|
}
|
|
1584
1614
|
|
|
1615
|
+
#------------------------------------------------------------------------------
|
|
1616
|
+
# Process ID3 General Encapsulated Object
|
|
1617
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
|
1618
|
+
# Returns: 1 on success
|
|
1619
|
+
sub ProcessGEOB($$$)
|
|
1620
|
+
{
|
|
1621
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
|
1622
|
+
$et->VerboseDir('GEOB', undef, length ${$$dirInfo{DataPt}});
|
|
1623
|
+
my $dataPt = $$dirInfo{DataPt};
|
|
1624
|
+
my $len = length $$dataPt;
|
|
1625
|
+
$len >= 4 or $et->Warn("Short GEOB frame"), return 0;
|
|
1626
|
+
my ($hdr, $attr);
|
|
1627
|
+
my $enc = unpack('C', $$dataPt);
|
|
1628
|
+
if ($enc == 1 or $enc == 2) {
|
|
1629
|
+
$hdr = ".(.*?)\0((?:..)*?)\0\0((?:..)*?)\0\0";
|
|
1630
|
+
} else {
|
|
1631
|
+
$hdr = ".(.*?)\0(.*?)\0(.*?)\0";
|
|
1632
|
+
}
|
|
1633
|
+
# remove header (encoding, mime, filename, description)
|
|
1634
|
+
$$dataPt =~ s/^$hdr//s or $et->Warn("Invalid GEOB frame"), return 0;
|
|
1635
|
+
my ($mime, $file, $desc) = ($1, DecodeString($et, $2, $enc), DecodeString($et, $3, $enc));
|
|
1636
|
+
$et->HandleTag($tagTablePtr, 'GEOB-Mime', $mime) if length $mime;
|
|
1637
|
+
$et->HandleTag($tagTablePtr, 'GEOB-File', $file) if length $file;
|
|
1638
|
+
$et->HandleTag($tagTablePtr, 'GEOB-Desc', $desc) if length $desc;
|
|
1639
|
+
if ($$tagTablePtr{$mime}) {
|
|
1640
|
+
$et->HandleTag($tagTablePtr, $mime, undef,
|
|
1641
|
+
DataPt => $dataPt,
|
|
1642
|
+
Start => 0,
|
|
1643
|
+
Size => length($$dataPt),
|
|
1644
|
+
);
|
|
1645
|
+
} else {
|
|
1646
|
+
$et->HandleTag($tagTablePtr, 'GEOB-Data', $dataPt);
|
|
1647
|
+
}
|
|
1648
|
+
return 1;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1585
1651
|
#------------------------------------------------------------------------------
|
|
1586
1652
|
# Extract ID3 information from an MP3 audio file
|
|
1587
1653
|
# 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
|
|
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
|
|
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',
|
|
@@ -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.
|
|
17
|
+
$VERSION = '1.06';
|
|
18
18
|
|
|
19
19
|
sub ProcessJSON($$);
|
|
20
20
|
sub ProcessTag($$$$%);
|
|
@@ -60,6 +60,9 @@ sub FoundTag($$$$%)
|
|
|
60
60
|
# avoid conflict with special table entries
|
|
61
61
|
$tag .= '!' if $Image::ExifTool::specialTags{$tag};
|
|
62
62
|
|
|
63
|
+
# use underline instead of colon if necessary in tag name
|
|
64
|
+
$tag =~ s/([A-Z]):([A-Z]{2})/${1}_$2/g;
|
|
65
|
+
|
|
63
66
|
AddTagToTable($tagTablePtr, $tag, {
|
|
64
67
|
Name => Image::ExifTool::MakeTagName($tag),
|
|
65
68
|
%flags,
|
|
@@ -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
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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);
|