exiftool_vendored 12.68.0 → 12.72.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +98 -15
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +10 -10
- data/bin/exiftool +32 -25
- data/bin/lib/Image/ExifTool/AAC.pm +175 -0
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +87 -20
- 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 +204 -22
- data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ID3.pm +76 -10
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/JSON.pm +4 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
- 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/Pentax.pm +15 -6
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
- data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
- data/bin/lib/Image/ExifTool/Sony.pm +177 -37
- data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
- data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
- 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 +33 -8
- 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 +121 -28
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +94 -43
- data/bin/lib/Image/ExifTool.pod +28 -17
- data/bin/perl-Image-ExifTool.spec +9 -9
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -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.48';
|
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',
|
@@ -1425,12 +1426,12 @@ my %opcodeInfo = (
|
|
1425
1426
|
Count => 6,
|
1426
1427
|
Priority => 0,
|
1427
1428
|
},
|
1428
|
-
# 0x220 - int32u: 0 (IFD0,
|
1429
|
-
# 0x221 - int32u: 0 (IFD0,
|
1430
|
-
# 0x222 - int32u: 0 (IFD0,
|
1431
|
-
# 0x223 - int32u: 0 (IFD0,
|
1432
|
-
# 0x224 - int32u: 0,1 (IFD0,
|
1433
|
-
# 0x225 - string: "" (IFD0,
|
1429
|
+
# 0x220 - int32u: 0 (IFD0, Xiaomi Redmi models)
|
1430
|
+
# 0x221 - int32u: 0 (IFD0, Xiaomi Redmi models)
|
1431
|
+
# 0x222 - int32u: 0 (IFD0, Xiaomi Redmi models)
|
1432
|
+
# 0x223 - int32u: 0 (IFD0, Xiaomi Redmi models)
|
1433
|
+
# 0x224 - int32u: 0,1 (IFD0, Xiaomi Redmi models)
|
1434
|
+
# 0x225 - string: "" (IFD0, Xiaomi Redmi models)
|
1434
1435
|
0x22f => 'StripRowCounts',
|
1435
1436
|
0x2bc => {
|
1436
1437
|
Name => 'ApplicationNotes', # (writable directory!)
|
@@ -1444,6 +1445,16 @@ my %opcodeInfo = (
|
|
1444
1445
|
TagTable => 'Image::ExifTool::XMP::Main',
|
1445
1446
|
},
|
1446
1447
|
},
|
1448
|
+
0x303 => { #https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions
|
1449
|
+
Name => 'RenderingIntent',
|
1450
|
+
Format => 'int8u',
|
1451
|
+
PrintConv => {
|
1452
|
+
0 => 'Perceptual',
|
1453
|
+
1 => 'Relative Colorimetric',
|
1454
|
+
2 => 'Saturation',
|
1455
|
+
3 => 'Absolute colorimetric',
|
1456
|
+
},
|
1457
|
+
},
|
1447
1458
|
0x3e7 => 'USPTOMiscellaneous', #20
|
1448
1459
|
0x1000 => { #5
|
1449
1460
|
Name => 'RelatedImageFileFormat',
|
@@ -1491,6 +1502,75 @@ my %opcodeInfo = (
|
|
1491
1502
|
WriteGroup => 'IFD0',
|
1492
1503
|
Avoid => 1,
|
1493
1504
|
},
|
1505
|
+
# tags 0x5XXX are obscure tags defined by Microsoft:
|
1506
|
+
# ref https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms932271(v=msdn.10)
|
1507
|
+
# ref https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions
|
1508
|
+
0x5001 => { Name => 'ResolutionXUnit', Notes => "ID's from 0x5001 to 0x5113 are obscure tags defined by Microsoft" }, # (int16u)
|
1509
|
+
0x5002 => 'ResolutionYUnit', # (int16u)
|
1510
|
+
0x5003 => 'ResolutionXLengthUnit', # (int16u)
|
1511
|
+
0x5004 => 'ResolutionYLengthUnit', # (int16u)
|
1512
|
+
0x5005 => 'PrintFlags', # (string)
|
1513
|
+
0x5006 => 'PrintFlagsVersion', # (int16u)
|
1514
|
+
0x5007 => 'PrintFlagsCrop', # (int8u)
|
1515
|
+
0x5008 => 'PrintFlagsBleedWidth', # (int32u)
|
1516
|
+
0x5009 => 'PrintFlagsBleedWidthScale', # (int16u)
|
1517
|
+
0x500a => 'HalftoneLPI', # (rational64u)
|
1518
|
+
0x500b => 'HalftoneLPIUnit', # (int16u, 1=inch, 2=cm)
|
1519
|
+
0x500c => 'HalftoneDegree', # (rational64u)
|
1520
|
+
0x500d => 'HalftoneShape', # (int16u,0=round,1=Ellipse,2=Line,3=Square,4=Cross,5=Diamond)
|
1521
|
+
0x500e => 'HalftoneMisc', # (int32u)
|
1522
|
+
0x500f => 'HalftoneScreen', # (int8u)
|
1523
|
+
0x5010 => 'JPEGQuality', # (int32u[N])
|
1524
|
+
0x5011 => { Name => 'GridSize', Binary => 1 }, # (undef)
|
1525
|
+
0x5012 => 'ThumbnailFormat', # (int32u,1=raw RGB,2=JPEG)
|
1526
|
+
0x5013 => 'ThumbnailWidth', # (int32u)
|
1527
|
+
0x5014 => 'ThumbnailHeight', # (int32u)
|
1528
|
+
0x5015 => 'ThumbnailColorDepth', # (int16u)
|
1529
|
+
0x5016 => 'ThumbnailPlanes', # (int16u)
|
1530
|
+
0x5017 => 'ThumbnailRawBytes', # (int32u)
|
1531
|
+
0x5018 => 'ThumbnailLength', # (int32u)
|
1532
|
+
0x5019 => 'ThumbnailCompressedSize', # (int32u)
|
1533
|
+
0x501a => { Name => 'ColorTransferFunction', Binary => 1 }, # (undef)
|
1534
|
+
0x501b => { Name => 'ThumbnailData', Binary => 1, Format => 'undef' }, # (int8u)
|
1535
|
+
0x5020 => 'ThumbnailImageWidth', # (int16u or int32u)
|
1536
|
+
0x5021 => 'ThumbnailImageHeight', # (int16u or int32u)
|
1537
|
+
0x5022 => 'ThumbnailBitsPerSample', # (int16u[N])
|
1538
|
+
0x5023 => 'ThumbnailCompression', # (int16u)
|
1539
|
+
0x5024 => 'ThumbnailPhotometricInterp', # (int16u)
|
1540
|
+
0x5025 => 'ThumbnailDescription', # (string)
|
1541
|
+
0x5026 => 'ThumbnailEquipMake', # (string)
|
1542
|
+
0x5027 => 'ThumbnailEquipModel', # (string)
|
1543
|
+
0x5028 => 'ThumbnailStripOffsets', # (int16u or int32u)
|
1544
|
+
0x5029 => 'ThumbnailOrientation', # (int16u)
|
1545
|
+
0x502a => 'ThumbnailSamplesPerPixel', # (int16u)
|
1546
|
+
0x502b => 'ThumbnailRowsPerStrip', # (int16u or int32u)
|
1547
|
+
0x502c => 'ThumbnailStripByteCounts', # (int16u or int32u)
|
1548
|
+
0x502d => 'ThumbnailResolutionX',
|
1549
|
+
0x502e => 'ThumbnailResolutionY',
|
1550
|
+
0x502f => 'ThumbnailPlanarConfig', # (int16u)
|
1551
|
+
0x5030 => 'ThumbnailResolutionUnit', # (int16u)
|
1552
|
+
0x5031 => 'ThumbnailTransferFunction', # (int16u[N])
|
1553
|
+
0x5032 => 'ThumbnailSoftware', # (string)
|
1554
|
+
0x5033 => { Name => 'ThumbnailDateTime', Groups => { 2 => 'Time' } }, # (string)
|
1555
|
+
0x5034 => 'ThumbnailArtist', # (string)
|
1556
|
+
0x5035 => 'ThumbnailWhitePoint', # (rational64u[2])
|
1557
|
+
0x5036 => 'ThumbnailPrimaryChromaticities', # (rational64u[6])
|
1558
|
+
0x5037 => 'ThumbnailYCbCrCoefficients', # (rational64u[3])
|
1559
|
+
0x5038 => 'ThumbnailYCbCrSubsampling', # (int16u)
|
1560
|
+
0x5039 => 'ThumbnailYCbCrPositioning', # (int16u)
|
1561
|
+
0x503a => 'ThumbnailRefBlackWhite', # (rational64u[6])
|
1562
|
+
0x503b => 'ThumbnailCopyright', # (string)
|
1563
|
+
0x5090 => 'LuminanceTable', # (int16u[64])
|
1564
|
+
0x5091 => 'ChrominanceTable', # (int16u[64])
|
1565
|
+
0x5100 => 'FrameDelay', # (int32u[N])
|
1566
|
+
0x5101 => 'LoopCount', # (int16u)
|
1567
|
+
0x5102 => 'GlobalPalette', # (int8u[N])
|
1568
|
+
0x5103 => 'IndexBackground', # (int8u)
|
1569
|
+
0x5104 => 'IndexTransparent', # (int8u)
|
1570
|
+
0x5110 => 'PixelUnits', # (int8u)
|
1571
|
+
0x5111 => 'PixelsPerUnitX', # (int32u)
|
1572
|
+
0x5112 => 'PixelsPerUnitY', # (int32u)
|
1573
|
+
0x5113 => 'PaletteHistogram', # (int8u[N])
|
1494
1574
|
0x7000 => { #JR
|
1495
1575
|
Name => 'SonyRawFileType',
|
1496
1576
|
# (only valid if Sony:FileFormat >= ARW 2.0, ref IB)
|
@@ -2453,8 +2533,18 @@ my %opcodeInfo = (
|
|
2453
2533
|
Name => 'CameraElevationAngle',
|
2454
2534
|
Writable => 'rational64s',
|
2455
2535
|
},
|
2456
|
-
|
2457
|
-
|
2536
|
+
0x9999 => { # (ExifIFD, Xiaomi)
|
2537
|
+
Name => 'XiaomiSettings', # (writable directory!)
|
2538
|
+
Writable => 'string',
|
2539
|
+
Protected => 1,
|
2540
|
+
SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
|
2541
|
+
},
|
2542
|
+
0x9a00 => {
|
2543
|
+
Name => 'XiaomiModel',
|
2544
|
+
Writable => 'string',
|
2545
|
+
Protected => 1,
|
2546
|
+
},
|
2547
|
+
# 0x9aaa - int8u[2048/2176]: ? (ExifIFD, Xiaomi POCO F1)
|
2458
2548
|
0x9c9b => {
|
2459
2549
|
Name => 'XPTitle',
|
2460
2550
|
Format => 'undef',
|
@@ -2906,6 +2996,7 @@ my %opcodeInfo = (
|
|
2906
2996
|
0xa480 => { Name => 'GDALMetadata', Writable => 'string', WriteGroup => 'IFD0' }, #3
|
2907
2997
|
0xa481 => { Name => 'GDALNoData', Writable => 'string', WriteGroup => 'IFD0' }, #3
|
2908
2998
|
0xa500 => { Name => 'Gamma', Writable => 'rational64u' },
|
2999
|
+
# 0xa661 - string: ? (ExifIFD, Xiaomi)
|
2909
3000
|
0xafc0 => 'ExpandSoftware', #JD (Opanda)
|
2910
3001
|
0xafc1 => 'ExpandLens', #JD (Opanda)
|
2911
3002
|
0xafc2 => 'ExpandFilm', #JD (Opanda)
|
@@ -3077,14 +3168,31 @@ my %opcodeInfo = (
|
|
3077
3168
|
},
|
3078
3169
|
PrintConvInv => '$val =~ /^PrintIM/ ? $val : undef', # quick validation
|
3079
3170
|
},
|
3171
|
+
0xc519 => { # (Hasselblad X2D)
|
3172
|
+
Name => 'HasselbladXML',
|
3173
|
+
Format => 'undef',
|
3174
|
+
TruncateOK => 1, # (incorrect size written by X2D)
|
3175
|
+
SubDirectory => {
|
3176
|
+
DirName => 'XML',
|
3177
|
+
TagTable => 'Image::ExifTool::PLIST::Main',
|
3178
|
+
Start => '$valuePtr + 4',
|
3179
|
+
},
|
3180
|
+
},
|
3080
3181
|
0xc51b => { # (Hasselblad H3D)
|
3081
3182
|
Name => 'HasselbladExif',
|
3082
3183
|
Format => 'undef',
|
3083
|
-
|
3084
|
-
|
3085
|
-
|
3086
|
-
|
3087
|
-
|
3184
|
+
SubDirectory => {
|
3185
|
+
Start => '$valuePtr',
|
3186
|
+
Base => '$start',
|
3187
|
+
TagTable => 'Image::ExifTool::Exif::Main',
|
3188
|
+
ProcessProc => \&Image::ExifTool::ProcessSubTIFF,
|
3189
|
+
# Writing this is problematic due to the braindead Hasselblad programmers.
|
3190
|
+
# One problem is that some values run outside the HasselbladExif data so they
|
3191
|
+
# will be lost if we do a simple copy (which is what we are currently doing
|
3192
|
+
# by returning undef from the WriteProc), but we can't rebuild this directory
|
3193
|
+
# by writing it properly because there is an erroneous StripByteCounts value
|
3194
|
+
# written by the X2D 100C that renders the data unreadable
|
3195
|
+
WriteProc => sub { return undef },
|
3088
3196
|
},
|
3089
3197
|
},
|
3090
3198
|
0xc573 => { #PH
|
@@ -3123,7 +3231,7 @@ my %opcodeInfo = (
|
|
3123
3231
|
0xc612 => {
|
3124
3232
|
Name => 'DNGVersion',
|
3125
3233
|
Notes => q{
|
3126
|
-
tags 0xc612-
|
3234
|
+
tags 0xc612-0xcd48 are defined by the DNG specification unless otherwise
|
3127
3235
|
noted. See L<https://helpx.adobe.com/photoshop/digital-negative.html> for
|
3128
3236
|
the specification
|
3129
3237
|
},
|
@@ -3609,6 +3717,11 @@ my %opcodeInfo = (
|
|
3609
3717
|
Writable => 'int16u',
|
3610
3718
|
WriteGroup => 'IFD0',
|
3611
3719
|
Protected => 1,
|
3720
|
+
PrintConv => {
|
3721
|
+
0 => 'Scene-referred',
|
3722
|
+
1 => 'Output-referred (ICC Profile Dynamic Range)',
|
3723
|
+
2 => 'Output-referred (High Dyanmic Range)', # DNG 1.7
|
3724
|
+
},
|
3612
3725
|
},
|
3613
3726
|
0xc6c5 => { Name => 'SRawType', Description => 'SRaw Type', WriteGroup => 'IFD0' }, #exifprobe (CR2 proprietary)
|
3614
3727
|
0xc6d2 => { #JD (Panasonic DMC-TZ5)
|
@@ -4133,7 +4246,7 @@ my %opcodeInfo = (
|
|
4133
4246
|
0xcd2d => { # DNG 1.6
|
4134
4247
|
Name => 'ProfileGainTableMap',
|
4135
4248
|
Writable => 'undef',
|
4136
|
-
WriteGroup => 'SubIFD',
|
4249
|
+
WriteGroup => 'SubIFD', # (according to DNG 1.7 docs, this was an error and it should have been IFD0)
|
4137
4250
|
Protected => 1,
|
4138
4251
|
Binary => 1,
|
4139
4252
|
},
|
@@ -4221,6 +4334,61 @@ my %opcodeInfo = (
|
|
4221
4334
|
WriteGroup => 'IFD0',
|
4222
4335
|
Protected => 1,
|
4223
4336
|
},
|
4337
|
+
0xcd40 => { # DNG 1.7
|
4338
|
+
Name => 'ProfileGainTableMap2',
|
4339
|
+
Writable => 'undef',
|
4340
|
+
WriteGroup => 'IFD0',
|
4341
|
+
Protected => 1,
|
4342
|
+
Binary => 1,
|
4343
|
+
},
|
4344
|
+
0xcd41 => {
|
4345
|
+
Name => 'JUMBF',
|
4346
|
+
# (set Deletable flag so we can delete this because
|
4347
|
+
# Jpeg2000 directories are otherwise permanent)
|
4348
|
+
Deletable => 1,
|
4349
|
+
SubDirectory => {
|
4350
|
+
TagTable => 'Image::ExifTool::Jpeg2000::Main',
|
4351
|
+
ByteOrder => 'BigEndian',
|
4352
|
+
},
|
4353
|
+
},
|
4354
|
+
0xcd43 => { # DNG 1.7
|
4355
|
+
Name => 'ColumnInterleaveFactor',
|
4356
|
+
Writable => 'int32u',
|
4357
|
+
WriteGroup => 'SubIFD',
|
4358
|
+
Protected => 1,
|
4359
|
+
},
|
4360
|
+
0xcd44 => { # DNG 1.7
|
4361
|
+
Name => 'ImageSequenceInfo',
|
4362
|
+
Writable => 'undef',
|
4363
|
+
WriteGroup => 'IFD0',
|
4364
|
+
SubDirectory => {
|
4365
|
+
TagTable => 'Image::ExifTool::DNG::ImageSeq',
|
4366
|
+
ByteOrder => 'BigEndian',
|
4367
|
+
},
|
4368
|
+
},
|
4369
|
+
0xcd46 => { # DNG 1.7
|
4370
|
+
Name => 'ImageStats',
|
4371
|
+
Writable => 'undef',
|
4372
|
+
WriteGroup => 'IFD0',
|
4373
|
+
Binary => 1,
|
4374
|
+
Protected => 1,
|
4375
|
+
},
|
4376
|
+
0xcd47 => { # DNG 1.7
|
4377
|
+
Name => 'ProfileDynamicRange',
|
4378
|
+
Writable => 'undef',
|
4379
|
+
WriteGroup => 'IFD0',
|
4380
|
+
SubDirectory => {
|
4381
|
+
TagTable => 'Image::ExifTool::DNG::ProfileDynamicRange',
|
4382
|
+
ByteOrder => 'BigEndian', # (not indicated in spec)
|
4383
|
+
},
|
4384
|
+
},
|
4385
|
+
0xcd48 => { # DNG 1.7
|
4386
|
+
Name => 'ProfileGroupName',
|
4387
|
+
Writable => 'string',
|
4388
|
+
Format => 'string',
|
4389
|
+
WriteGroup => 'IFD0',
|
4390
|
+
Protected => 1,
|
4391
|
+
},
|
4224
4392
|
0xea1c => { #13
|
4225
4393
|
Name => 'Padding',
|
4226
4394
|
Binary => 1,
|
@@ -5944,6 +6112,12 @@ sub ProcessExif($$$)
|
|
5944
6112
|
my $inMakerNotes = $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
|
5945
6113
|
my $isExif = ($tagTablePtr eq \%Image::ExifTool::Exif::Main);
|
5946
6114
|
|
6115
|
+
# warn for incorrect maker notes in CR3 files
|
6116
|
+
if ($$dirInfo{DirName} eq 'MakerNotes' and $$et{FileType} eq 'CR3' and
|
6117
|
+
$$dirInfo{Parent} and $$dirInfo{Parent} eq 'ExifIFD')
|
6118
|
+
{
|
6119
|
+
$et->WarnOnce("MakerNotes shouldn't exist ExifIFD of CR3 image", 1);
|
6120
|
+
}
|
5947
6121
|
# set flag to calculate image data hash if requested
|
5948
6122
|
$doHash = 1 if $$et{ImageDataHash} and (($$et{FILE_TYPE} eq 'TIFF' and not $base and not $inMakerNotes) or
|
5949
6123
|
($$et{FILE_TYPE} eq 'RAF' and $dirName eq 'FujiIFD'));
|
@@ -6219,7 +6393,7 @@ sub ProcessExif($$$)
|
|
6219
6393
|
}
|
6220
6394
|
# read from file if necessary
|
6221
6395
|
unless (defined $buff) {
|
6222
|
-
my $wrn;
|
6396
|
+
my ($wrn, $truncOK);
|
6223
6397
|
my $readFromRAF = ($tagInfo and $$tagInfo{ReadFromRAF});
|
6224
6398
|
if (not $raf->Seek($base + $valuePtr + $dataPos, 0)) {
|
6225
6399
|
$wrn = "Invalid offset for $dir entry $index";
|
@@ -6229,18 +6403,22 @@ sub ProcessExif($$$)
|
|
6229
6403
|
$buff = "$$tagInfo{Name} data $size bytes";
|
6230
6404
|
$readSize = length $buff;
|
6231
6405
|
} elsif ($raf->Read($buff,$size) != $size) {
|
6232
|
-
$wrn = "Error reading value for $dir entry $index";
|
6406
|
+
$wrn = sprintf("Error reading value for $dir entry $index, ID 0x%.4x", $tagID);
|
6407
|
+
if ($tagInfo and not $$tagInfo{Unknown}) {
|
6408
|
+
$wrn .= " $$tagInfo{Name}";
|
6409
|
+
$truncOK = $$tagInfo{TruncateOK};
|
6410
|
+
}
|
6233
6411
|
} elsif ($readFromRAF) {
|
6234
6412
|
# seek back to the start of the value
|
6235
6413
|
$raf->Seek($base + $valuePtr + $dataPos, 0);
|
6236
6414
|
}
|
6237
6415
|
if ($wrn) {
|
6238
|
-
$et->Warn($wrn, $inMakerNotes);
|
6239
|
-
return 0 unless $inMakerNotes or $htmlDump;
|
6416
|
+
$et->Warn($wrn, $inMakerNotes || $truncOK);
|
6417
|
+
return 0 unless $inMakerNotes or $htmlDump or $truncOK;
|
6240
6418
|
++$warnCount;
|
6241
6419
|
$buff = '' unless defined $buff;
|
6242
6420
|
$readSize = length $buff;
|
6243
|
-
$bad = 1;
|
6421
|
+
$bad = 1 unless $truncOK;
|
6244
6422
|
}
|
6245
6423
|
}
|
6246
6424
|
$valueDataLen = length $buff;
|
@@ -6813,6 +6991,10 @@ sub ProcessExif($$$)
|
|
6813
6991
|
# save original components of rational numbers (used when copying)
|
6814
6992
|
$$et{RATIONAL}{$tagKey} = $rational if defined $rational;
|
6815
6993
|
$$et{TAG_EXTRA}{$tagKey}{G6} = $saveFormat if $saveFormat;
|
6994
|
+
if ($$et{MAKER_NOTE_FIXUP}) {
|
6995
|
+
$$et{TAG_EXTRA}{$tagKey}{Fixup} = $$et{MAKER_NOTE_FIXUP};
|
6996
|
+
delete $$et{MAKER_NOTE_FIXUP};
|
6997
|
+
}
|
6816
6998
|
}
|
6817
6999
|
}
|
6818
7000
|
|
@@ -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)
|