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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +98 -15
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +10 -10
  7. data/bin/exiftool +32 -25
  8. data/bin/lib/Image/ExifTool/AAC.pm +175 -0
  9. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
  10. data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
  11. data/bin/lib/Image/ExifTool/Canon.pm +87 -20
  12. data/bin/lib/Image/ExifTool/DJI.pm +3 -2
  13. data/bin/lib/Image/ExifTool/DNG.pm +25 -2
  14. data/bin/lib/Image/ExifTool/EXE.pm +54 -6
  15. data/bin/lib/Image/ExifTool/Exif.pm +204 -22
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
  17. data/bin/lib/Image/ExifTool/GIF.pm +5 -1
  18. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  19. data/bin/lib/Image/ExifTool/ID3.pm +76 -10
  20. data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
  21. data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
  22. data/bin/lib/Image/ExifTool/JSON.pm +4 -1
  23. data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  24. data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
  25. data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
  26. data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
  27. data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
  28. data/bin/lib/Image/ExifTool/PNG.pm +8 -13
  29. data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
  30. data/bin/lib/Image/ExifTool/Pentax.pm +15 -6
  31. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
  32. data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
  33. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
  34. data/bin/lib/Image/ExifTool/README +14 -5
  35. data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
  36. data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
  37. data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
  38. data/bin/lib/Image/ExifTool/Sony.pm +177 -37
  39. data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
  40. data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
  41. data/bin/lib/Image/ExifTool/Text.pm +4 -5
  42. data/bin/lib/Image/ExifTool/Validate.pm +23 -20
  43. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  44. data/bin/lib/Image/ExifTool/WriteExif.pl +33 -8
  45. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  46. data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  47. data/bin/lib/Image/ExifTool/Writer.pl +121 -28
  48. data/bin/lib/Image/ExifTool/XMP.pm +67 -2
  49. data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
  50. data/bin/lib/Image/ExifTool.pm +94 -43
  51. data/bin/lib/Image/ExifTool.pod +28 -17
  52. data/bin/perl-Image-ExifTool.spec +9 -9
  53. data/lib/exiftool_vendored/version.rb +1 -1
  54. 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.44';
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, Xaiomi Redmi models)
1429
- # 0x221 - int32u: 0 (IFD0, Xaiomi Redmi models)
1430
- # 0x222 - int32u: 0 (IFD0, Xaiomi Redmi models)
1431
- # 0x223 - int32u: 0 (IFD0, Xaiomi Redmi models)
1432
- # 0x224 - int32u: 0,1 (IFD0, Xaiomi Redmi models)
1433
- # 0x225 - string: "" (IFD0, Xaiomi Redmi models)
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
- # 0x9999 - string: camera settings (ExifIFD, Xiaomi POCO F1)
2457
- # 0x9aaa - int8u[2176]: ? (ExifIFD, Xiaomi POCO F1)
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
- RawConv => q{
3084
- $$self{DOC_NUM} = ++$$self{DOC_COUNT};
3085
- $self->ExtractInfo(\$val, { ReEntry => 1 });
3086
- $$self{DOC_NUM} = 0;
3087
- return undef;
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-0xcd3b are defined by the DNG specification unless otherwise
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.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,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->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
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
- Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
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
- $raf->Seek($jpos, 0) or return 0;
1674
- $raf->Read($jpeg, $jlen) == $jlen or return 0;
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
- $$et{BASE} += $jpos;
1685
- my $rtnVal = $et->ProcessJPEG(\%dirInfo);
1686
- $$et{BASE} -= $jpos;
1687
- $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
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) or $warn = 1;
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 $rtnVal;
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.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
@@ -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.07';
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)