exiftool_vendored 12.42.0 → 12.50.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +189 -6
  3. data/bin/MANIFEST +12 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +45 -44
  7. data/bin/config_files/acdsee.config +2 -1
  8. data/bin/config_files/frameCount.config +56 -0
  9. data/bin/config_files/tiff_version.config +1 -1
  10. data/bin/exiftool +113 -95
  11. data/bin/fmt_files/gpx.fmt +3 -0
  12. data/bin/fmt_files/gpx_wpt.fmt +3 -0
  13. data/bin/lib/Image/ExifTool/Apple.pm +16 -3
  14. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +23 -12
  15. data/bin/lib/Image/ExifTool/Canon.pm +66 -37
  16. data/bin/lib/Image/ExifTool/CanonRaw.pm +8 -1
  17. data/bin/lib/Image/ExifTool/CanonVRD.pm +7 -8
  18. data/bin/lib/Image/ExifTool/DJI.pm +2 -1
  19. data/bin/lib/Image/ExifTool/DarwinCore.pm +13 -1
  20. data/bin/lib/Image/ExifTool/EXE.pm +9 -1
  21. data/bin/lib/Image/ExifTool/Exif.pm +17 -12
  22. data/bin/lib/Image/ExifTool/FLAC.pm +17 -3
  23. data/bin/lib/Image/ExifTool/FLIR.pm +4 -3
  24. data/bin/lib/Image/ExifTool/FlashPix.pm +26 -3
  25. data/bin/lib/Image/ExifTool/FujiFilm.pm +51 -4
  26. data/bin/lib/Image/ExifTool/GPS.pm +21 -1
  27. data/bin/lib/Image/ExifTool/Geotag.pm +25 -5
  28. data/bin/lib/Image/ExifTool/ICC_Profile.pm +3 -2
  29. data/bin/lib/Image/ExifTool/ICO.pm +143 -0
  30. data/bin/lib/Image/ExifTool/ID3.pm +6 -6
  31. data/bin/lib/Image/ExifTool/IPTC.pm +5 -1
  32. data/bin/lib/Image/ExifTool/LNK.pm +5 -2
  33. data/bin/lib/Image/ExifTool/M2TS.pm +98 -8
  34. data/bin/lib/Image/ExifTool/MIE.pm +9 -3
  35. data/bin/lib/Image/ExifTool/MISB.pm +494 -0
  36. data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -1
  37. data/bin/lib/Image/ExifTool/Matroska.pm +24 -16
  38. data/bin/lib/Image/ExifTool/Motorola.pm +8 -2
  39. data/bin/lib/Image/ExifTool/Nikon.pm +288 -122
  40. data/bin/lib/Image/ExifTool/NikonSettings.pm +5 -3
  41. data/bin/lib/Image/ExifTool/Olympus.pm +3 -2
  42. data/bin/lib/Image/ExifTool/Panasonic.pm +21 -4
  43. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +25 -5
  44. data/bin/lib/Image/ExifTool/Parrot.pm +96 -2
  45. data/bin/lib/Image/ExifTool/Pentax.pm +7 -2
  46. data/bin/lib/Image/ExifTool/Photoshop.pm +29 -3
  47. data/bin/lib/Image/ExifTool/QuickTime.pm +163 -13
  48. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +119 -13
  49. data/bin/lib/Image/ExifTool/README +13 -3
  50. data/bin/lib/Image/ExifTool/RIFF.pm +106 -9
  51. data/bin/lib/Image/ExifTool/Samsung.pm +2 -2
  52. data/bin/lib/Image/ExifTool/Sigma.pm +27 -1
  53. data/bin/lib/Image/ExifTool/SigmaRaw.pm +37 -13
  54. data/bin/lib/Image/ExifTool/Sony.pm +71 -43
  55. data/bin/lib/Image/ExifTool/TagInfoXML.pm +3 -1
  56. data/bin/lib/Image/ExifTool/TagLookup.pm +4737 -4517
  57. data/bin/lib/Image/ExifTool/TagNames.pod +1837 -1417
  58. data/bin/lib/Image/ExifTool/Text.pm +3 -4
  59. data/bin/lib/Image/ExifTool/Torrent.pm +2 -3
  60. data/bin/lib/Image/ExifTool/Validate.pm +3 -3
  61. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +7 -0
  62. data/bin/lib/Image/ExifTool/WriteExif.pl +100 -23
  63. data/bin/lib/Image/ExifTool/WriteIPTC.pl +2 -6
  64. data/bin/lib/Image/ExifTool/WritePhotoshop.pl +5 -5
  65. data/bin/lib/Image/ExifTool/WriteRIFF.pl +359 -0
  66. data/bin/lib/Image/ExifTool/Writer.pl +13 -5
  67. data/bin/lib/Image/ExifTool/XMP.pm +78 -59
  68. data/bin/lib/Image/ExifTool/XMP2.pl +19 -4
  69. data/bin/lib/Image/ExifTool.pm +111 -24
  70. data/bin/lib/Image/ExifTool.pod +83 -69
  71. data/bin/perl-Image-ExifTool.spec +43 -43
  72. data/lib/exiftool_vendored/version.rb +1 -1
  73. metadata +9 -4
@@ -395,7 +395,9 @@ numerical, and generated automatically otherwise.
395
395
  be accessible.
396
396
 
397
397
  'Hidden' - set to hide tag from the TagName documentation.
398
- Also suppresses verbose output of a BinaryData tag.
398
+ Also suppresses verbose output of a BinaryData tag. The
399
+ RawConv of a Hidden tag should return undef so the tag value
400
+ is not seen by the user.
399
401
 
400
402
  'IsComposite' - flag set for Composite tags
401
403
 
@@ -531,7 +533,8 @@ numerical, and generated automatically otherwise.
531
533
  SubIFD's where the PutFirst flag is valid.
532
534
 
533
535
  'Unknown' - this is an unknown tag (only extracted when the
534
- Unknown option is set).
536
+ Unknown option is set). This is set to 2 for Unknown tags in
537
+ binary tables (extracted when Unknown is 2).
535
538
 
536
539
  'WriteNothing' - flag indicating that nothing is actually
537
540
  written when this tag is set. It is a fake writable tag that
@@ -717,7 +720,7 @@ numerical, and generated automatically otherwise.
717
720
  condition exists, then a 'true' condition is assumed. The
718
721
  expression may use $self to access the ExifTool object. The
719
722
  first 128 bytes of the raw data value are accessible through
720
- the reference $valPt for EXIF, Jpeg2000, QuickTime and
723
+ the reference $valPt for EXIF, Jpeg2000, QuickTime, FLAC and
721
724
  BinaryData tags only (note that for BinaryData tags, the raw
722
725
  data of $$valPt is always 'undef' type, and may not be used
723
726
  when writing except for SubDirectory tags). EXIF tags (and
@@ -964,6 +967,10 @@ numerical, and generated automatically otherwise.
964
967
  OtherLang : [reserved] Used internally by QuickTime module to store a list
965
968
  of tag ID's for alternate-language tags based on this one.
966
969
 
970
+ ParentTagInfo : [reserved] Used internally to store a reference to the tag
971
+ information hash of the parent structure for flattened
972
+ structure tags.
973
+
967
974
  RootTagInfo : [reserved] Used internally to store a reference to the tag
968
975
  information hash of the top-level structure for flattened
969
976
  structure tags.
@@ -975,6 +982,9 @@ numerical, and generated automatically otherwise.
975
982
  alternate language tags (eg. 'fr'). Only used with formats
976
983
  which support alternate languages (eg. XMP, MIE, etc).
977
984
 
985
+ AddedUnknown : [reserved] Used internally to mark Unknown tags that were
986
+ added to the table at run time.
987
+
978
988
  SubDirectory { If it exists, this specifies the start of a new subdirectory.
979
989
  It contains a collection of variables which specify the type
980
990
  and location of the subdirectory. Note that ValueConv and
@@ -27,15 +27,16 @@
27
27
  package Image::ExifTool::RIFF;
28
28
 
29
29
  use strict;
30
- use vars qw($VERSION);
30
+ use vars qw($VERSION $AUTOLOAD);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
 
33
- $VERSION = '1.59';
33
+ $VERSION = '1.61';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
37
37
  sub ProcessSLLT($$$);
38
38
  sub ProcessLucas($$$);
39
+ sub WriteRIFF($$);
39
40
 
40
41
  # recognized RIFF variants
41
42
  my %riffType = (
@@ -340,6 +341,9 @@ my %code2charset = (
340
341
  Large AVI videos may be a concatenation of two or more RIFF chunks. For
341
342
  these files, information is extracted from subsequent RIFF chunks as
342
343
  sub-documents, but the Duration is calculated for the full video.
344
+
345
+ ExifTool currently has the ability to write EXIF, XMP and ICC_Profile
346
+ metadata to WEBP images, but can't yet write to other RIFF-based formats.
343
347
  },
344
348
  # (not 100% sure that the concatenation technique mentioned above is valid - PH)
345
349
  'fmt ' => {
@@ -544,7 +548,7 @@ my %code2charset = (
544
548
  },
545
549
  },{ # (WebP) - have also seen with "Exif\0\0" header - PH
546
550
  Name => 'EXIF',
547
- Condition => '$$valPt =~ /^Exif\0\0(II\x2a\0|MM\0\x2a)/',
551
+ Condition => '$$valPt =~ /^Exif\0\0(II\x2a\0|MM\0\x2a)/ and $self->Warn("Improper EXIF header",1)',
548
552
  SubDirectory => {
549
553
  TagTable => 'Image::ExifTool::Exif::Main',
550
554
  ProcessProc => \&Image::ExifTool::ProcessTIFF,
@@ -636,6 +640,11 @@ my %code2charset = (
636
640
  },
637
641
  # gpsa - seen hex "01 20 00 00", same as QuickTime
638
642
  # gsea - 16 bytes hex "04 08 02 00 20 02 00 00 1f 03 00 00 01 00 00 00"
643
+
644
+ acid => { # writen by Acidizer
645
+ Name => 'Acidizer',
646
+ SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Acidizer' },
647
+ },
639
648
  );
640
649
 
641
650
  # the maker notes used by some digital cameras
@@ -1249,6 +1258,7 @@ my %code2charset = (
1249
1258
  Name => 'ImageWidth',
1250
1259
  Format => 'int16u',
1251
1260
  Mask => 0x3fff,
1261
+ Priority => 0,
1252
1262
  },
1253
1263
  6.1 => {
1254
1264
  Name => 'HorizontalScale',
@@ -1259,6 +1269,7 @@ my %code2charset = (
1259
1269
  Name => 'ImageHeight',
1260
1270
  Format => 'int16u',
1261
1271
  Mask => 0x3fff,
1272
+ Priority => 0,
1262
1273
  },
1263
1274
  8.1 => {
1264
1275
  Name => 'VerticalScale',
@@ -1275,11 +1286,13 @@ my %code2charset = (
1275
1286
  1 => {
1276
1287
  Name => 'ImageWidth',
1277
1288
  Format => 'int16u',
1289
+ Priority => 0,
1278
1290
  ValueConv => '($val & 0x3fff) + 1',
1279
1291
  },
1280
1292
  2 => {
1281
1293
  Name => 'ImageHeight',
1282
1294
  Format => 'int32u',
1295
+ Priority => 0,
1283
1296
  ValueConv => '(($val >> 6) & 0x3fff) + 1',
1284
1297
  },
1285
1298
  );
@@ -1290,6 +1303,19 @@ my %code2charset = (
1290
1303
  GROUPS => { 2 => 'Image' },
1291
1304
  NOTES => 'This chunk is found in extended WebP files.',
1292
1305
  # 0 - bitmask: 2=ICC, 3=alpha, 4=EXIF, 5=XMP, 6=animation
1306
+ 0 => {
1307
+ Name => 'WebP_Flags',
1308
+ Description => 'WebP Flags',
1309
+ Notes => 'flags used in Extended WebP images',
1310
+ Format => 'int32u',
1311
+ PrintConv => { BITMASK => {
1312
+ 1 => 'Animation',
1313
+ 2 => 'XMP',
1314
+ 3 => 'EXIF',
1315
+ 4 => 'Alpha',
1316
+ 5 => 'ICC Profile',
1317
+ }},
1318
+ },
1293
1319
  4 => {
1294
1320
  Name => 'ImageWidth',
1295
1321
  Format => 'int32u',
@@ -1420,6 +1446,54 @@ my %code2charset = (
1420
1446
  },
1421
1447
  );
1422
1448
 
1449
+ # Acidizer information (ref https://forums.cockos.com/showthread.php?t=227118)
1450
+ %Image::ExifTool::RIFF::Acidizer = (
1451
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1452
+ GROUPS => { 2 => 'Audio' },
1453
+ 0 => {
1454
+ Name => 'AcidizerFlags',
1455
+ Format => 'int32u',
1456
+ PrintConv => { BITMASK => {
1457
+ 0 => 'One shot',
1458
+ 1 => 'Root note set',
1459
+ 2 => 'Stretch',
1460
+ 3 => 'Disk-based',
1461
+ 4 => 'High octave',
1462
+ }},
1463
+ },
1464
+ 4 => {
1465
+ Name => 'RootNote',
1466
+ Format => 'int16u',
1467
+ PrintConv => {
1468
+ 0x30 => 'C', 0x3c => 'High C',
1469
+ 0x31 => 'C#', 0x3d => 'High C#',
1470
+ 0x32 => 'D', 0x3e => 'High D',
1471
+ 0x33 => 'D#', 0x3f => 'High D#',
1472
+ 0x34 => 'E', 0x40 => 'High E',
1473
+ 0x35 => 'F', 0x41 => 'High F',
1474
+ 0x36 => 'F#', 0x42 => 'High F#',
1475
+ 0x37 => 'G', 0x43 => 'High G',
1476
+ 0x38 => 'G#', 0x44 => 'High G#',
1477
+ 0x39 => 'A', 0x45 => 'High A',
1478
+ 0x3a => 'A#', 0x46 => 'High A#',
1479
+ 0x3b => 'B', 0x47 => 'High B',
1480
+ },
1481
+ },
1482
+ 12 => {
1483
+ Name => 'Beats',
1484
+ Format => 'int32u',
1485
+ },
1486
+ 16 => {
1487
+ Name => 'Meter',
1488
+ Format => 'int16u[2]',
1489
+ PrintConv => '$val =~ s/(\d+) (\d+)/$2\/$1/; $val', # denominator comes first, so swap them
1490
+ },
1491
+ 20 => {
1492
+ Name => 'Tempo',
1493
+ Format => 'float',
1494
+ },
1495
+ );
1496
+
1423
1497
  # RIFF composite tags
1424
1498
  %Image::ExifTool::RIFF::Composite = (
1425
1499
  Duration => {
@@ -1459,6 +1533,14 @@ my %code2charset = (
1459
1533
  Image::ExifTool::AddCompositeTags('Image::ExifTool::RIFF');
1460
1534
 
1461
1535
 
1536
+ #------------------------------------------------------------------------------
1537
+ # AutoLoad our writer routines when necessary
1538
+ #
1539
+ sub AUTOLOAD
1540
+ {
1541
+ return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
1542
+ }
1543
+
1462
1544
  #------------------------------------------------------------------------------
1463
1545
  # Convert RIFF date to EXIF format
1464
1546
  my %monthNum = (
@@ -1642,7 +1724,7 @@ sub ProcessChunks($$$)
1642
1724
  my $start = $$dirInfo{DirStart};
1643
1725
  my $size = $$dirInfo{DirLen};
1644
1726
  my $end = $start + $size;
1645
- my $base = $$dirInfo{Base};
1727
+ my $base = $$dirInfo{Base} || 0;
1646
1728
  my $verbose = $et->Options('Verbose');
1647
1729
  my $unknown = $et->Options('Unknown');
1648
1730
  my $charset = $et->Options('CharsetRIFF');
@@ -1896,6 +1978,7 @@ sub ProcessRIFF($$)
1896
1978
  my ($buff, $buf2, $type, $mime, $err, $rf64);
1897
1979
  my $verbose = $et->Options('Verbose');
1898
1980
  my $unknown = $et->Options('Unknown');
1981
+ my $validate = $et->Options('Validate');
1899
1982
  my $ee = $et->Options('ExtractEmbedded');
1900
1983
 
1901
1984
  # verify this is a valid RIFF file
@@ -1917,6 +2000,8 @@ sub ProcessRIFF($$)
1917
2000
  $$et{RIFFStreamType} = ''; # initialize stream type
1918
2001
  $$et{RIFFStreamCodec} = []; # initialize codec array
1919
2002
  SetByteOrder('II');
2003
+ my $riffEnd = Get32u(\$buff, 4) + 8;
2004
+ $riffEnd += $riffEnd & 0x01; # (account for padding)
1920
2005
  my $tagTbl = GetTagTable('Image::ExifTool::RIFF::Main');
1921
2006
  my $pos = 12;
1922
2007
  #
@@ -1926,10 +2011,13 @@ sub ProcessRIFF($$)
1926
2011
  my $num = $raf->Read($buff, 8);
1927
2012
  if ($num < 8) {
1928
2013
  $err = 1 if $num;
2014
+ $et->Warn('Incorrect RIFF chunk size' . " $pos vs. $riffEnd") if $validate and $pos != $riffEnd;
1929
2015
  last;
1930
2016
  }
1931
2017
  $pos += 8;
1932
2018
  my ($tag, $len) = unpack('a4V', $buff);
2019
+ # tweak WEBP type if this is an extended WebP
2020
+ $et->OverrideFileType('Extended WEBP',undef,'webp') if $tag eq 'VP8X' and $type eq 'WEBP';
1933
2021
  # special case: construct new tag name from specific LIST type
1934
2022
  if ($tag eq 'LIST') {
1935
2023
  $raf->Read($buff, 4) == 4 or $err=1, last;
@@ -1949,7 +2037,6 @@ sub ProcessRIFF($$)
1949
2037
  } else {
1950
2038
  next;
1951
2039
  }
1952
- last;
1953
2040
  }
1954
2041
  # stop when we hit the audio data or AVI index or AVI movie data
1955
2042
  # --> no more because Adobe Bridge stores XMP after this!!
@@ -1969,6 +2056,7 @@ sub ProcessRIFF($$)
1969
2056
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
1970
2057
  }
1971
2058
  my $tagInfo = $$tagTbl{$tag};
2059
+ # (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
1972
2060
  if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
1973
2061
  $raf->Read($buff, $len2) == $len2 or $err=1, last;
1974
2062
  my $setGroups;
@@ -1980,7 +2068,7 @@ sub ProcessRIFF($$)
1980
2068
  DataPt => \$buff,
1981
2069
  DataPos => 0, # (relative to Base)
1982
2070
  Start => 0,
1983
- Size => $len2,
2071
+ Size => $len,
1984
2072
  Base => $pos,
1985
2073
  );
1986
2074
  if ($setGroups) {
@@ -1989,10 +2077,14 @@ sub ProcessRIFF($$)
1989
2077
  }
1990
2078
  delete $$et{DOC_NUM} if $ee;
1991
2079
  } elsif ($tag eq 'RIFF') {
2080
+ $et->Warn('Incorrect RIFF chunk size') if $validate and $pos - 8 != $riffEnd;
2081
+ $riffEnd += $len2 + 8;
1992
2082
  # don't read into RIFF chunk (eg. concatenated video file)
1993
- $raf->Read($buff, 4) == 4 or $err=1, last;
2083
+ $raf->Read($buff, 4) == 4 or $err=1, last; # (skip RIFF type word)
2084
+ $pos += 4;
1994
2085
  # extract information from remaining file as an embedded file
1995
- $$et{DOC_NUM} = ++$$et{DOC_COUNT}
2086
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2087
+ next; # (must not increment $pos)
1996
2088
  } elsif ($tag eq 'LIST_movi' and $ee) {
1997
2089
  next; # parse into movi chunk
1998
2090
  } else {
@@ -2000,7 +2092,12 @@ sub ProcessRIFF($$)
2000
2092
  $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2001
2093
  last;
2002
2094
  }
2003
- $raf->Seek($len2, 1) or $err=1, last;
2095
+ if ($validate and $len2) {
2096
+ # (must actually try to read something after seeking to detect error)
2097
+ $raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, last;
2098
+ } else {
2099
+ $raf->Seek($len2, 1) or $err=1, last;
2100
+ }
2004
2101
  }
2005
2102
  $pos += $len2;
2006
2103
  }
@@ -22,7 +22,7 @@ use vars qw($VERSION %samsungLensTypes);
22
22
  use Image::ExifTool qw(:DataAccess :Utils);
23
23
  use Image::ExifTool::Exif;
24
24
 
25
- $VERSION = '1.52';
25
+ $VERSION = '1.53';
26
26
 
27
27
  sub WriteSTMN($$$);
28
28
  sub ProcessINFO($$$);
@@ -991,7 +991,7 @@ my %formatMinMax = (
991
991
  '0x0a01' => { #forum7161
992
992
  Name => 'TimeStamp',
993
993
  Groups => { 2 => 'Time' },
994
- ValueConv => 'ConvertUnixTime($val / 1e3, 1)',
994
+ ValueConv => 'ConvertUnixTime($val / 1e3, 1, 3)',
995
995
  PrintConv => '$self->ConvertDateTime($val)',
996
996
  },
997
997
  '0x0a20-name' => 'DualCameraImageName', # ("FlipPhoto_002")
@@ -19,7 +19,7 @@ use strict;
19
19
  use vars qw($VERSION %sigmaLensTypes);
20
20
  use Image::ExifTool::Exif;
21
21
 
22
- $VERSION = '1.31';
22
+ $VERSION = '1.32';
23
23
 
24
24
  # sigma LensType lookup (ref IB)
25
25
  %sigmaLensTypes = (
@@ -226,9 +226,35 @@ $VERSION = '1.31';
226
226
  0x1008 => 'Sigma 50mm F2.8 Macro', #NJ (DP3 Quattro kit)
227
227
  0x1009 => 'Sigma 14mm F4', #NJ (DP0 Quattro kit)
228
228
  # L-mount lenses?:
229
+ 0x4001 => 'Lumix S 24-105mm F4 Macro OIS (S-R24105)', #IB
230
+ 0x4002 => 'Lumix S 70-200mm F4 OIS (S-R70200)', #IB
231
+ 0x4003 => 'Lumix S 50mm F1.4 (S-X50)', #IB
232
+ 0x4006 => 'Lumix S 24-70mm F2.8 (S-E2470)', #IB
233
+ 0x4007 => 'Lumix S 16-35mm F4 (S-R1635)', #IB
234
+ 0x4008 => 'Lumix S 70-200mm F2.8 OIS (S-E70200)', #IB
235
+ 0x4010 => 'Lumix S 35mm F1.8 (S-S35)', #IB
236
+ 0x4011 => 'LUMIX S 18mm F1.8 (S-S18)', #IB
237
+ 0x400b => 'Lumix S 20-60mm F3.5-5.6 (S-R2060)', #IB
238
+ 0x400c => 'Lumix S 85mm F1.8 (S-S85)', #IB
239
+ 0x400d => 'Lumix S 70-300 F4.5-5.6 Macro OIS (S-R70300)', #IB
240
+ 0x400f => 'Lumix S 24mm F1.8 (S-S24)', #IB
229
241
  0x6001 => 'Sigma 150-600mm F5-6.3 DG OS HSM | S', #PH (NC, fp)
230
242
  0x6003 => 'Sigma 45mm F2.8 DG DN | C', #PH (NC, fp)
243
+ 0x6005 => 'Sigma 14-24mm F2.8 DG DN | A', #IB
231
244
  0x6006 => 'Sigma 50mm F1.4 DG HSM | A', #IB (014)
245
+ 0x6011 => 'Sigma 24-70mm F2.8 DG DN | A', #IB
246
+ 0x6012 => 'Sigma 100-400mm F5-6.3 DG DN OS | C', #IB
247
+ 0x6013 => 'Sigma 100-400mm F5-6.3 DG DN OS | C + TC-1411', #IB
248
+ 0x6015 => 'Sigma 85mm F1.4 DG DN | A', #IB
249
+ 0x6017 => 'Sigma 65mm F2 DG DN | C', #IB
250
+ 0x6018 => 'Sigma 35mm F2 DG DN | C', #IB
251
+ 0x601a => 'Sigma 28-70mm F2.8 DG DN | C', #IB
252
+ 0x601b => 'Sigma 150-600mm F5-6.3 DG DN OS | S', #IB
253
+ 0x6020 => 'Sigma 35mm F1.4 DG DN | A', #IB
254
+ 0x6021 => 'Sigma 90mm F2.8 DG DN | C', #IB
255
+ 0x6023 => 'Sigma 20mm F2 DG DN | C', #IB
256
+ 0x6025 => 'Sigma 20mm F1.4 DG DN | A', #IB
257
+ 0x6026 => 'Sigma 24mm F1.4 DG DN | A', #IB
232
258
  0x8005 => 'Sigma 35mm F1.4 DG HSM | A', #PH (012)
233
259
  0x8009 => 'Sigma 18-35mm F1.8 DC HSM | A', #PH
234
260
  0x8900 => 'Sigma 70-300mm F4-5.6 DG OS', #PH (SD15)
@@ -16,7 +16,7 @@ use vars qw($VERSION);
16
16
  use Image::ExifTool qw(:DataAccess :Utils);
17
17
  use Image::ExifTool::Sigma;
18
18
 
19
- $VERSION = '1.27';
19
+ $VERSION = '1.29';
20
20
 
21
21
  sub ProcessX3FHeader($$$);
22
22
  sub ProcessX3FDirectory($$$);
@@ -385,14 +385,14 @@ sub WriteX3F($$)
385
385
  my ($et, $dirInfo) = @_;
386
386
  my $raf = $$dirInfo{RAF};
387
387
  my $outfile = $$dirInfo{OutFile};
388
- my ($outDir, $buff, $ver, $entries, $dir, $outPos, $index, $didContain);
388
+ my ($hdr, $buff, $ver, $entries, $dir, $outPos, $index, $didContain, %order, @order);
389
389
 
390
390
  $raf->Seek($$dirInfo{DirStart}, 0) or return 'Error seeking to directory start';
391
391
 
392
392
  # read the X3F directory header (will be copied directly to output)
393
- $raf->Read($outDir, 12) == 12 or return 'Truncated X3F image';
394
- $outDir =~ /^SECd/ or return 'Bad section header';
395
- ($ver, $entries) = unpack('x4V2', $outDir);
393
+ $raf->Read($hdr, 12) == 12 or return 'Truncated X3F image';
394
+ $hdr =~ /^SECd/ or return 'Bad section header';
395
+ ($ver, $entries) = unpack('x4V2', $hdr);
396
396
 
397
397
  # do sanity check on number of entries in directory
398
398
  return 'Invalid X3F directory count' unless $entries > 2 and $entries < 20;
@@ -400,12 +400,16 @@ sub WriteX3F($$)
400
400
  unless ($raf->Read($dir, $entries * 12) == $entries * 12) {
401
401
  return 'Truncated X3F directory';
402
402
  }
403
- # do a quick scan to determine the offset of the first data subsection
403
+ # do a quick scan to determine the offset of the first data subsection,
404
+ # and the order in which the actual data is stored in the file
404
405
  for ($index=0; $index<$entries; ++$index) {
405
406
  my $pos = $index * 12;
406
407
  my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
407
408
  # remember position of first data subsection
408
409
  $outPos = $offset if not defined $outPos or $outPos > $offset;
410
+ # save the order of the data
411
+ $order{BAD} = 1 if defined $order{$offset};
412
+ $order{$offset} = $index;
409
413
  }
410
414
  # copy the file header up to the start of the first data subsection
411
415
  unless ($raf->Seek(0,0) and $raf->Read($buff, $outPos) == $outPos) {
@@ -413,8 +417,25 @@ sub WriteX3F($$)
413
417
  }
414
418
  Write($outfile, $buff) or return -1;
415
419
 
416
- # loop through directory, rewriting each section
417
- for ($index=0; $index<$entries; ++$index) {
420
+ # this is a bit tricky/unfortunate: the current version of Sigma Photo Pro
421
+ # (2022-10-18) is sensitive to the order of the data sections, and these may
422
+ # differ from the order of their respective entries in the footer. To patch
423
+ # this, instead of looping through the footer sections in order, we process
424
+ # them in the order of the offsets they contain, writing their referenced data
425
+ # sequentially as we go. This preserves both the order of the data sections
426
+ # and the order of the footer entries. (Note that the upcoming release of
427
+ # Sigma Photo Pro will fix this issue at their end, but this patch will remain
428
+ # to maintain backward compatibilty with older SPP versions.)
429
+ if ($order{BAD}) {
430
+ # (this could perhaps happen if any of the sections is ever zero-length)
431
+ $et->Error('Double-referenced data in footer directory!', 1);
432
+ @order = ( 0 .. $entries-1 );
433
+ } else {
434
+ @order = map $order{$_}, sort { $a <=> $b } keys %order;
435
+ }
436
+
437
+ # loop through footer directory, rewriting each section
438
+ foreach $index (@order) {
418
439
 
419
440
  my $pos = $index * 12;
420
441
  my ($offset, $len, $tag) = unpack("x${pos}V2a4", $dir);
@@ -450,6 +471,8 @@ sub WriteX3F($$)
450
471
  return -1 if $success < 0;
451
472
  # (this shouldn't happen unless someone tries to delete the EXIF...)
452
473
  return 'EXIF segment must come first in X3F JpgFromRaw' unless $newData =~ /^\xff\xd8\xff\xe1/;
474
+ # trim off any extra null bytes (since section length includes padding -- silly Sigma)
475
+ $newData =~ s/\0+$//;
453
476
  # write new data if anything changed, otherwise copy old image
454
477
  my $outPt = $$et{CHANGED} ? \$newData : \$buff;
455
478
  Write($outfile, $$outPt) or return -1;
@@ -468,20 +491,21 @@ sub WriteX3F($$)
468
491
  # copy data for this subsection
469
492
  Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F directory';
470
493
  }
471
- # add directory entry and update output file position
472
- $outDir .= pack('V2a4', $outPos, $len, $tag);
473
- $outPos += $len;
474
494
  # pad data to an even 4-byte boundary
495
+ # (stored length includes padding! ref Sigma engineer Yuki Miyahara)
475
496
  if ($len & 0x03) {
476
497
  my $pad = 4 - ($len & 0x03);
477
498
  Write($outfile, "\0" x $pad) or return -1;
478
- $outPos += $pad;
499
+ $len += $pad;
479
500
  }
501
+ # update footer entry with new offset/size
502
+ substr($dir, $pos, 8) = pack('V2', $outPos, $len);
503
+ $outPos += $len;
480
504
  }
481
505
  # warn if we couldn't add metadata to this image (should only be SD9 or SD10)
482
506
  $didContain or $et->Warn("Can't yet write SD9 or SD10 X3F images");
483
507
  # write out the directory and the directory pointer, and we are done
484
- Write($outfile, $outDir, pack('V', $outPos)) or return -1;
508
+ Write($outfile, $hdr, $dir, pack('V', $outPos)) or return -1;
485
509
  return undef;
486
510
  }
487
511