exiftool-vendored.exe 12.67.0 → 12.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/bin/exiftool_files/Changes +79 -10
  2. package/bin/exiftool_files/README +7 -7
  3. package/bin/exiftool_files/exiftool.pl +37 -31
  4. package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +18 -2
  5. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +87 -16
  6. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +3 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/DNG.pm +25 -2
  8. package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +54 -6
  9. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +175 -14
  10. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +158 -20
  11. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
  12. package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +16 -11
  13. package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +70 -7
  14. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +1 -1
  15. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +1 -1
  16. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  17. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +2 -2
  18. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +82 -22
  19. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +7 -1
  20. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +3 -1
  21. package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +22 -9
  22. package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +6 -1
  23. package/bin/exiftool_files/lib/Image/ExifTool/PhotoMechanic.pm +2 -1
  24. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +92 -55
  25. package/bin/exiftool_files/lib/Image/ExifTool/README +14 -5
  26. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +60 -10
  27. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +152 -46
  28. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6955 -6713
  29. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +878 -334
  30. package/bin/exiftool_files/lib/Image/ExifTool/Text.pm +4 -5
  31. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +23 -20
  32. package/bin/exiftool_files/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  33. package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +14 -4
  34. package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +3 -0
  35. package/bin/exiftool_files/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  36. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +40 -14
  37. package/bin/exiftool_files/lib/Image/ExifTool/XISF.pm +185 -0
  38. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +67 -2
  39. package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +35 -0
  40. package/bin/exiftool_files/lib/Image/ExifTool.pm +92 -45
  41. package/bin/exiftool_files/lib/Image/ExifTool.pod +14 -8
  42. package/package.json +3 -3
@@ -21,7 +21,7 @@ use strict;
21
21
  use vars qw($VERSION);
22
22
  use Image::ExifTool qw(:DataAccess :Utils);
23
23
 
24
- $VERSION = '1.18';
24
+ $VERSION = '1.19';
25
25
 
26
26
  sub ProcessPEResources($$);
27
27
  sub ProcessPEVersion($$);
@@ -726,6 +726,7 @@ my %languageCode = (
726
726
  Name => 'CPUType',
727
727
  Format => 'int16u',
728
728
  # ref /usr/include/linux/elf-em.h
729
+ # ref https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
729
730
  PrintConv => {
730
731
  0 => 'None',
731
732
  1 => 'AT&T WE 32100',
@@ -736,21 +737,68 @@ my %languageCode = (
736
737
  6 => 'i486',
737
738
  7 => 'i860',
738
739
  8 => 'MIPS R3000',
740
+ 9 => 'IBM System/370',
739
741
  10 => 'MIPS R4000',
740
- 15 => 'HPPA',
742
+ 15 => 'HP PA-RISC',
741
743
  18 => 'Sun v8plus',
744
+ 19 => 'Intel 80960',
742
745
  20 => 'PowerPC',
743
746
  21 => 'PowerPC 64-bit',
744
747
  22 => 'IBM S/390',
745
748
  23 => 'Cell BE SPU',
749
+ 36 => 'NEC V800',
750
+ 37=> 'Fujitsu FR20',
751
+ 38 => 'TRW RH-32',
752
+ 39 => 'Motorola RCE',
753
+ 40 => 'Arm (up to Armv7/AArch32)',
754
+ 41 => 'Digital Alpha',
746
755
  42 => 'SuperH',
747
756
  43 => 'SPARC v9 64-bit',
757
+ 44 => 'Siemens TriCore',
758
+ 45 => 'Argonaut RISC Core',
748
759
  46 => 'Renesas H8/300,300H,H8S',
760
+ 47 => 'Hitachi H8/300H',
761
+ 48 => 'Hitachi H8S',
762
+ 49 => 'Hitachi H8/500',
749
763
  50 => 'HP/Intel IA-64',
750
- 62 => 'AMD x86-64',
751
- 76 => 'Axis Communications 32-bit embedded processor',
752
- 87 => 'NEC v850',
753
- 88 => 'Renesas M32R',
764
+ 0x33 => 'Stanford MIPS-X',
765
+ 0x34 => 'Motorola ColdFire',
766
+ 0x35 => 'Motorola M68HC12',
767
+ 0x36 => 'Fujitsu MMA Multimedia Accelerator',
768
+ 0x37 => 'Siemens PCP',
769
+ 0x38 => 'Sony nCPU embedded RISC processor',
770
+ 0x39 => 'Denso NDR1 microprocessor',
771
+ 0x3a => 'Motorola Star*Core processor',
772
+ 0x3b => 'Toyota ME16 processor',
773
+ 0x3c => 'STMicroelectronics ST100 processor',
774
+ 0x3d => 'Advanced Logic Corp. TinyJ embedded processor family',
775
+ 0x3e => 'AMD x86-64',
776
+ 0x3f => 'Sony DSP Processor',
777
+ 0x40 => 'Digital Equipment Corp. PDP-10',
778
+ 0x41 => 'Digital Equipment Corp. PDP-11',
779
+ 0x42 => 'Siemens FX66 microcontroller',
780
+ 0x43 => 'STMicroelectronics ST9+ 8/16 bit microcontroller',
781
+ 0x44 => 'STMicroelectronics ST7 8-bit microcontroller',
782
+ 0x45 => 'Motorola MC68HC16 Microcontroller',
783
+ 0x46 => 'Motorola MC68HC11 Microcontroller',
784
+ 0x47 => 'Motorola MC68HC08 Microcontroller',
785
+ 0x48 => 'Motorola MC68HC05 Microcontroller',
786
+ 0x49 => 'Silicon Graphics SVx',
787
+ 0x4a => 'STMicroelectronics ST19 8-bit microcontroller',
788
+ 0x4b => 'Digital VAX',
789
+ 0x4c => 'Axis Communications 32-bit embedded processor',
790
+ 0x4d => 'Infineon Technologies 32-bit embedded processor',
791
+ 0x4e => 'Element 14 64-bit DSP Processor',
792
+ 0x4f => 'LSI Logic 16-bit DSP Processor',
793
+ 0x57 => 'NEC v850',
794
+ 0x58 => 'Renesas M32R',
795
+ 0x8c => 'TMS320C6000 Family',
796
+ 0xaf => 'MCST Elbrus e2k',
797
+ 0xb7 => 'Arm 64-bits (Armv8/AArch64)',
798
+ 0xdc => 'Zilog Z80',
799
+ 0xf3 => 'RISC-V',
800
+ 0xf7 => 'Berkeley Packet Filter',
801
+ 0x101 => 'WDC 65C816',
754
802
  0x5441 => 'Fujitsu FR-V',
755
803
  0x9026 => 'Alpha', # (interim value)
756
804
  0x9041 => 'm32r (old)',
@@ -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.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
- RawConv => q{
3084
- $$self{DOC_NUM} = ++$$self{DOC_COUNT};
3085
- $self->ExtractInfo(\$val, { ReEntry => 1 });
3086
- $$self{DOC_NUM} = 0;
3087
- return undef;
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-0xcd3b are defined by the DNG specification unless otherwise
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.89';
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',
@@ -428,6 +430,14 @@ my %faceCategories = (
428
430
  Name => 'ShadowTone',
429
431
  Writable => 'int32s',
430
432
  PrintConv => {
433
+ OTHER => sub {
434
+ my ($val, $inv) = @_;
435
+ if ($inv) {
436
+ return int(-$val * 16);
437
+ } else {
438
+ return -$val / 16;
439
+ }
440
+ },
431
441
  -64 => '+4 (hardest)',
432
442
  -48 => '+3 (very hard)',
433
443
  -32 => '+2 (hard)',
@@ -441,6 +451,14 @@ my %faceCategories = (
441
451
  Name => 'HighlightTone',
442
452
  Writable => 'int32s',
443
453
  PrintConv => {
454
+ OTHER => sub {
455
+ my ($val, $inv) = @_;
456
+ if ($inv) {
457
+ return int(-$val * 16);
458
+ } else {
459
+ return -$val / 16;
460
+ }
461
+ },
444
462
  -64 => '+4 (hardest)',
445
463
  -48 => '+3 (very hard)',
446
464
  -32 => '+2 (hard)',
@@ -1438,6 +1456,27 @@ my %faceCategories = (
1438
1456
  },
1439
1457
  );
1440
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
+
1441
1480
  #------------------------------------------------------------------------------
1442
1481
  # decode information from FujiFilm face recognition information
1443
1482
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
@@ -1509,7 +1548,7 @@ sub ProcessFujiDir($$$)
1509
1548
  $raf->Read($buff, 4) or return 0;
1510
1549
  my $entries = unpack 'N', $buff;
1511
1550
  $entries < 256 or return 0;
1512
- $et->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
1551
+ $et->VerboseDir('Fuji', $entries);
1513
1552
  SetByteOrder('MM');
1514
1553
  my $pos = $offset + 4;
1515
1554
  for ($index=0; $index<$entries; ++$index) {
@@ -1541,6 +1580,51 @@ sub ProcessFujiDir($$$)
1541
1580
  return 1;
1542
1581
  }
1543
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
+
1544
1628
  #------------------------------------------------------------------------------
1545
1629
  # write information to FujiFilm RAW file (RAF)
1546
1630
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -1556,10 +1640,12 @@ sub WriteRAF($$)
1556
1640
  my $ver = substr($hdr, 0x3c, 4);
1557
1641
  $ver =~ /^\d{4}$/ or $testedRAF{$ver} or return 0;
1558
1642
 
1643
+ # get position and size of M-RAW header
1644
+ my ($mpos, $mlen) = unpack('x72NN', $hdr);
1559
1645
  # get the position and size of embedded JPEG
1560
1646
  my ($jpos, $jlen) = unpack('x84NN', $hdr);
1561
1647
  # check to be sure the JPEG starts in the expected location
1562
- if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
1648
+ if (($mpos > 0x94 or $jpos > 0x94 + $mlen) or $jpos < 0x68 or $jpos & 0x03) {
1563
1649
  $et->Error("Unsupported or corrupted RAF image (version $ver)");
1564
1650
  return 1;
1565
1651
  }
@@ -1573,6 +1659,27 @@ sub WriteRAF($$)
1573
1659
  $et->Error('Error reading RAF meta information');
1574
1660
  return 1;
1575
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
+ }
1576
1683
  # use same write directories as JPEG
1577
1684
  $et->InitWriteDirs('JPEG');
1578
1685
  # rewrite the embedded JPEG in memory
@@ -1617,12 +1724,28 @@ sub WriteRAF($$)
1617
1724
  }
1618
1725
  # calculate offset difference due to change in JPEG size
1619
1726
  my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
1620
- # update necessary pointers in header
1621
- 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) {
1622
1729
  last if $offset >= $jpos; # some versions have a short header
1623
1730
  my $oldPtr = Get32u(\$hdr, $offset);
1624
1731
  next unless $oldPtr; # don't update if pointer is zero
1625
- Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
1732
+ my $newPtr = $oldPtr + $ptrDiff;
1733
+ if ($newPtr < 0 or $newPtr > 0xffffffff) {
1734
+ $offset < 0xcc and $et->Error('Invalid offset in RAF header'), return 1;
1735
+ # assume values at 0xcc and greater are 8-byte integers (NC)
1736
+ # and adjust high word if necessary
1737
+ my $high = Get32u(\$hdr, $offset-4);
1738
+ if ($newPtr < 0) {
1739
+ $high -= 1;
1740
+ $newPtr += 0xffffffff + 1;
1741
+ $high < 0 and $et->Error('RAF header offset error'), return 1;
1742
+ } else {
1743
+ $high += 1;
1744
+ $newPtr -= 0xffffffff + 1;
1745
+ }
1746
+ Set32u($high, \$hdr, $offset-4);
1747
+ }
1748
+ Set32u($newPtr, \$hdr, $offset);
1626
1749
  }
1627
1750
  # write the new header
1628
1751
  my $outfile = $$dirInfo{OutFile};
@@ -1652,11 +1775,14 @@ sub ProcessRAF($$)
1652
1775
  my $raf = $$dirInfo{RAF};
1653
1776
  $raf->Read($buff,0x5c) == 0x5c or return 0;
1654
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);
1655
1780
  my ($jpos, $jlen) = unpack('x84NN', $buff);
1656
1781
  $jpos & 0x8000 and return 0;
1657
- $raf->Seek($jpos, 0) or return 0;
1658
- $raf->Read($jpeg, $jlen) == $jlen or return 0;
1659
-
1782
+ if ($jpos) {
1783
+ $raf->Seek($jpos, 0) or return 0;
1784
+ $raf->Read($jpeg, $jlen) == $jlen or return 0;
1785
+ }
1660
1786
  $et->SetFileType();
1661
1787
  $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
1662
1788
 
@@ -1665,15 +1791,16 @@ sub ProcessRAF($$)
1665
1791
  Parent => 'RAF',
1666
1792
  RAF => new File::RandomAccess(\$jpeg),
1667
1793
  );
1668
- $$et{BASE} += $jpos;
1669
- my $rtnVal = $et->ProcessJPEG(\%dirInfo);
1670
- $$et{BASE} -= $jpos;
1671
- $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
1672
-
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
+ }
1673
1800
  # extract information from Fuji RAF and TIFF directories
1674
1801
  my ($rafNum, $ifdNum) = ('','');
1675
- foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1676
- last if $offset >= $jpos;
1802
+ foreach $offset (0x48, 0x5c, 0x64, 0x78, 0x80) {
1803
+ last if $jpos and $offset >= $jpos;
1677
1804
  unless ($raf->Seek($offset, 0) and $raf->Read($buff, 8)) {
1678
1805
  $warn = 1;
1679
1806
  last;
@@ -1695,6 +1822,14 @@ sub ProcessRAF($$)
1695
1822
  }
1696
1823
  delete $$et{SET_GROUP1};
1697
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
+ }
1698
1833
  } else {
1699
1834
  # parse RAF directory
1700
1835
  %dirInfo = (
@@ -1703,14 +1838,17 @@ sub ProcessRAF($$)
1703
1838
  );
1704
1839
  $$et{SET_GROUP1} = "RAF$rafNum";
1705
1840
  my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
1706
- $et->ProcessDirectory(\%dirInfo, $tagTablePtr) or $warn = 1;
1841
+ if ($et->ProcessDirectory(\%dirInfo, $tagTablePtr)) {
1842
+ $rafNum = ($rafNum || 1) + 1;
1843
+ } else {
1844
+ $warn = 1;
1845
+ }
1707
1846
  delete $$et{SET_GROUP1};
1708
- $rafNum = ($rafNum || 1) + 1;
1709
1847
  }
1710
1848
  }
1711
1849
  $warn and $et->Warn('Possibly corrupt RAF information');
1712
1850
 
1713
- return $rtnVal;
1851
+ return 1;
1714
1852
  }
1715
1853
 
1716
1854
  1; # end