exiftool-vendored.exe 12.56.0 → 12.60.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 (54) hide show
  1. package/bin/exiftool_files/Changes +80 -5
  2. package/bin/exiftool_files/README +2 -2
  3. package/bin/exiftool_files/config_files/example.config +1 -0
  4. package/bin/exiftool_files/config_files/rotate_regions.config +1 -1
  5. package/bin/exiftool_files/exiftool.pl +174 -99
  6. package/bin/exiftool_files/lib/Image/ExifTool/AIFF.pm +2 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/APE.pm +2 -2
  8. package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +19 -15
  9. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +26 -6
  10. package/bin/exiftool_files/lib/Image/ExifTool/CanonRaw.pm +5 -1
  11. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +28 -2
  12. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +77 -19
  13. package/bin/exiftool_files/lib/Image/ExifTool/FlashPix.pm +32 -10
  14. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +7 -3
  15. package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +7 -2
  16. package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +30 -7
  17. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +14 -2
  18. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +5 -5
  19. package/bin/exiftool_files/lib/Image/ExifTool/LIF.pm +10 -2
  20. package/bin/exiftool_files/lib/Image/ExifTool/LNK.pm +5 -4
  21. package/bin/exiftool_files/lib/Image/ExifTool/MIE.pm +3 -3
  22. package/bin/exiftool_files/lib/Image/ExifTool/MPEG.pm +2 -2
  23. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +3 -2
  24. package/bin/exiftool_files/lib/Image/ExifTool/Minolta.pm +6 -7
  25. package/bin/exiftool_files/lib/Image/ExifTool/MinoltaRaw.pm +2 -1
  26. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +1003 -907
  27. package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +2 -2
  28. package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +1 -1
  29. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +88 -6
  30. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +10 -2
  31. package/bin/exiftool_files/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
  32. package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +8 -5
  33. package/bin/exiftool_files/lib/Image/ExifTool/PhaseOne.pm +14 -1
  34. package/bin/exiftool_files/lib/Image/ExifTool/Photoshop.pm +38 -7
  35. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +44 -13
  36. package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +40 -6
  37. package/bin/exiftool_files/lib/Image/ExifTool/README +19 -2
  38. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +34 -13
  39. package/bin/exiftool_files/lib/Image/ExifTool/Rawzor.pm +2 -2
  40. package/bin/exiftool_files/lib/Image/ExifTool/Ricoh.pm +2 -1
  41. package/bin/exiftool_files/lib/Image/ExifTool/Sigma.pm +5 -4
  42. package/bin/exiftool_files/lib/Image/ExifTool/SigmaRaw.pm +9 -3
  43. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +24 -1
  44. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +4678 -4628
  45. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +305 -113
  46. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +5 -5
  47. package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +42 -0
  48. package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +1 -1
  49. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +150 -36
  50. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +19 -4
  51. package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +2 -1
  52. package/bin/exiftool_files/lib/Image/ExifTool.pm +195 -42
  53. package/bin/exiftool_files/lib/Image/ExifTool.pod +44 -9
  54. package/package.json +2 -2
@@ -56,7 +56,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
56
56
  use Image::ExifTool qw(:DataAccess :Utils);
57
57
  use Image::ExifTool::MakerNotes;
58
58
 
59
- $VERSION = '4.43';
59
+ $VERSION = '4.44';
60
60
 
61
61
  sub ProcessExif($$$);
62
62
  sub WriteExif($$$);
@@ -65,6 +65,7 @@ sub RebuildMakerNotes($$$);
65
65
  sub EncodeExifText($$);
66
66
  sub ValidateIFD($;$);
67
67
  sub ValidateImageData($$$;$);
68
+ sub AddImageDataMD5($$$);
68
69
  sub ProcessTiffIFD($$$);
69
70
  sub PrintParameter($$$);
70
71
  sub GetOffList($$$$$);
@@ -573,6 +574,7 @@ my %opcodeInfo = (
573
574
  ],
574
575
  Name => 'StripOffsets',
575
576
  IsOffset => 1,
577
+ IsImageData => 1,
576
578
  OffsetPair => 0x117, # point to associated byte counts
577
579
  # A200 stores this information in the wrong byte order!!
578
580
  ValueConv => '$val=join(" ",unpack("N*",pack("V*",split(" ",$val))));\$val',
@@ -582,6 +584,7 @@ my %opcodeInfo = (
582
584
  Condition => '$$self{Compression} and $$self{Compression} eq "34892"', # DNG Lossy JPEG
583
585
  Name => 'OtherImageStart',
584
586
  IsOffset => 1,
587
+ IsImageData => 1,
585
588
  OffsetPair => 0x117, # point to associated byte counts
586
589
  DataTag => 'OtherImage',
587
590
  },
@@ -594,6 +597,7 @@ my %opcodeInfo = (
594
597
  ],
595
598
  Name => 'StripOffsets',
596
599
  IsOffset => 1,
600
+ IsImageData => 1,
597
601
  OffsetPair => 0x117, # point to associated byte counts
598
602
  ValueConv => 'length($val) > 32 ? \$val : $val',
599
603
  },
@@ -630,6 +634,7 @@ my %opcodeInfo = (
630
634
  # JpgFromRawStart in various IFD's of DNG images except SubIFD2
631
635
  Name => 'JpgFromRawStart',
632
636
  IsOffset => 1,
637
+ IsImageData => 1,
633
638
  OffsetPair => 0x117,
634
639
  DataTag => 'JpgFromRaw',
635
640
  Writable => 'int32u',
@@ -933,6 +938,7 @@ my %opcodeInfo = (
933
938
  0x144 => {
934
939
  Name => 'TileOffsets',
935
940
  IsOffset => 1,
941
+ IsImageData => 1,
936
942
  OffsetPair => 0x145,
937
943
  ValueConv => 'length($val) > 32 ? \$val : $val',
938
944
  },
@@ -1187,6 +1193,7 @@ my %opcodeInfo = (
1187
1193
  Name => 'JpgFromRawStart',
1188
1194
  Condition => '$$self{DIR_NAME} eq "SubIFD"',
1189
1195
  IsOffset => 1,
1196
+ IsImageData => 1,
1190
1197
  OffsetPair => 0x202,
1191
1198
  DataTag => 'JpgFromRaw',
1192
1199
  Writable => 'int32u',
@@ -1199,6 +1206,7 @@ my %opcodeInfo = (
1199
1206
  Name => 'JpgFromRawStart',
1200
1207
  Condition => '$$self{DIR_NAME} eq "IFD2"',
1201
1208
  IsOffset => 1,
1209
+ IsImageData => 1,
1202
1210
  OffsetPair => 0x202,
1203
1211
  DataTag => 'JpgFromRaw',
1204
1212
  Writable => 'int32u',
@@ -1210,6 +1218,7 @@ my %opcodeInfo = (
1210
1218
  {
1211
1219
  Name => 'OtherImageStart',
1212
1220
  Condition => '$$self{DIR_NAME} eq "SubIFD1"',
1221
+ IsImageData => 1,
1213
1222
  IsOffset => 1,
1214
1223
  OffsetPair => 0x202,
1215
1224
  DataTag => 'OtherImage',
@@ -1222,6 +1231,7 @@ my %opcodeInfo = (
1222
1231
  Name => 'OtherImageStart',
1223
1232
  Condition => '$$self{DIR_NAME} eq "SubIFD2"',
1224
1233
  IsOffset => 1,
1234
+ IsImageData => 1,
1225
1235
  OffsetPair => 0x202,
1226
1236
  DataTag => 'OtherImage',
1227
1237
  Writable => 'int32u',
@@ -1232,6 +1242,7 @@ my %opcodeInfo = (
1232
1242
  {
1233
1243
  Name => 'OtherImageStart',
1234
1244
  IsOffset => 1,
1245
+ IsImageData => 1,
1235
1246
  OffsetPair => 0x202,
1236
1247
  },
1237
1248
  ],
@@ -1500,9 +1511,10 @@ my %opcodeInfo = (
1500
1511
  0x7031 => {
1501
1512
  Name => 'VignettingCorrection',
1502
1513
  Notes => 'found in Sony ARW images',
1503
- Protected => 1,
1504
1514
  Writable => 'int16s',
1505
1515
  WriteGroup => 'SubIFD',
1516
+ Permanent => 1,
1517
+ Protected => 1,
1506
1518
  PrintConv => {
1507
1519
  256 => 'Off',
1508
1520
  257 => 'Auto',
@@ -1513,17 +1525,19 @@ my %opcodeInfo = (
1513
1525
  0x7032 => {
1514
1526
  Name => 'VignettingCorrParams', #forum7640
1515
1527
  Notes => 'found in Sony ARW images',
1516
- Protected => 1,
1517
1528
  Writable => 'int16s',
1518
1529
  WriteGroup => 'SubIFD',
1519
1530
  Count => 17,
1531
+ Permanent => 1,
1532
+ Protected => 1,
1520
1533
  },
1521
1534
  0x7034 => {
1522
1535
  Name => 'ChromaticAberrationCorrection',
1523
1536
  Notes => 'found in Sony ARW images',
1524
- Protected => 1,
1525
1537
  Writable => 'int16s',
1526
1538
  WriteGroup => 'SubIFD',
1539
+ Permanent => 1,
1540
+ Protected => 1,
1527
1541
  PrintConv => {
1528
1542
  0 => 'Off',
1529
1543
  1 => 'Auto',
@@ -1533,17 +1547,19 @@ my %opcodeInfo = (
1533
1547
  0x7035 => {
1534
1548
  Name => 'ChromaticAberrationCorrParams', #forum6509
1535
1549
  Notes => 'found in Sony ARW images',
1536
- Protected => 1,
1537
1550
  Writable => 'int16s',
1538
1551
  WriteGroup => 'SubIFD',
1539
1552
  Count => 33,
1553
+ Permanent => 1,
1554
+ Protected => 1,
1540
1555
  },
1541
1556
  0x7036 => {
1542
1557
  Name => 'DistortionCorrection',
1543
1558
  Notes => 'found in Sony ARW images',
1544
- Protected => 1,
1545
1559
  Writable => 'int16s',
1546
1560
  WriteGroup => 'SubIFD',
1561
+ Permanent => 1,
1562
+ Protected => 1,
1547
1563
  PrintConv => {
1548
1564
  0 => 'Off',
1549
1565
  1 => 'Auto',
@@ -1554,10 +1570,38 @@ my %opcodeInfo = (
1554
1570
  0x7037 => {
1555
1571
  Name => 'DistortionCorrParams', #forum6509
1556
1572
  Notes => 'found in Sony ARW images',
1557
- Protected => 1,
1558
1573
  Writable => 'int16s',
1559
1574
  WriteGroup => 'SubIFD',
1560
1575
  Count => 17,
1576
+ Permanent => 1,
1577
+ Protected => 1,
1578
+ },
1579
+ 0x7038 => { #github#195 (Sony ARW)
1580
+ Name => 'SonyRawImageSize',
1581
+ Notes => 'size of actual image in Sony ARW files',
1582
+ Writable => 'int32u',
1583
+ WriteGroup => 'SubIFD',
1584
+ Count => 2,
1585
+ Permanent => 1,
1586
+ Protected => 1,
1587
+ },
1588
+ 0x7310 => { #github#195 (Sony ARW)
1589
+ Name => 'BlackLevel',
1590
+ Notes => 'found in Sony ARW images',
1591
+ Writable => 'int16u',
1592
+ WriteGroup => 'SubIFD',
1593
+ Count => 4,
1594
+ Permanent => 1,
1595
+ Protected => 1,
1596
+ },
1597
+ 0x7313 => { #github#195 (Sony ARW)
1598
+ Name => 'WB_RGGBLevels',
1599
+ Notes => 'found in Sony ARW images',
1600
+ Writable => 'int16s',
1601
+ WriteGroup => 'SubIFD',
1602
+ Count => 4,
1603
+ Permanent => 1,
1604
+ Protected => 1,
1561
1605
  },
1562
1606
  0x74c7 => { #IB (in ARW images from some Sony cameras)
1563
1607
  Name => 'SonyCropTopLeft',
@@ -2968,6 +3012,7 @@ my %opcodeInfo = (
2968
3012
  0xbcc0 => { #13
2969
3013
  Name => 'ImageOffset',
2970
3014
  IsOffset => 1,
3015
+ IsImageData => 1,
2971
3016
  OffsetPair => 0xbcc1, # point to associated byte count
2972
3017
  },
2973
3018
  0xbcc1 => { #13
@@ -2977,6 +3022,7 @@ my %opcodeInfo = (
2977
3022
  0xbcc2 => { #13
2978
3023
  Name => 'AlphaOffset',
2979
3024
  IsOffset => 1,
3025
+ IsImageData => 1,
2980
3026
  OffsetPair => 0xbcc3, # point to associated byte count
2981
3027
  },
2982
3028
  0xbcc3 => { #13
@@ -5880,15 +5926,17 @@ sub ProcessExif($$$)
5880
5926
  my $base = $$dirInfo{Base} || 0;
5881
5927
  my $firstBase = $base;
5882
5928
  my $raf = $$dirInfo{RAF};
5883
- my $verbose = $et->Options('Verbose');
5884
- my $validate = $et->Options('Validate');
5885
- my $saveFormat = $et->Options('SaveFormat');
5929
+ my ($verbose,$validate,$saveFormat) = @{$$et{OPTIONS}}{qw(Verbose Validate SaveFormat)};
5886
5930
  my $htmlDump = $$et{HTML_DUMP};
5887
5931
  my $success = 1;
5888
- my ($tagKey, $dirSize, $makerAddr, $strEnc, %offsetInfo, $offName, $nextOffName);
5932
+ my ($tagKey, $dirSize, $makerAddr, $strEnc, %offsetInfo, $offName, $nextOffName, $doMD5);
5889
5933
  my $inMakerNotes = $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
5890
5934
  my $isExif = ($tagTablePtr eq \%Image::ExifTool::Exif::Main);
5891
5935
 
5936
+ # set flag to calculate image data MD5 if requested
5937
+ $doMD5 = 1 if $$et{ImageDataMD5} and (($$et{FILE_TYPE} eq 'TIFF' and not $base and not $inMakerNotes) or
5938
+ ($$et{FILE_TYPE} eq 'RAF' and $dirName eq 'FujiIFD'));
5939
+
5892
5940
  # set encoding to assume for strings
5893
5941
  $strEnc = $et->Options('CharsetEXIF') if $$tagTablePtr{GROUPS}{0} eq 'EXIF';
5894
5942
 
@@ -5897,7 +5945,12 @@ sub ProcessExif($$$)
5897
5945
  $isExif and $$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/)
5898
5946
  {
5899
5947
  my $path = $et->MetadataPath();
5900
- unless ($path =~ /^(JPEG-APP1-IFD0|TIFF-IFD0|PSD-EXIFInfo-IFD0)$/) {
5948
+ if ($path =~ /^(JPEG-APP1-IFD0|TIFF-IFD0|PSD-EXIFInfo-IFD0)$/) {
5949
+ unless ($$et{DOC_NUM}) {
5950
+ $et->Warn("Duplicate EXIF at $path") if $$et{HasExif};
5951
+ $$et{HasExif} = 1;
5952
+ }
5953
+ } else {
5901
5954
  if ($Image::ExifTool::MWG::strict) {
5902
5955
  $et->Warn("Ignored non-standard EXIF at $path");
5903
5956
  return 0;
@@ -6361,10 +6414,10 @@ sub ProcessExif($$$)
6361
6414
  $tval .= " ($rational)" if defined $rational;
6362
6415
  if ($htmlDump) {
6363
6416
  my ($tagName, $colName);
6364
- if ($tagID == 0x927c and $dirName eq 'ExifIFD') {
6365
- $tagName = 'MakerNotes';
6366
- } elsif ($tagInfo) {
6417
+ if ($tagInfo) {
6367
6418
  $tagName = $$tagInfo{Name};
6419
+ } elsif ($tagID == 0x927c and $dirName eq 'ExifIFD') {
6420
+ $tagName = 'MakerNotes';
6368
6421
  } else {
6369
6422
  $tagName = sprintf("Tag 0x%.4x",$tagID);
6370
6423
  }
@@ -6439,6 +6492,9 @@ sub ProcessExif($$$)
6439
6492
  }
6440
6493
  # add value data block (underlining maker notes data)
6441
6494
  $et->HDump($exifDumpPos,$size,"$tagName value",'SAME', $flag, $sid);
6495
+ if ($subdir and $$tagInfo{MakerNotes} and $$tagInfo{NotIFD}) {
6496
+ $et->HDump($exifDumpPos,$size,"$tagName value",undef,undef,$$dirInfo{OffsetName});
6497
+ }
6442
6498
  }
6443
6499
  } else {
6444
6500
  if ($tagID <= $lastID and not $inMakerNotes) {
@@ -6725,7 +6781,7 @@ sub ProcessExif($$$)
6725
6781
  }
6726
6782
  $val = join(' ', @vals);
6727
6783
  }
6728
- if ($validate) {
6784
+ if ($validate or $doMD5) {
6729
6785
  if ($$tagInfo{OffsetPair}) {
6730
6786
  $offsetInfo{$tagID} = [ $tagInfo, $val ];
6731
6787
  } elsif ($saveForValidate{$tagID} and $isExif) {
@@ -6743,9 +6799,11 @@ sub ProcessExif($$$)
6743
6799
  }
6744
6800
  }
6745
6801
 
6746
- # validate image data offsets for this IFD
6747
- if ($validate and %offsetInfo) {
6748
- Image::ExifTool::Validate::ValidateOffsetInfo($et, \%offsetInfo, $$dirInfo{DirName}, $inMakerNotes)
6802
+ if (%offsetInfo) {
6803
+ # calculate image data MD5 if requested
6804
+ AddImageDataMD5($et, $dirInfo, \%offsetInfo) if $doMD5;
6805
+ # validate image data offsets for this IFD (note: modifies %offsetInfo)
6806
+ Image::ExifTool::Validate::ValidateOffsetInfo($et, \%offsetInfo, $dirName, $inMakerNotes) if $validate;
6749
6807
  }
6750
6808
 
6751
6809
  # scan for subsequent IFD's if specified
@@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
21
21
  use Image::ExifTool::Exif;
22
22
  use Image::ExifTool::ASF; # for GetGUID()
23
23
 
24
- $VERSION = '1.42';
24
+ $VERSION = '1.44';
25
25
 
26
26
  sub ProcessFPX($$);
27
27
  sub ProcessFPXR($$$);
@@ -318,6 +318,10 @@ my %fpxFileType = (
318
318
  unrecognized Windows Compound Binary file as a FlashPix (FPX) file. See
319
319
  L<http://graphcomp.com/info/specs/livepicture/fpx.pdf> for the FlashPix
320
320
  specification.
321
+
322
+ Note that Microsoft is not consistent with the time zone used for some
323
+ date/time tags, and it may be either UTC or local time depending on the
324
+ software used to create the file.
321
325
  },
322
326
  "\x05SummaryInformation" => {
323
327
  Name => 'SummaryInfo',
@@ -484,16 +488,27 @@ my %fpxFileType = (
484
488
  IeImg => {
485
489
  Name => 'EmbeddedImage',
486
490
  Notes => q{
487
- embedded images in Scene7 vignette VNT files. EmbeddedImageRectangle is
488
- generated for applicable images, and may be associated with the
489
- corresponding EmbeddedImage via the family 3 group name
491
+ embedded images in Scene7 vignette VNT files. The EmbeddedImage Class and
492
+ Rectangle are also extracted for applicable images, and may be associated
493
+ with the corresponding EmbeddedImage via the family 3 group name
490
494
  },
491
495
  Groups => { 2 => 'Preview' },
492
496
  Binary => 1,
493
497
  },
494
- IeImg_rect => { # (not a real tag -- extracted from Contents of VNT file)
498
+ IeImg_class => {
499
+ Name => 'EmbeddedImageClass',
500
+ Notes => q{
501
+ not a real tag. This information is extracted if available for the
502
+ corresponding EmbeddedImage from the Contents of a VNT file
503
+ },
504
+ # eg. "Cache", "Mask"
505
+ },
506
+ IeImg_rect => { #
495
507
  Name => 'EmbeddedImageRectangle',
496
- Hidden => 1,
508
+ Notes => q{
509
+ not a real tag. This information is extracted if available for the
510
+ corresponding EmbeddedImage from the Contents of a VNT file
511
+ },
497
512
  },
498
513
  );
499
514
 
@@ -1573,13 +1588,16 @@ sub ProcessContents($$$)
1573
1588
  pos($$dataPt) += $size;
1574
1589
  }
1575
1590
  $$et{IeImg_lkup} = { };
1576
- # - the byte after TargetRole1 is 0x0d or 0x11 for separate images in my samples,
1591
+ $$et{IeImg_class} = { };
1592
+ # - the byte before \x80 is 0x0d, 0x11 or 0x1f for separate images in my samples,
1577
1593
  # and 0x1c or 0x23 for inline masks
1578
- while ($$dataPt =~ /\x0bTargetRole1.\x80\0\0\x01.{4}(.{24})/sg) {
1579
- my ($index, @coords) = unpack('Vx4V4', $1);
1594
+ # - the byte after \xff\xff is 0x3b in my samples for $1 containing 'VnMask' or 'VnCache'
1595
+ while ($$dataPt =~ /\x0bTargetRole1(?:.\x80|\xff\xff.\0.\0Vn(\w+))\0\0\x01.{4}(.{24})/sg) {
1596
+ my ($index, @coords) = unpack('Vx4V4', $2);
1580
1597
  next if $index == 0xffffffff;
1581
1598
  $$et{IeImg_lkup}{$index} and $et->WarnOnce('Duplicate image index');
1582
1599
  $$et{IeImg_lkup}{$index} = "@coords";
1600
+ $$et{IeImg_class}{$index} = $1 if $1;
1583
1601
  }
1584
1602
  }
1585
1603
  }
@@ -2391,6 +2409,10 @@ sub ProcessFPX($$)
2391
2409
  # save position of this image
2392
2410
  $et->HandleTag($tagTablePtr, IeImg_rect => $$et{IeImg_lkup}{$num});
2393
2411
  delete $$et{IeImg_lkup}{$num};
2412
+ if ($$et{IeImg_class} and $$et{IeImg_class}{$num}) {
2413
+ $et->HandleTag($tagTablePtr, IeImg_class => $$et{IeImg_class}{$num});
2414
+ delete $$et{IeImg_class}{$num};
2415
+ }
2394
2416
  }
2395
2417
  delete $$et{DOC_NUM};
2396
2418
  } else {
@@ -2437,7 +2459,7 @@ sub ProcessFPX($$)
2437
2459
  }
2438
2460
  $$et{INDENT} = $oldIndent if $verbose;
2439
2461
  # try to better identify the file type
2440
- if ($$et{VALUE}{FileType} eq 'FPX') {
2462
+ if ($$et{FileType} eq 'FPX') {
2441
2463
  my $val = $$et{CompObjUserType} || $$et{Software};
2442
2464
  if ($val) {
2443
2465
  my %type = ( '^3ds Max' => 'MAX', Word => 'DOC', PowerPoint => 'PPT', Excel => 'XLS' );
@@ -1372,6 +1372,7 @@ my %faceCategories = (
1372
1372
  0xf007 => {
1373
1373
  Name => 'StripOffsets',
1374
1374
  IsOffset => 1,
1375
+ IsImageData => 1,
1375
1376
  OffsetPair => 0xf008, # point to associated byte counts
1376
1377
  },
1377
1378
  0xf008 => {
@@ -1670,11 +1671,11 @@ sub ProcessRAF($$)
1670
1671
  my ($rafNum, $ifdNum) = ('','');
1671
1672
  foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1672
1673
  last if $offset >= $jpos;
1673
- unless ($raf->Seek($offset, 0) and $raf->Read($buff, 4)) {
1674
+ unless ($raf->Seek($offset, 0) and $raf->Read($buff, 8)) {
1674
1675
  $warn = 1;
1675
1676
  last;
1676
1677
  }
1677
- my $start = unpack('N',$buff);
1678
+ my ($start, $len) = unpack('N2',$buff);
1678
1679
  next unless $start;
1679
1680
  if ($offset == 0x64 or $offset == 0x80) {
1680
1681
  # parse FujiIFD directory
@@ -1685,7 +1686,10 @@ sub ProcessRAF($$)
1685
1686
  $$et{SET_GROUP1} = "FujiIFD$ifdNum";
1686
1687
  my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::IFD');
1687
1688
  # this is TIFF-format data only for some models, so no warning if it fails
1688
- $et->ProcessTIFF(\%dirInfo, $tagTablePtr, \&Image::ExifTool::ProcessTIFF);
1689
+ unless ($et->ProcessTIFF(\%dirInfo, $tagTablePtr, \&Image::ExifTool::ProcessTIFF)) {
1690
+ # do MD5 of image data if necessary
1691
+ $et->ImageDataMD5($raf, $len, 'raw') if $$et{ImageDataMD5} and $raf->Seek($start,0);
1692
+ }
1689
1693
  delete $$et{SET_GROUP1};
1690
1694
  $ifdNum = ($ifdNum || 1) + 1;
1691
1695
  } else {
@@ -482,13 +482,13 @@ sub PrintTimeStamp($)
482
482
  #------------------------------------------------------------------------------
483
483
  # Convert degrees to DMS, or whatever the current settings are
484
484
  # Inputs: 0) ExifTool reference, 1) Value in degrees,
485
- # 2) format code (0=no format, 1=CoordFormat, 2=XMP format)
485
+ # 2) format code (0=no format, 1=CoordFormat, 2=XMP format, 3=signed unformatted)
486
486
  # 3) 'N' or 'E' if sign is significant and N/S/E/W should be added
487
487
  # Returns: DMS string
488
488
  sub ToDMS($$;$$)
489
489
  {
490
490
  my ($et, $val, $doPrintConv, $ref) = @_;
491
- my ($fmt, @fmt, $num, $sign, $rtnVal);
491
+ my ($fmt, @fmt, $num, $sign, $rtnVal, $neg);
492
492
 
493
493
  unless (length $val) {
494
494
  # don't convert an empty value
@@ -505,6 +505,10 @@ sub ToDMS($$;$$)
505
505
  }
506
506
  $ref = " $ref" unless $doPrintConv and $doPrintConv eq '2';
507
507
  } else {
508
+ if ($doPrintConv and $doPrintConv eq '3') {
509
+ $neg = 1 if $val < 0;
510
+ $doPrintConv = 0;
511
+ }
508
512
  $val = abs($val);
509
513
  $ref = '';
510
514
  }
@@ -554,6 +558,7 @@ sub ToDMS($$;$$)
554
558
  # trim trailing zeros in XMP
555
559
  $rtnVal =~ s/(\d)0+$ref$/$1$ref/ if $doPrintConv eq '2';
556
560
  } else {
561
+ $neg and map { $_ *= -1 } @c;
557
562
  $rtnVal = "@c$ref";
558
563
  }
559
564
  return $rtnVal;
@@ -29,7 +29,7 @@ use vars qw($VERSION);
29
29
  use Image::ExifTool qw(:Public);
30
30
  use Image::ExifTool::GPS;
31
31
 
32
- $VERSION = '1.70';
32
+ $VERSION = '1.71';
33
33
 
34
34
  sub JITTER() { return 2 } # maximum time jitter
35
35
 
@@ -92,7 +92,7 @@ my %isOrient = ( dir => 1, pitch => 1, roll => 1 ); # test for orientation key
92
92
  # tags which may exist separately in some formats (eg. CSV)
93
93
  my %sepTags = ( dir => 1, pitch => 1, roll => 1, track => 1, speed => 1 );
94
94
 
95
- # conversion factors for GPSSpeed
95
+ # conversion factors for GPSSpeed (standard EXIF units only)
96
96
  my %speedConv = (
97
97
  'K' => 1.852, # km/h per knot
98
98
  'M' => 1.150779448, # mph per knot
@@ -102,7 +102,14 @@ my %speedConv = (
102
102
  'mph' => 'M',
103
103
  );
104
104
 
105
- my $secPerDay = 24 * 3600; # a useful constant
105
+ # all recognized speed conversion factors (non-EXIF included)
106
+ my %otherConv = (
107
+ 'km/h' => 1.852,
108
+ 'mph' => 1.150779448,
109
+ 'm/s' => 0.514444,
110
+ );
111
+
112
+ my $secPerDay = 24 * 3600; # a useful constant
106
113
 
107
114
  #------------------------------------------------------------------------------
108
115
  # Load GPS track log file
@@ -140,6 +147,7 @@ sub LoadTrackLog($$;$)
140
147
  my ($raf, $from, $time, $isDate, $noDate, $noDateChanged, $lastDate, $dateFlarm);
141
148
  my ($nmeaStart, $fixSecs, @fixTimes, $lastFix, %nmea, @csvHeadings, $sortFixes);
142
149
  my ($canCut, $cutPDOP, $cutHDOP, $cutSats, $e0, $e1, @tmp, $trackFile, $trackTime);
150
+ my $scaleSpeed;
143
151
 
144
152
  unless (eval { require Time::Local }) {
145
153
  return 'Geotag feature requires Time::Local installed';
@@ -246,7 +254,9 @@ sub LoadTrackLog($$;$)
246
254
  $format = 'CSV';
247
255
  # convert recognized headings to our parameter names
248
256
  foreach (@csvHeadings) {
257
+ my $head = $_;
249
258
  my $param;
259
+ my $xtra = '';
250
260
  s/^GPS ?//; # remove leading "GPS" to simplify regex patterns
251
261
  if (/^Time ?\(seconds\)$/i) { # DJI
252
262
  # DJI CSV log files have a column "Time(seconds)" which is seconds since
@@ -274,7 +284,16 @@ sub LoadTrackLog($$;$)
274
284
  /ref$/i and $param .= 'ref';
275
285
  } elsif (/^(Pos)?Alt/i) {
276
286
  $param = 'alt';
277
- } elsif (/^(Angle)?(Heading|Track)/i) {
287
+ } elsif (/^Speed/i) {
288
+ $param = 'speed';
289
+ # (recognize units in brackets)
290
+ if (m{\((mph|km/h|m/s)\)}) {
291
+ $scaleSpeed = $otherConv{$1};
292
+ $xtra = " in $1";
293
+ } else {
294
+ $xtra = ' in knots';
295
+ }
296
+ } elsif (/^(Angle)?(Heading|Track|Bearing)/i) {
278
297
  $param = 'track';
279
298
  } elsif (/^(Angle)?Pitch/i or /^Camera ?Elevation ?Angle/i) {
280
299
  $param = 'pitch';
@@ -284,10 +303,10 @@ sub LoadTrackLog($$;$)
284
303
  $param = 'dir';
285
304
  }
286
305
  if ($param) {
287
- $et->VPrint(2, "CSV column '${_}' is $param\n");
306
+ $et->VPrint(2, "CSV column '${head}' is $param$xtra\n");
288
307
  $_ = $param;
289
308
  } else {
290
- $et->VPrint(2, "CSV column '${_}' ignored\n");
309
+ $et->VPrint(2, "CSV column '${head}' ignored\n");
291
310
  $_ = ''; # ignore this column
292
311
  }
293
312
  }
@@ -479,9 +498,11 @@ DoneFix: $isDate = 1;
479
498
  my ($param, $date, $secs, %neg);
480
499
  foreach $param (@csvHeadings) {
481
500
  my $val = shift @vals;
482
- last unless defined $val;
501
+ last unless defined $val and length($val);
483
502
  next unless $param;
484
503
  if ($param eq 'datetime') {
504
+ # (fix formats like "24.07.2016 13:47:30")
505
+ $val =~ s/^(\d{2})[^\d](\d{2})[^\d](\d{4}) /$3:$2:$1 /;
485
506
  local $SIG{'__WARN__'} = sub { };
486
507
  my $dateTime = $et->InverseDateTime($val);
487
508
  if ($dateTime) {
@@ -510,6 +531,7 @@ DoneFix: $isDate = 1;
510
531
  $date = $trackTime;
511
532
  $secs = $val;
512
533
  } else {
534
+ $val /= $scaleSpeed if $scaleSpeed and $param eq 'speed';
513
535
  $$fix{$param} = $val;
514
536
  $$has{$param} = 1 if $sepTags{$param};
515
537
  }
@@ -1204,6 +1226,7 @@ Category: foreach $category (qw{pos track alt orient atemp}) {
1204
1226
  @r = $et->SetNewValue(GPSTrackRef => (defined $$tFix{track} ? 'T' : undef), %opts);
1205
1227
  my ($spd, $ref);
1206
1228
  if (defined($spd = $$tFix{speed})) {
1229
+ # convert to specified units if necessary
1207
1230
  $ref = $$et{OPTIONS}{GeoSpeedRef};
1208
1231
  if ($ref and defined $speedConv{$ref}) {
1209
1232
  $ref = $speedConv{$ref} if $speedConv{$speedConv{$ref}};
@@ -11,7 +11,7 @@ use strict;
11
11
  use vars qw($VERSION);
12
12
  use Image::ExifTool qw(:DataAccess :Utils);
13
13
 
14
- $VERSION = '1.34';
14
+ $VERSION = '1.35';
15
15
 
16
16
  sub ProcessOcad($$$);
17
17
  sub ProcessJPEG_HDR($$$);
@@ -134,9 +134,17 @@ sub ProcessJPEG_HDR($$$);
134
134
  Condition => '$$self{HasIJPEG}"',
135
135
  SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Factory' },
136
136
  }, {
137
- Name => 'ThermalParams', # (written by DJI FLIR models)
137
+ Name => 'ThermalParams', # (written by some DJI FLIR models)
138
138
  Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^\xaa\x55\x12\x06/',
139
139
  SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams' },
140
+ }, {
141
+ Name => 'ThermalParams2', # (written by M3T)
142
+ Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^(.{32})?.{32}\x2c\x01\x20\0/s',
143
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams2' },
144
+ }, {
145
+ Name => 'ThermalParams3', # (written by M30T)
146
+ Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^.{32}\xaa\x55\x38\0/s',
147
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams3' },
140
148
  }, {
141
149
  Name => 'PreviewImage', # (eg. Samsung S1060)
142
150
  Notes => 'continued from APP3',
@@ -207,6 +215,10 @@ sub ProcessJPEG_HDR($$$);
207
215
  Name => 'InfiRayOpMode',
208
216
  Condition => '$$self{HasIJPEG}',
209
217
  SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::OpMode' },
218
+ }, {
219
+ Name => 'DJI-DBG',
220
+ Condition => '$$valPt =~ /^DJI-DBG\0/',
221
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
210
222
  }],
211
223
  APP8 => [{
212
224
  Name => 'SPIFF',
@@ -59,7 +59,7 @@ my %jp2Map = (
59
59
  # map of where information is written in a JXL image
60
60
  my %jxlMap = (
61
61
  IFD0 => 'Exif',
62
- XMP => 'XML',
62
+ XMP => 'xml ',
63
63
  'Exif' => 'JP2',
64
64
  IFD1 => 'IFD0',
65
65
  EXIF => 'IFD0', # to write EXIF as a block
@@ -827,8 +827,8 @@ sub CreateNewBoxes($$)
827
827
  # add UUID boxes (and/or JXL Exif/XML boxes)
828
828
  foreach $dirName (sort keys %$addDirs) {
829
829
  # handle JPEG XL XMP and EXIF
830
- if ($dirName eq 'XML' or $dirName eq 'Exif') {
831
- my ($tag, $dir) = $dirName eq 'XML' ? ('xml ', 'XMP') : ('Exif', 'EXIF');
830
+ if ($dirName eq 'xml ' or $dirName eq 'Exif') {
831
+ my ($tag, $dir) = $dirName eq 'xml ' ? ('xml ', 'XMP') : ('Exif', 'EXIF');
832
832
  my $tagInfo = $Image::ExifTool::Jpeg2000::Main{$tag};
833
833
  $tagInfo = $$tagInfo[1] if ref $tagInfo eq 'ARRAY'; # (hack for stupid JXL XMP)
834
834
  my $subdir = $$tagInfo{SubDirectory};
@@ -1123,8 +1123,8 @@ sub ProcessJpeg2000Box($$$)
1123
1123
  my $subTable = GetTagTable($$subdir{TagTable}) || $tagTablePtr;
1124
1124
  if ($outfile) {
1125
1125
  # remove this directory from our create list
1126
- delete $$et{AddJp2Dirs}{$$tagInfo{Name}}; # (eg. 'EXIF')
1127
- delete $$et{AddJp2Dirs}{$boxID}; # (eg. 'Exif')
1126
+ delete $$et{AddJp2Dirs}{$$tagInfo{Name}}; # (eg. 'EXIF' or 'XMP')
1127
+ delete $$et{AddJp2Dirs}{$boxID}; # (eg. 'Exif' or 'xml ')
1128
1128
  my $newdir;
1129
1129
  # only edit writable UUID, Exif and jp2h boxes
1130
1130
  if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL}) or
@@ -13,7 +13,7 @@ use vars qw($VERSION);
13
13
  use Image::ExifTool qw(:DataAccess :Utils);
14
14
  use Image::ExifTool::XMP;
15
15
 
16
- $VERSION = '1.00';
16
+ $VERSION = '1.01';
17
17
 
18
18
  %Image::ExifTool::LIF::Main = (
19
19
  GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
@@ -30,7 +30,15 @@ $VERSION = '1.00';
30
30
  my $unixTimeZero = 134774 * 24 * 3600;
31
31
  my @vals = split ' ', $val;
32
32
  foreach (@vals) {
33
- $_ = 1e-7 * hex($_);
33
+ if (/[^0-9a-f]/i) {
34
+ $_ = '0000:00:00 00:00:00';
35
+ } elsif (length $_ > 8) {
36
+ my $lo = hex substr($_, -8);
37
+ my $hi = hex substr($_, 0, -8);
38
+ $_ = 1e-7 * ($hi * 4294967296 + $lo);
39
+ } else {
40
+ $_ = 1e-7 * hex($_);
41
+ }
34
42
  # shift from Jan 1, 1601 to Jan 1, 1970
35
43
  $_ = Image::ExifTool::ConvertUnixTime($_ - $unixTimeZero);
36
44
  }