exiftool_vendored 12.68.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.
- checksums.yaml +4 -4
- data/bin/Changes +63 -15
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +13 -13
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +68 -16
- data/bin/lib/Image/ExifTool/DJI.pm +3 -2
- data/bin/lib/Image/ExifTool/DNG.pm +25 -2
- data/bin/lib/Image/ExifTool/EXE.pm +54 -6
- data/bin/lib/Image/ExifTool/Exif.pm +175 -14
- data/bin/lib/Image/ExifTool/FujiFilm.pm +142 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/ID3.pm +70 -7
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +58 -18
- data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- data/bin/lib/Image/ExifTool/PNG.pm +8 -13
- data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +32 -5
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Sony.pm +95 -34
- data/bin/lib/Image/ExifTool/TagLookup.pm +6937 -6714
- data/bin/lib/Image/ExifTool/TagNames.pod +812 -332
- data/bin/lib/Image/ExifTool/Text.pm +4 -5
- data/bin/lib/Image/ExifTool/Validate.pm +23 -20
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteExif.pl +14 -4
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
- data/bin/lib/Image/ExifTool/Writer.pl +40 -14
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +79 -40
- data/bin/lib/Image/ExifTool.pod +9 -3
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -57,7 +57,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
|
|
57
57
|
use Image::ExifTool qw(:DataAccess :Utils);
|
58
58
|
use Image::ExifTool::MakerNotes;
|
59
59
|
|
60
|
-
$VERSION = '4.
|
60
|
+
$VERSION = '4.46';
|
61
61
|
|
62
62
|
sub ProcessExif($$$);
|
63
63
|
sub WriteExif($$$);
|
@@ -250,6 +250,7 @@ $formatName[129] = 'utf8'; # (Exif 3.0)
|
|
250
250
|
34927 => 'WebP', #LibTiff
|
251
251
|
34933 => 'PNG', # (TIFF mail list)
|
252
252
|
34934 => 'JPEG XR', # (TIFF mail list)
|
253
|
+
52546 => 'JPEG XL', # (DNG 1.7)
|
253
254
|
65000 => 'Kodak DCR Compressed', #PH
|
254
255
|
65535 => 'Pentax PEF Compressed', #Jens
|
255
256
|
);
|
@@ -1004,7 +1005,7 @@ my %opcodeInfo = (
|
|
1004
1005
|
},
|
1005
1006
|
0x14d => 'InkNames', #3
|
1006
1007
|
0x14e => 'NumberofInks', #3
|
1007
|
-
0x150 => 'DotRange',
|
1008
|
+
0x150 => 'DotRange', # (int8u or int16u)
|
1008
1009
|
0x151 => {
|
1009
1010
|
Name => 'TargetPrinter',
|
1010
1011
|
Writable => 'string',
|
@@ -1491,6 +1492,75 @@ my %opcodeInfo = (
|
|
1491
1492
|
WriteGroup => 'IFD0',
|
1492
1493
|
Avoid => 1,
|
1493
1494
|
},
|
1495
|
+
# tags 0x5XXX are obscure tags defined by Microsoft:
|
1496
|
+
# ref https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms932271(v=msdn.10)
|
1497
|
+
# ref https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions
|
1498
|
+
0x5001 => { Name => 'ResolutionXUnit', Notes => "ID's from 0x5001 to 0x5113 are obscure tags defined by Microsoft" }, # (int16u)
|
1499
|
+
0x5002 => 'ResolutionYUnit', # (int16u)
|
1500
|
+
0x5003 => 'ResolutionXLengthUnit', # (int16u)
|
1501
|
+
0x5004 => 'ResolutionYLengthUnit', # (int16u)
|
1502
|
+
0x5005 => 'PrintFlags', # (string)
|
1503
|
+
0x5006 => 'PrintFlagsVersion', # (int16u)
|
1504
|
+
0x5007 => 'PrintFlagsCrop', # (int8u)
|
1505
|
+
0x5008 => 'PrintFlagsBleedWidth', # (int32u)
|
1506
|
+
0x5009 => 'PrintFlagsBleedWidthScale', # (int16u)
|
1507
|
+
0x500a => 'HalftoneLPI', # (rational64u)
|
1508
|
+
0x500b => 'HalftoneLPIUnit', # (int16u, 1=inch, 2=cm)
|
1509
|
+
0x500c => 'HalftoneDegree', # (rational64u)
|
1510
|
+
0x500d => 'HalftoneShape', # (int16u,0=round,1=Ellipse,2=Line,3=Square,4=Cross,5=Diamond)
|
1511
|
+
0x500e => 'HalftoneMisc', # (int32u)
|
1512
|
+
0x500f => 'HalftoneScreen', # (int8u)
|
1513
|
+
0x5010 => 'JPEGQuality', # (int32u[N])
|
1514
|
+
0x5011 => { Name => 'GridSize', Binary => 1 }, # (undef)
|
1515
|
+
0x5012 => 'ThumbnailFormat', # (int32u,1=raw RGB,2=JPEG)
|
1516
|
+
0x5013 => 'ThumbnailWidth', # (int32u)
|
1517
|
+
0x5014 => 'ThumbnailHeight', # (int32u)
|
1518
|
+
0x5015 => 'ThumbnailColorDepth', # (int16u)
|
1519
|
+
0x5016 => 'ThumbnailPlanes', # (int16u)
|
1520
|
+
0x5017 => 'ThumbnailRawBytes', # (int32u)
|
1521
|
+
0x5018 => 'ThumbnailLength', # (int32u)
|
1522
|
+
0x5019 => 'ThumbnailCompressedSize', # (int32u)
|
1523
|
+
0x501a => { Name => 'ColorTransferFunction', Binary => 1 }, # (undef)
|
1524
|
+
0x501b => { Name => 'ThumbnailData', Binary => 1, Format => 'undef' }, # (int8u)
|
1525
|
+
0x5020 => 'ThumbnailImageWidth', # (int16u or int32u)
|
1526
|
+
0x5021 => 'ThumbnailImageHeight', # (int16u or int32u)
|
1527
|
+
0x5022 => 'ThumbnailBitsPerSample', # (int16u[N])
|
1528
|
+
0x5023 => 'ThumbnailCompression', # (int16u)
|
1529
|
+
0x5024 => 'ThumbnailPhotometricInterp', # (int16u)
|
1530
|
+
0x5025 => 'ThumbnailDescription', # (string)
|
1531
|
+
0x5026 => 'ThumbnailEquipMake', # (string)
|
1532
|
+
0x5027 => 'ThumbnailEquipModel', # (string)
|
1533
|
+
0x5028 => 'ThumbnailStripOffsets', # (int16u or int32u)
|
1534
|
+
0x5029 => 'ThumbnailOrientation', # (int16u)
|
1535
|
+
0x502a => 'ThumbnailSamplesPerPixel', # (int16u)
|
1536
|
+
0x502b => 'ThumbnailRowsPerStrip', # (int16u or int32u)
|
1537
|
+
0x502c => 'ThumbnailStripByteCounts', # (int16u or int32u)
|
1538
|
+
0x502d => 'ThumbnailResolutionX',
|
1539
|
+
0x502e => 'ThumbnailResolutionY',
|
1540
|
+
0x502f => 'ThumbnailPlanarConfig', # (int16u)
|
1541
|
+
0x5030 => 'ThumbnailResolutionUnit', # (int16u)
|
1542
|
+
0x5031 => 'ThumbnailTransferFunction', # (int16u[N])
|
1543
|
+
0x5032 => 'ThumbnailSoftware', # (string)
|
1544
|
+
0x5033 => { Name => 'ThumbnailDateTime', Groups => { 2 => 'Time' } }, # (string)
|
1545
|
+
0x5034 => 'ThumbnailArtist', # (string)
|
1546
|
+
0x5035 => 'ThumbnailWhitePoint', # (rational64u[2])
|
1547
|
+
0x5036 => 'ThumbnailPrimaryChromaticities', # (rational64u[6])
|
1548
|
+
0x5037 => 'ThumbnailYCbCrCoefficients', # (rational64u[3])
|
1549
|
+
0x5038 => 'ThumbnailYCbCrSubsampling', # (int16u)
|
1550
|
+
0x5039 => 'ThumbnailYCbCrPositioning', # (int16u)
|
1551
|
+
0x503a => 'ThumbnailRefBlackWhite', # (rational64u[6])
|
1552
|
+
0x503b => 'ThumbnailCopyright', # (string)
|
1553
|
+
0x5090 => 'LuminanceTable', # (int16u[64])
|
1554
|
+
0x5091 => 'ChrominanceTable', # (int16u[64])
|
1555
|
+
0x5100 => 'FrameDelay', # (int32u[N])
|
1556
|
+
0x5101 => 'LoopCount', # (int16u)
|
1557
|
+
0x5102 => 'GlobalPalette', # (int8u[N])
|
1558
|
+
0x5103 => 'IndexBackground', # (int8u)
|
1559
|
+
0x5104 => 'IndexTransparent', # (int8u)
|
1560
|
+
0x5110 => 'PixelUnits', # (int8u)
|
1561
|
+
0x5111 => 'PixelsPerUnitX', # (int32u)
|
1562
|
+
0x5112 => 'PixelsPerUnitY', # (int32u)
|
1563
|
+
0x5113 => 'PaletteHistogram', # (int8u[N])
|
1494
1564
|
0x7000 => { #JR
|
1495
1565
|
Name => 'SonyRawFileType',
|
1496
1566
|
# (only valid if Sony:FileFormat >= ARW 2.0, ref IB)
|
@@ -3077,14 +3147,31 @@ my %opcodeInfo = (
|
|
3077
3147
|
},
|
3078
3148
|
PrintConvInv => '$val =~ /^PrintIM/ ? $val : undef', # quick validation
|
3079
3149
|
},
|
3150
|
+
0xc519 => { # (Hasselblad X2D)
|
3151
|
+
Name => 'HasselbladXML',
|
3152
|
+
Format => 'undef',
|
3153
|
+
TruncateOK => 1, # (incorrect size written by X2D)
|
3154
|
+
SubDirectory => {
|
3155
|
+
DirName => 'XML',
|
3156
|
+
TagTable => 'Image::ExifTool::PLIST::Main',
|
3157
|
+
Start => '$valuePtr + 4',
|
3158
|
+
},
|
3159
|
+
},
|
3080
3160
|
0xc51b => { # (Hasselblad H3D)
|
3081
3161
|
Name => 'HasselbladExif',
|
3082
3162
|
Format => 'undef',
|
3083
|
-
|
3084
|
-
|
3085
|
-
|
3086
|
-
|
3087
|
-
|
3163
|
+
SubDirectory => {
|
3164
|
+
Start => '$valuePtr',
|
3165
|
+
Base => '$start',
|
3166
|
+
TagTable => 'Image::ExifTool::Exif::Main',
|
3167
|
+
ProcessProc => \&Image::ExifTool::ProcessSubTIFF,
|
3168
|
+
# Writing this is problematic due to the braindead Hasselblad programmers.
|
3169
|
+
# One problem is that some values run outside the HasselbladExif data so they
|
3170
|
+
# will be lost if we do a simple copy (which is what we are currently doing
|
3171
|
+
# by returning undef from the WriteProc), but we can't rebuild this directory
|
3172
|
+
# by writing it properly because there is an erroneous StripByteCounts value
|
3173
|
+
# written by the X2D 100C that renders the data unreadable
|
3174
|
+
WriteProc => sub { return undef },
|
3088
3175
|
},
|
3089
3176
|
},
|
3090
3177
|
0xc573 => { #PH
|
@@ -3123,7 +3210,7 @@ my %opcodeInfo = (
|
|
3123
3210
|
0xc612 => {
|
3124
3211
|
Name => 'DNGVersion',
|
3125
3212
|
Notes => q{
|
3126
|
-
tags 0xc612-
|
3213
|
+
tags 0xc612-0xcd48 are defined by the DNG specification unless otherwise
|
3127
3214
|
noted. See L<https://helpx.adobe.com/photoshop/digital-negative.html> for
|
3128
3215
|
the specification
|
3129
3216
|
},
|
@@ -3609,6 +3696,11 @@ my %opcodeInfo = (
|
|
3609
3696
|
Writable => 'int16u',
|
3610
3697
|
WriteGroup => 'IFD0',
|
3611
3698
|
Protected => 1,
|
3699
|
+
PrintConv => {
|
3700
|
+
0 => 'Scene-referred',
|
3701
|
+
1 => 'Output-referred (ICC Profile Dynamic Range)',
|
3702
|
+
2 => 'Output-referred (High Dyanmic Range)', # DNG 1.7
|
3703
|
+
},
|
3612
3704
|
},
|
3613
3705
|
0xc6c5 => { Name => 'SRawType', Description => 'SRaw Type', WriteGroup => 'IFD0' }, #exifprobe (CR2 proprietary)
|
3614
3706
|
0xc6d2 => { #JD (Panasonic DMC-TZ5)
|
@@ -4133,7 +4225,7 @@ my %opcodeInfo = (
|
|
4133
4225
|
0xcd2d => { # DNG 1.6
|
4134
4226
|
Name => 'ProfileGainTableMap',
|
4135
4227
|
Writable => 'undef',
|
4136
|
-
WriteGroup => 'SubIFD',
|
4228
|
+
WriteGroup => 'SubIFD', # (according to DNG 1.7 docs, this was an error and it should have been IFD0)
|
4137
4229
|
Protected => 1,
|
4138
4230
|
Binary => 1,
|
4139
4231
|
},
|
@@ -4221,6 +4313,61 @@ my %opcodeInfo = (
|
|
4221
4313
|
WriteGroup => 'IFD0',
|
4222
4314
|
Protected => 1,
|
4223
4315
|
},
|
4316
|
+
0xcd40 => { # DNG 1.7
|
4317
|
+
Name => 'ProfileGainTableMap2',
|
4318
|
+
Writable => 'undef',
|
4319
|
+
WriteGroup => 'IFD0',
|
4320
|
+
Protected => 1,
|
4321
|
+
Binary => 1,
|
4322
|
+
},
|
4323
|
+
0xcd41 => {
|
4324
|
+
Name => 'JUMBF',
|
4325
|
+
# (set Deletable flag so we can delete this because
|
4326
|
+
# Jpeg2000 directories are otherwise permanent)
|
4327
|
+
Deletable => 1,
|
4328
|
+
SubDirectory => {
|
4329
|
+
TagTable => 'Image::ExifTool::Jpeg2000::Main',
|
4330
|
+
ByteOrder => 'BigEndian',
|
4331
|
+
},
|
4332
|
+
},
|
4333
|
+
0xcd43 => { # DNG 1.7
|
4334
|
+
Name => 'ColumnInterleaveFactor',
|
4335
|
+
Writable => 'int32u',
|
4336
|
+
WriteGroup => 'SubIFD',
|
4337
|
+
Protected => 1,
|
4338
|
+
},
|
4339
|
+
0xcd44 => { # DNG 1.7
|
4340
|
+
Name => 'ImageSequenceInfo',
|
4341
|
+
Writable => 'undef',
|
4342
|
+
WriteGroup => 'IFD0',
|
4343
|
+
SubDirectory => {
|
4344
|
+
TagTable => 'Image::ExifTool::DNG::ImageSeq',
|
4345
|
+
ByteOrder => 'BigEndian',
|
4346
|
+
},
|
4347
|
+
},
|
4348
|
+
0xcd46 => { # DNG 1.7
|
4349
|
+
Name => 'ImageStats',
|
4350
|
+
Writable => 'undef',
|
4351
|
+
WriteGroup => 'IFD0',
|
4352
|
+
Binary => 1,
|
4353
|
+
Protected => 1,
|
4354
|
+
},
|
4355
|
+
0xcd47 => { # DNG 1.7
|
4356
|
+
Name => 'ProfileDynamicRange',
|
4357
|
+
Writable => 'undef',
|
4358
|
+
WriteGroup => 'IFD0',
|
4359
|
+
SubDirectory => {
|
4360
|
+
TagTable => 'Image::ExifTool::DNG::ProfileDynamicRange',
|
4361
|
+
ByteOrder => 'BigEndian', # (not indicated in spec)
|
4362
|
+
},
|
4363
|
+
},
|
4364
|
+
0xcd48 => { # DNG 1.7
|
4365
|
+
Name => 'ProfileGroupName',
|
4366
|
+
Writable => 'string',
|
4367
|
+
Format => 'string',
|
4368
|
+
WriteGroup => 'IFD0',
|
4369
|
+
Protected => 1,
|
4370
|
+
},
|
4224
4371
|
0xea1c => { #13
|
4225
4372
|
Name => 'Padding',
|
4226
4373
|
Binary => 1,
|
@@ -5944,6 +6091,12 @@ sub ProcessExif($$$)
|
|
5944
6091
|
my $inMakerNotes = $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
|
5945
6092
|
my $isExif = ($tagTablePtr eq \%Image::ExifTool::Exif::Main);
|
5946
6093
|
|
6094
|
+
# warn for incorrect maker notes in CR3 files
|
6095
|
+
if ($$dirInfo{DirName} eq 'MakerNotes' and $$et{FileType} eq 'CR3' and
|
6096
|
+
$$dirInfo{Parent} and $$dirInfo{Parent} eq 'ExifIFD')
|
6097
|
+
{
|
6098
|
+
$et->WarnOnce("MakerNotes shouldn't exist ExifIFD of CR3 image", 1);
|
6099
|
+
}
|
5947
6100
|
# set flag to calculate image data hash if requested
|
5948
6101
|
$doHash = 1 if $$et{ImageDataHash} and (($$et{FILE_TYPE} eq 'TIFF' and not $base and not $inMakerNotes) or
|
5949
6102
|
($$et{FILE_TYPE} eq 'RAF' and $dirName eq 'FujiIFD'));
|
@@ -6219,7 +6372,7 @@ sub ProcessExif($$$)
|
|
6219
6372
|
}
|
6220
6373
|
# read from file if necessary
|
6221
6374
|
unless (defined $buff) {
|
6222
|
-
my $wrn;
|
6375
|
+
my ($wrn, $truncOK);
|
6223
6376
|
my $readFromRAF = ($tagInfo and $$tagInfo{ReadFromRAF});
|
6224
6377
|
if (not $raf->Seek($base + $valuePtr + $dataPos, 0)) {
|
6225
6378
|
$wrn = "Invalid offset for $dir entry $index";
|
@@ -6229,18 +6382,22 @@ sub ProcessExif($$$)
|
|
6229
6382
|
$buff = "$$tagInfo{Name} data $size bytes";
|
6230
6383
|
$readSize = length $buff;
|
6231
6384
|
} elsif ($raf->Read($buff,$size) != $size) {
|
6232
|
-
$wrn = "Error reading value for $dir entry $index";
|
6385
|
+
$wrn = sprintf("Error reading value for $dir entry $index, ID 0x%.4x", $tagID);
|
6386
|
+
if ($tagInfo and not $$tagInfo{Unknown}) {
|
6387
|
+
$wrn .= " $$tagInfo{Name}";
|
6388
|
+
$truncOK = $$tagInfo{TruncateOK};
|
6389
|
+
}
|
6233
6390
|
} elsif ($readFromRAF) {
|
6234
6391
|
# seek back to the start of the value
|
6235
6392
|
$raf->Seek($base + $valuePtr + $dataPos, 0);
|
6236
6393
|
}
|
6237
6394
|
if ($wrn) {
|
6238
|
-
$et->Warn($wrn, $inMakerNotes);
|
6239
|
-
return 0 unless $inMakerNotes or $htmlDump;
|
6395
|
+
$et->Warn($wrn, $inMakerNotes || $truncOK);
|
6396
|
+
return 0 unless $inMakerNotes or $htmlDump or $truncOK;
|
6240
6397
|
++$warnCount;
|
6241
6398
|
$buff = '' unless defined $buff;
|
6242
6399
|
$readSize = length $buff;
|
6243
|
-
$bad = 1;
|
6400
|
+
$bad = 1 unless $truncOK;
|
6244
6401
|
}
|
6245
6402
|
}
|
6246
6403
|
$valueDataLen = length $buff;
|
@@ -6813,6 +6970,10 @@ sub ProcessExif($$$)
|
|
6813
6970
|
# save original components of rational numbers (used when copying)
|
6814
6971
|
$$et{RATIONAL}{$tagKey} = $rational if defined $rational;
|
6815
6972
|
$$et{TAG_EXTRA}{$tagKey}{G6} = $saveFormat if $saveFormat;
|
6973
|
+
if ($$et{MAKER_NOTE_FIXUP}) {
|
6974
|
+
$$et{TAG_EXTRA}{$tagKey}{Fixup} = $$et{MAKER_NOTE_FIXUP};
|
6975
|
+
delete $$et{MAKER_NOTE_FIXUP};
|
6976
|
+
}
|
6816
6977
|
}
|
6817
6978
|
}
|
6818
6979
|
|
@@ -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,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->
|
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
|
-
|
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
|
-
|
1674
|
-
|
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
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
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)
|
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
|
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.
|
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
|