exiftool-vendored.pl 12.39.0 → 12.42.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 (46) hide show
  1. package/bin/Changes +66 -1
  2. package/bin/MANIFEST +1 -0
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +1 -1
  5. package/bin/README +2 -2
  6. package/bin/arg_files/exif2xmp.args +5 -0
  7. package/bin/arg_files/xmp2exif.args +6 -0
  8. package/bin/config_files/acdsee.config +6 -6
  9. package/bin/config_files/photoshop_paths.config +30 -7
  10. package/bin/config_files/picasa_faces.config +1 -1
  11. package/bin/config_files/pix4d.config +2 -2
  12. package/bin/config_files/tiff_version.config +2 -2
  13. package/bin/exiftool +54 -22
  14. package/bin/lib/Image/ExifTool/Canon.pm +89 -6
  15. package/bin/lib/Image/ExifTool/DJI.pm +59 -1
  16. package/bin/lib/Image/ExifTool/DNG.pm +8 -2
  17. package/bin/lib/Image/ExifTool/Exif.pm +53 -20
  18. package/bin/lib/Image/ExifTool/Geotag.pm +3 -2
  19. package/bin/lib/Image/ExifTool/ICC_Profile.pm +10 -8
  20. package/bin/lib/Image/ExifTool/ID3.pm +5 -5
  21. package/bin/lib/Image/ExifTool/MacOS.pm +9 -9
  22. package/bin/lib/Image/ExifTool/MakerNotes.pm +17 -1
  23. package/bin/lib/Image/ExifTool/Nikon.pm +44 -12
  24. package/bin/lib/Image/ExifTool/NikonCustom.pm +4 -1
  25. package/bin/lib/Image/ExifTool/Olympus.pm +27 -7
  26. package/bin/lib/Image/ExifTool/PDF.pm +2 -1
  27. package/bin/lib/Image/ExifTool/Panasonic.pm +10 -1
  28. package/bin/lib/Image/ExifTool/Pentax.pm +1 -1
  29. package/bin/lib/Image/ExifTool/Photoshop.pm +6 -5
  30. package/bin/lib/Image/ExifTool/QuickTime.pm +9 -5
  31. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +2 -2
  32. package/bin/lib/Image/ExifTool/Samsung.pm +237 -2
  33. package/bin/lib/Image/ExifTool/Shortcuts.pm +3 -1
  34. package/bin/lib/Image/ExifTool/Sony.pm +10 -4
  35. package/bin/lib/Image/ExifTool/TagLookup.pm +6376 -6354
  36. package/bin/lib/Image/ExifTool/TagNames.pod +79 -28
  37. package/bin/lib/Image/ExifTool/WriteQuickTime.pl +7 -3
  38. package/bin/lib/Image/ExifTool/WriteXMP.pl +2 -0
  39. package/bin/lib/Image/ExifTool/Writer.pl +1 -1
  40. package/bin/lib/Image/ExifTool/XMP.pm +9 -1
  41. package/bin/lib/Image/ExifTool/XMPStruct.pl +21 -7
  42. package/bin/lib/Image/ExifTool.pm +20 -12
  43. package/bin/lib/Image/ExifTool.pod +7 -6
  44. package/bin/perl-Image-ExifTool.spec +1 -1
  45. package/bin/pp_build_exe.args +4 -4
  46. package/package.json +14 -3
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
88
88
  sub ProcessExifInfo($$$);
89
89
  sub SwapWords($);
90
90
 
91
- $VERSION = '4.55';
91
+ $VERSION = '4.58';
92
92
 
93
93
  # Note: Removed 'USM' from 'L' lenses since it is redundant - PH
94
94
  # (or is it? Ref 32 shows 5 non-USM L-type lenses)
@@ -197,6 +197,7 @@ $VERSION = '4.55';
197
197
  44 => 'Canon EF 90-300mm f/4.5-5.6', #32
198
198
  45 => 'Canon EF-S 18-55mm f/3.5-5.6 [II]', #PH (same ID for version II, ref 20)
199
199
  46 => 'Canon EF 28-90mm f/4-5.6', #32
200
+ # 46 => 'Tamron 28-300mm f/3.5-6.3 Di VC PZD (A010)', # (also possibly?)
200
201
  47 => 'Zeiss Milvus 35mm f/2 or 50mm f/2', #IB
201
202
  47.1 => 'Zeiss Milvus 50mm f/2 Makro', #IB
202
203
  47.2 => 'Zeiss Milvus 135mm f/2 ZE', #IB
@@ -208,6 +209,7 @@ $VERSION = '4.55';
208
209
  53 => 'Canon EF-S 18-55mm f/3.5-5.6 III', #Jon Charnas
209
210
  54 => 'Canon EF-S 55-250mm f/4-5.6 IS II', #47
210
211
  60 => 'Irix 11mm f/4', #50
212
+ 63 => 'Irix 30mm F1.4 Dragonfly', #IB
211
213
  80 => 'Canon TS-E 50mm f/2.8L Macro', #42
212
214
  81 => 'Canon TS-E 90mm f/2.8L Macro', #42
213
215
  82 => 'Canon TS-E 135mm f/4L Macro', #42
@@ -570,7 +572,9 @@ $VERSION = '4.55';
570
572
  61494 => 'Canon CN-E 85mm T1.3 L F', #PH
571
573
  61495 => 'Canon CN-E 135mm T2.2 L F', #PH
572
574
  61496 => 'Canon CN-E 35mm T1.5 L F', #PH
573
- # see RFLensType tag for master list of 61182 RF lenses
575
+ #
576
+ # see RFLensType tag for master list of 61182 RF lenses
577
+ #
574
578
  61182 => 'Canon RF 50mm F1.2L USM or other Canon RF Lens',
575
579
  61182.1 => 'Canon RF 24-105mm F4L IS USM',
576
580
  61182.2 => 'Canon RF 28-70mm F2L USM',
@@ -599,7 +603,15 @@ $VERSION = '4.55';
599
603
  '61182.25' => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
600
604
  '61182.26' => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
601
605
  '61182.27' => 'Canon RF 16mm F2.8 STM', #42
602
- #'61182.xx' => 'Canon RF 100mm F2.8L MACRO IS USM',
606
+ '61182.28' => 'Canon RF 400mm F2.8L IS USM', #IB
607
+ '61182.29' => 'Canon RF 400mm F2.8L IS USM + RF1.4x', #IB
608
+ '61182.30' => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB
609
+ '61182.31' => 'Canon RF 600mm F4L IS USM', #GiaZopatti
610
+ # we need the RFLensType values for the following...
611
+ '61182.32' => 'Canon RF 800mm F5.6L IS USM', #PH (NC)
612
+ '61182.33' => 'Canon RF 1200mm F8L IS USM', #PH (NC)
613
+ '61182.34' => 'Canon RF 5.2mm F2.8L Dual Fisheye 3D VR', #PH (NC)
614
+ '61182.35' => 'Canon RF 100mm F2.8L MACRO IS USM', #(NC)
603
615
  65535 => 'n/a',
604
616
  );
605
617
 
@@ -970,8 +982,8 @@ my %canonQuality = (
970
982
  4 => 'RAW',
971
983
  5 => 'Superfine',
972
984
  7 => 'CRAW', #42
973
- 130 => 'Normal Movie', #22
974
- 131 => 'Movie (2)', #PH (7DmkII 1920x1080)
985
+ 130 => 'Light (RAW)', #github#119
986
+ 131 => 'Standard (RAW)', #github#119
975
987
  );
976
988
  my %canonImageSize = (
977
989
  -1 => 'n/a',
@@ -1018,7 +1030,7 @@ my %canonWhiteBalance = (
1018
1030
  20 => 'PC Set4', #PH
1019
1031
  21 => 'PC Set5', #PH
1020
1032
  # 22 - Custom 2?
1021
- 23 => 'Auto (ambience priority)', #PH (5DS)
1033
+ 23 => 'Auto (ambience priority)', #PH (5DS) (perhaps this needs re-thinking?: forum13295)
1022
1034
  # 30 - Click White Balance?
1023
1035
  # 31 - Shot Settings?
1024
1036
  # 137 - Tungsten?
@@ -2053,6 +2065,13 @@ my %offOn = ( 0 => 'Off', 1 => 'On' );
2053
2065
  TagTable => 'Image::ExifTool::Canon::HDRInfo',
2054
2066
  }
2055
2067
  },
2068
+ 0x4026 => { #github#119
2069
+ Name => 'LogInfo',
2070
+ SubDirectory => {
2071
+ Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
2072
+ TagTable => 'Image::ExifTool::Canon::LogInfo',
2073
+ }
2074
+ },
2056
2075
  0x4028 => { #PH
2057
2076
  Name => 'AFConfig', # (AFTabInfo)
2058
2077
  SubDirectory => {
@@ -2126,6 +2145,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' );
2126
2145
  4 => 'Continuous, Low', #PH
2127
2146
  5 => 'Continuous, High', #PH
2128
2147
  6 => 'Silent Single', #PH
2148
+ 8 => 'Continuous, High+', #WolfgangGulcker
2129
2149
  # ref A: https://exiftool.org/forum/index.php/topic,5701.msg27843.html#msg27843
2130
2150
  9 => 'Single, Silent', #A
2131
2151
  10 => 'Continuous, Silent', #A
@@ -6789,6 +6809,10 @@ my %ciMaxFocal = (
6789
6809
  284 => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC)
6790
6810
  285 => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC)
6791
6811
  288 => 'Canon RF 16mm F2.8 STM', #42
6812
+ 289 => 'Canon RF 400mm F2.8L IS USM', #IB
6813
+ 290 => 'Canon RF 400mm F2.8L IS USM + RF1.4x', #IB
6814
+ 291 => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB
6815
+ 292 => 'Canon RF 600mm F4L IS USM', #GiaZopatti
6792
6816
  #xxx => 'Canon RF 100mm F2.8L MACRO IS USM',
6793
6817
  # Note: add new RF lenses to %canonLensTypes with ID 61182
6794
6818
  },
@@ -8701,6 +8725,65 @@ my %filterConv = (
8701
8725
  # 3 - maybe related to AutoImageAlign?
8702
8726
  );
8703
8727
 
8728
+ # More color information (MakerNotes tag 0x4026) (ref github issue #119)
8729
+ %Image::ExifTool::Canon::LogInfo = (
8730
+ %binaryDataAttrs,
8731
+ FORMAT => 'int32s',
8732
+ FIRST_ENTRY => 1,
8733
+ PRIORITY => 0,
8734
+ 4 => {
8735
+ Name => 'CompressionFormat',
8736
+ PrintConv => {
8737
+ 0 => 'Editing (ALL-I)',
8738
+ 1 => 'Standard (IPB)',
8739
+ 2 => 'Light (IPB)',
8740
+ 3 => 'Motion JPEG',
8741
+ 4 => 'RAW', # either Standard or Light, depending on Quality
8742
+ },
8743
+ },
8744
+ 6 => { # 0 to 7
8745
+ Name => 'Sharpness',
8746
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8747
+ },
8748
+ 7 => { # -4 to 4
8749
+ Name => 'Saturation',
8750
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8751
+ %Image::ExifTool::Exif::printParameter,
8752
+ },
8753
+ 8 => { # -4 to 4
8754
+ Name => 'ColorTone',
8755
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8756
+ %Image::ExifTool::Exif::printParameter,
8757
+ },
8758
+ 9 => {
8759
+ Name => 'ColorSpace2',
8760
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8761
+ PrintConv => {
8762
+ 0 => 'BT.709',
8763
+ 1 => 'BT.2020',
8764
+ 2 => 'CinemaGamut',
8765
+ },
8766
+ },
8767
+ 10 => {
8768
+ Name => 'ColorMatrix',
8769
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8770
+ PrintConv => {
8771
+ 0 => 'EOS Original',
8772
+ 1 => 'Neutral',
8773
+ },
8774
+ },
8775
+ 11 => {
8776
+ Name => 'CanonLogVersion', # (increases dynamic range of sensor data)
8777
+ RawConv => '$val == 0x7fffffff ? undef : $val',
8778
+ PrintConv => {
8779
+ 0 => 'OFF',
8780
+ 1 => 'CLogV1',
8781
+ 2 => 'CLogV2', # (NC)
8782
+ 3 => 'CLogV3',
8783
+ },
8784
+ },
8785
+ );
8786
+
8704
8787
  # AF configuration info (MakerNotes tag 0x4028) (ref PH)
8705
8788
  %Image::ExifTool::Canon::AFConfig = (
8706
8789
  %binaryDataAttrs,
@@ -11,11 +11,14 @@ package Image::ExifTool::DJI;
11
11
 
12
12
  use strict;
13
13
  use vars qw($VERSION);
14
+ use Image::ExifTool qw(:DataAccess :Utils);
14
15
  use Image::ExifTool::Exif;
15
16
  use Image::ExifTool::XMP;
16
17
  use Image::ExifTool::GPS;
17
18
 
18
- $VERSION = '1.04';
19
+ $VERSION = '1.05';
20
+
21
+ sub ProcessDJIInfo($$$);
19
22
 
20
23
  my %convFloat2 = (
21
24
  PrintConv => 'sprintf("%+.2f", $val)',
@@ -44,6 +47,29 @@ my %convFloat2 = (
44
47
  0x0b => { Name => 'CameraRoll', Writable => 'float', %convFloat2 },
45
48
  );
46
49
 
50
+ # DJI debug maker notes
51
+ %Image::ExifTool::DJI::Info = (
52
+ PROCESS_PROC => \&ProcessDJIInfo,
53
+ GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
54
+ NOTES => 'Tags written by some DJI drones.',
55
+ VARS => { LONG_TAGS => 2 },
56
+ ae_dbg_info => { Name => 'AEDebugInfo' },
57
+ ae_histogram_info => { Name => 'AEHistogramInfo' },
58
+ ae_local_histogram => { Name => 'AELocalHistogram' },
59
+ ae_liveview_histogram_info => { Name => 'AELiveViewHistogramInfo' },
60
+ ae_liveview_local_histogram => { Name => 'AELiveViewLocalHistogram' },
61
+ awb_dbg_info => { Name => 'AWBDebugInfo' },
62
+ af_dbg_info => { Name => 'AFDebugInfo' },
63
+ hiso => { Name => 'Histogram' },
64
+ xidiri => { Name => 'Xidiri' },
65
+ 'GimbalDegree(Y,P,R)'=> { Name => 'GimbalDegree' },
66
+ 'FlightDegree(Y,P,R)'=> { Name => 'FlightDegree' },
67
+ adj_dbg_info => { Name => 'ADJDebugInfo' },
68
+ sensor_id => { Name => 'SensorID' },
69
+ 'FlightSpeed(X,Y,Z)' => { Name => 'FlightSpeed' },
70
+ hyperlapse_dbg_info => { Name => 'HyperlapsDebugInfo' },
71
+ );
72
+
47
73
  # thermal parameters in APP4 of DJI ZH20T images (ref forum11401)
48
74
  %Image::ExifTool::DJI::ThermalParams = (
49
75
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
@@ -134,6 +160,38 @@ my %convFloat2 = (
134
160
  },
135
161
  );
136
162
 
163
+ #------------------------------------------------------------------------------
164
+ # Process DJI infor (ref PH)
165
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
166
+ # Returns: 1 on success
167
+ sub ProcessDJIInfo($$$)
168
+ {
169
+ my ($et, $dirInfo, $tagTbl) = @_;
170
+ my $dataPt = $$dirInfo{DataPt};
171
+ my $dirStart = $$dirInfo{DirStart} || 0;
172
+ my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
173
+ if ($dirStart) {
174
+ my $buff = substr($$dataPt, $dirStart, $dirLen);
175
+ $dataPt = \$buff;
176
+ }
177
+ while ($$dataPt =~ /\G\[(.*?)\](?=(\[|$))/sg) {
178
+ my ($tag, $val) = split /:/, $1, 2;
179
+ if ($val =~ /^([\x20-\x7f]+)\0*$/) {
180
+ $val = $1;
181
+ } else {
182
+ my $buff = $val;
183
+ $val = \$buff;
184
+ }
185
+ if (not $$tagTbl{$tag} and $tag=~ /^[-_a-zA-Z0-9]+$/) {
186
+ my $name = $tag;
187
+ $name =~ s/_([a-z])/_\U$1/g;
188
+ AddTagToTable($tagTbl, $tag, { Name => Image::ExifTool::MakeTagName($name) });
189
+ }
190
+ $et->HandleTag($tagTbl, $tag, $val);
191
+ }
192
+ return 1;
193
+ }
194
+
137
195
  __END__
138
196
 
139
197
  =head1 NAME
@@ -680,8 +680,14 @@ sub ProcessAdobeMakN($$$)
680
680
  my $dataPos = $$dirInfo{DataPos};
681
681
  my $hdrLen = 6;
682
682
 
683
- # hack for extra 12 bytes in MakN header of JPEG converted to DNG by Adobe Camera Raw
684
- # (4 bytes "00 00 00 01" followed by 8 unknown bytes)
683
+ # 2018-09-27: hack for extra 12 bytes in MakN header of JPEG converted to DNG
684
+ # by Adobe Camera Raw (4 bytes "00 00 00 01" followed by 8 unknown bytes)
685
+ # - this is because CameraRaw copies the maker notes from the wrong location
686
+ # in a JPG image (off by 12 bytes presumably due to the JPEG headers)
687
+ # - this hack won't work in most cases because the extra bytes are not consistent
688
+ # since they are just the data that existed in the JPG before the maker notes
689
+ # - also, the last 12 bytes of the maker notes will be missing
690
+ # - 2022-04-26: this bug still exists in Camera Raw 14.3
685
691
  $hdrLen += 12 if $len >= 18 and substr($$dataPt, $start+6, 4) eq "\0\0\0\x01";
686
692
 
687
693
  my $dirStart = $start + $hdrLen; # pointer to maker note directory
@@ -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.38';
59
+ $VERSION = '4.40';
60
60
 
61
61
  sub ProcessExif($$$);
62
62
  sub WriteExif($$$);
@@ -415,7 +415,14 @@ my %opcodeInfo = (
415
415
  WriteGroup => 'IFD0',
416
416
  # set priority directory if this is the full resolution image
417
417
  DataMember => 'SubfileType',
418
- RawConv => '$self->SetPriorityDir() if $val eq "0"; $$self{SubfileType} = $val',
418
+ RawConv => q{
419
+ if ($val == ($val & 0x02)) {
420
+ $self->SetPriorityDir() if $val == 0;
421
+ $$self{PageCount} = ($$self{PageCount} || 0) + 1;
422
+ $$self{MultiPage} = 1 if $val == 2 or $$self{PageCount} > 1;
423
+ }
424
+ $$self{SubfileType} = $val;
425
+ },
419
426
  PrintConv => \%subfileType,
420
427
  },
421
428
  0xff => {
@@ -425,7 +432,14 @@ my %opcodeInfo = (
425
432
  Writable => 'int16u',
426
433
  WriteGroup => 'IFD0',
427
434
  # set priority directory if this is the full resolution image
428
- RawConv => '$self->SetPriorityDir() if $val eq "1"; $val',
435
+ RawConv => q{
436
+ if ($val == 1 or $val == 3) {
437
+ $self->SetPriorityDir() if $val == 1;
438
+ $$self{PageCount} = ($$self{PageCount} || 0) + 1;
439
+ $$self{MultiPage} = 1 if $val == 3 or $$self{PageCount} > 1;
440
+ }
441
+ $val;
442
+ },
429
443
  PrintConv => {
430
444
  1 => 'Full-resolution image',
431
445
  2 => 'Reduced-resolution image',
@@ -2144,7 +2158,7 @@ my %opcodeInfo = (
2144
2158
  Notes => 'displayed in seconds, but stored as an APEX value',
2145
2159
  Format => 'rational64s', # Leica M8 patch (incorrectly written as rational64u)
2146
2160
  Writable => 'rational64s',
2147
- ValueConv => 'abs($val)<100 ? 2**(-$val) : 0',
2161
+ ValueConv => 'IsFloat($val) && abs($val)<100 ? 2**(-$val) : 0',
2148
2162
  ValueConvInv => '$val>0 ? -log($val)/log(2) : -100',
2149
2163
  PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
2150
2164
  PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
@@ -3383,6 +3397,15 @@ my %opcodeInfo = (
3383
3397
  },
3384
3398
  # the DJI FC2103 writes some interesting stuff here (with sections labelled
3385
3399
  # awb_dbg_info, ae_dbg_info, ae_histogram_info, af_dbg_info, hiso, xidiri) - PH
3400
+ {
3401
+ Name => 'MakerNoteDJIInfo',
3402
+ Condition => '$$valPt =~ /^\[ae_dbg_info:/',
3403
+ MakerNotes => 1,
3404
+ Binary => 1,
3405
+ WriteGroup => 'IFD0', # (for Validate)
3406
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
3407
+ Format => 'undef',
3408
+ },
3386
3409
  {
3387
3410
  Name => 'DNGPrivateData',
3388
3411
  Flags => [ 'Binary', 'Protected' ],
@@ -4827,6 +4850,7 @@ my %subSecConv = (
4827
4850
  PrintConvInv => q{
4828
4851
  return undef unless $val =~ /(.*? ?[NS]?), ?(.*? ?[EW]?)$/;
4829
4852
  my ($lat, $lon) = ($1, $2);
4853
+ require Image::ExifTool::GPS;
4830
4854
  $lat = Image::ExifTool::GPS::ToDegrees($lat, 1, "lat");
4831
4855
  $lon = Image::ExifTool::GPS::ToDegrees($lon, 1, "lon");
4832
4856
  return "$lat, $lon";
@@ -5248,6 +5272,7 @@ sub RedBlueBalance($@)
5248
5272
  sub PrintExposureTime($)
5249
5273
  {
5250
5274
  my $secs = shift;
5275
+ return $secs unless Image::ExifTool::IsFloat($secs);
5251
5276
  if ($secs < 0.25001 and $secs > 0) {
5252
5277
  return sprintf("1/%d",int(0.5 + 1/$secs));
5253
5278
  }
@@ -5853,7 +5878,7 @@ sub ProcessExif($$$)
5853
5878
  unless ($path =~ /^(JPEG-APP1-IFD0|TIFF-IFD0|PSD-EXIFInfo-IFD0)$/) {
5854
5879
  if ($Image::ExifTool::MWG::strict) {
5855
5880
  $et->Warn("Ignored non-standard EXIF at $path");
5856
- return 1;
5881
+ return 0;
5857
5882
  } else {
5858
5883
  $et->Warn("Non-standard EXIF at $path", 1);
5859
5884
  }
@@ -5896,10 +5921,6 @@ sub ProcessExif($$$)
5896
5921
  # also read next IFD pointer if available
5897
5922
  if ($raf->Read($buf2, $len+4) >= $len) {
5898
5923
  $buff .= $buf2;
5899
- # make copy of dirInfo since we're going to modify it
5900
- my %newDirInfo = %$dirInfo;
5901
- $dirInfo = \%newDirInfo;
5902
- # update directory parameters for the newly loaded IFD
5903
5924
  $dataPt = $$dirInfo{DataPt} = \$buff;
5904
5925
  $dataPos = $$dirInfo{DataPos} = $offset;
5905
5926
  $dataLen = $$dirInfo{DataLen} = length $buff;
@@ -6593,7 +6614,7 @@ sub ProcessExif($$$)
6593
6614
  #### eval Validate ($val, $dirData, $subdirStart, $size)
6594
6615
  my $ok = 0;
6595
6616
  if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
6596
- $et->Warn("Invalid $tagStr data");
6617
+ $et->Warn("Invalid $tagStr data", $inMakerNotes);
6597
6618
  $invalid = 1;
6598
6619
  } else {
6599
6620
  if (not $subdirInfo{DirName} and $inMakerNotes) {
@@ -6706,28 +6727,40 @@ sub ProcessExif($$$)
6706
6727
 
6707
6728
  # scan for subsequent IFD's if specified
6708
6729
  if ($$dirInfo{Multi} and $bytesFromEnd >= 4) {
6709
- my $offset = Get32u($dataPt, $dirEnd);
6710
- if ($offset) {
6711
- my $subdirStart = $offset - $dataPos;
6712
- # use same directory information for trailing directory,
6713
- # but change the start location (ProcessDirectory will
6714
- # test to make sure we don't reprocess the same dir twice)
6715
- my %newDirInfo = %$dirInfo;
6716
- $newDirInfo{DirStart} = $subdirStart;
6730
+ # use same directory information for trailing directory,
6731
+ # but change the start location (ProcessDirectory will
6732
+ # test to make sure we don't reprocess the same dir twice)
6733
+ my %newDirInfo = %$dirInfo;
6734
+ $newDirInfo{Multi} = 0; # prevent recursion
6735
+ $newDirInfo{OffsetName} = $nextOffName;
6736
+ $$et{INDENT} =~ s/..$//; # keep indent the same
6737
+ for (;;) {
6738
+ my $offset = Get32u($dataPt, $dirEnd) or last;
6739
+ $newDirInfo{DirStart} = $offset - $dataPos;
6717
6740
  # increment IFD number
6718
6741
  my $ifdNum = $newDirInfo{DirName} =~ s/(\d+)$// ? $1 : 0;
6719
6742
  $newDirInfo{DirName} .= $ifdNum + 1;
6720
- $newDirInfo{OffsetName} = $nextOffName;
6721
6743
  # must validate SubIFD1 because the nextIFD pointer is invalid for some RAW formats
6722
6744
  if ($newDirInfo{DirName} ne 'SubIFD1' or ValidateIFD(\%newDirInfo)) {
6723
- $$et{INDENT} =~ s/..$//; # keep indent the same
6724
6745
  my $cur = pop @{$$et{PATH}};
6725
6746
  $et->ProcessDirectory(\%newDirInfo, $tagTablePtr) or $success = 0;
6726
6747
  push @{$$et{PATH}}, $cur;
6748
+ if ($success and $newDirInfo{BytesFromEnd} >= 4) {
6749
+ $dataPt = $newDirInfo{DataPt};
6750
+ $dataPos = $newDirInfo{DataPos};
6751
+ $dirEnd = $newDirInfo{DirEnd};
6752
+ next;
6753
+ }
6727
6754
  } elsif ($verbose or $$et{TIFF_TYPE} eq 'TIFF') {
6728
6755
  $et->Warn('Ignored bad IFD linked from SubIFD');
6729
6756
  }
6757
+ last;
6730
6758
  }
6759
+ } elsif (defined $$dirInfo{Multi}) {
6760
+ # return necessary parameters for parsing next IFD
6761
+ $$dirInfo{DirEnd} = $dirEnd;
6762
+ $$dirInfo{OffsetName} = $nextOffName;
6763
+ $$dirInfo{BytesFromEnd} = $bytesFromEnd;
6731
6764
  }
6732
6765
  return $success;
6733
6766
  }
@@ -28,7 +28,7 @@ use vars qw($VERSION);
28
28
  use Image::ExifTool qw(:Public);
29
29
  use Image::ExifTool::GPS;
30
30
 
31
- $VERSION = '1.65';
31
+ $VERSION = '1.66';
32
32
 
33
33
  sub JITTER() { return 2 } # maximum time jitter
34
34
 
@@ -210,13 +210,14 @@ sub LoadTrackLog($$;$)
210
210
  $raf->ReadLine($_) or last;
211
211
  # determine file format
212
212
  if (not $format) {
213
+ s/^\xef\xbb\xbf//; # remove leading BOM if it exists
213
214
  if (/^<(\?xml|gpx)[\s>]/) { # look for XML or GPX header
214
215
  $format = 'XML';
215
216
  # check for NMEA sentence
216
217
  # (must ONLY start with ones that have timestamps! eg. not GSA or PTNTHPR!)
217
218
  } elsif (/^.*\$([A-Z]{2}(RMC|GGA|GLL|ZDA)|PMGNTRK),/) {
218
219
  $format = 'NMEA';
219
- $nmeaStart = $2 || $1; # save type of first sentence
220
+ $nmeaStart = $2 || $1; # save type of first sentence
220
221
  } elsif (/^A(FLA|XSY|FIL)/) {
221
222
  # (don't set format yet because we want to read HFDTE first)
222
223
  $nmeaStart = 'B' ;
@@ -25,7 +25,7 @@ use strict;
25
25
  use vars qw($VERSION);
26
26
  use Image::ExifTool qw(:DataAccess :Utils);
27
27
 
28
- $VERSION = '1.38';
28
+ $VERSION = '1.39';
29
29
 
30
30
  sub ProcessICC($$);
31
31
  sub ProcessICC_Profile($$$);
@@ -522,11 +522,11 @@ my %manuSig = ( #6
522
522
  prmg => 'Perceptual Reference Medium Gamut',
523
523
  },
524
524
  },
525
- meta => { #5 (EVENTUALLY DECODE THIS ONCE WE HAVE A SAMPLE!!)
525
+ meta => { #5
526
526
  Name => 'Metadata',
527
527
  SubDirectory => {
528
528
  TagTable => 'Image::ExifTool::ICC_Profile::Metadata',
529
- Validate => '$type eq "meta"',
529
+ Validate => '$type eq "dict"',
530
530
  },
531
531
  },
532
532
 
@@ -891,6 +891,7 @@ my %manuSig = ( #6
891
891
  ManufacturerName => { },
892
892
  MediaColor => { },
893
893
  MediaWeight => { },
894
+ CreatorApp => { },
894
895
  );
895
896
 
896
897
  #------------------------------------------------------------------------------
@@ -1000,7 +1001,7 @@ sub FormatICCTag($$$)
1000
1001
  }
1001
1002
 
1002
1003
  #------------------------------------------------------------------------------
1003
- # Process ICC metadata record (ref 5) (UNTESTED!)
1004
+ # Process ICC metadata record (ref 5)
1004
1005
  # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
1005
1006
  # Returns: 1 on success
1006
1007
  sub ProcessMetadata($$$)
@@ -1032,7 +1033,7 @@ sub ProcessMetadata($$$)
1032
1033
  my $namePtr = Get32u($dataPt, $entry);
1033
1034
  my $nameLen = Get32u($dataPt, $entry + 4);
1034
1035
  my $valuePtr = Get32u($dataPt, $entry + 8);
1035
- my $valueLen = Get32u($dataPt, $entry + 16);
1036
+ my $valueLen = Get32u($dataPt, $entry + 12);
1036
1037
  next unless $namePtr and $valuePtr; # ignore if offsets are zero
1037
1038
  if ($namePtr < $minPtr or $namePtr + $nameLen > $dirLen or
1038
1039
  $valuePtr < $minPtr or $valuePtr + $valueLen > $dirLen)
@@ -1040,8 +1041,8 @@ sub ProcessMetadata($$$)
1040
1041
  $et->Warn('Corrupted ICC meta dictionary');
1041
1042
  last;
1042
1043
  }
1043
- my $tag = substr($dataPt, $dirStart + $namePtr, $nameLen);
1044
- my $val = substr($dataPt, $dirStart + $valuePtr, $valueLen);
1044
+ my $tag = substr($$dataPt, $dirStart + $namePtr, $nameLen);
1045
+ my $val = substr($$dataPt, $dirStart + $valuePtr, $valueLen);
1045
1046
  $tag = $et->Decode($tag, 'UTF16', 'MM', 'UTF8');
1046
1047
  $val = $et->Decode($val, 'UTF16', 'MM');
1047
1048
  # generate tagInfo if it doesn't exist
@@ -1050,6 +1051,7 @@ sub ProcessMetadata($$$)
1050
1051
  $name =~ s/\s+(.)/\u$1/g;
1051
1052
  $name =~ tr/-_a-zA-Z0-9//dc;
1052
1053
  next unless length $name;
1054
+ $et->VPrint(0, $$et{INDENT}, "[adding $tag]\n");
1053
1055
  AddTagToTable($tagTablePtr, $tag, { Name => $name });
1054
1056
  }
1055
1057
  $et->HandleTag($tagTablePtr, $tag, $val);
@@ -1312,7 +1314,7 @@ sub ProcessICC_Profile($$$)
1312
1314
  DirName => $name,
1313
1315
  Parent => $$dirInfo{DirName},
1314
1316
  );
1315
- my $type = substr($$dataPt, $valuePtr, 4);
1317
+ my $type = $fmt;
1316
1318
  #### eval Validate ($type)
1317
1319
  if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
1318
1320
  $et->Warn("Invalid ICC $name data");
@@ -6,7 +6,7 @@
6
6
  # Revisions: 09/12/2005 - P. Harvey Created
7
7
  # 09/08/2020 - PH Added Lyrics3 support
8
8
  #
9
- # References: 1) http://www.id3.org/
9
+ # References: 1) http://www.id3.org/ (now https://id3.org)
10
10
  # 2) http://www.mp3-tech.org/
11
11
  # 3) http://www.fortunecity.com/underworld/sonic/3/id3tag.html
12
12
  # 4) https://id3.org/Lyrics3
@@ -76,9 +76,9 @@ my %dateTimeConv = (
76
76
  OGG, FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple
77
77
  languages (eg. Comment and Lyrics) are extracted by specifying the tag name,
78
78
  followed by a dash ('-'), then a 3-character ISO 639-2 language code (eg.
79
- "Comment-spa"). See L<http://www.id3.org/> for the official ID3
80
- specification and L<http://www.loc.gov/standards/iso639-2/php/code_list.php>
81
- for a list of ISO 639-2 language codes.
79
+ "Comment-spa"). See L<https://id3.org/> for the official ID3 specification
80
+ and L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of
81
+ ISO 639-2 language codes.
82
82
  },
83
83
  ID3v1 => {
84
84
  Name => 'ID3v1',
@@ -1661,7 +1661,7 @@ under the same terms as Perl itself.
1661
1661
 
1662
1662
  =over 4
1663
1663
 
1664
- =item L<http://www.id3.org/>
1664
+ =item L<https://id3.org/>
1665
1665
 
1666
1666
  =item L<http://www.mp3-tech.org/>
1667
1667
 
@@ -12,7 +12,7 @@ use strict;
12
12
  use vars qw($VERSION);
13
13
  use Image::ExifTool qw(:DataAccess :Utils);
14
14
 
15
- $VERSION = '1.11';
15
+ $VERSION = '1.12';
16
16
 
17
17
  sub MDItemLocalTime($);
18
18
  sub ProcessATTR($$$);
@@ -381,7 +381,7 @@ sub SetMacOSTags($$$)
381
381
  $val = Image::ExifTool::ConvertUnixTime($time, 1) if $time;
382
382
  }
383
383
  $val =~ s{(\d{4}):(\d{2}):(\d{2})}{$2/$3/$1}; # reformat for setfile
384
- $cmd = "setfile -d '${val}' '${f}'";
384
+ $cmd = "/usr/bin/setfile -d '${val}' '${f}'";
385
385
  } elsif ($tag eq 'MDItemUserTags') {
386
386
  # (tested with "tag" version 0.9.0)
387
387
  ($f = $file) =~ s/'/'\\''/g;
@@ -391,7 +391,7 @@ sub SetMacOSTags($$$)
391
391
  my @dels = @{$$nvHash{DelValue}};
392
392
  s/'/'\\''/g foreach @dels;
393
393
  my $del = join ',', @dels;
394
- $err = system "tag -r '${del}' '${f}'>/dev/null 2>&1";
394
+ $err = system "/usr/local/bin/tag -r '${del}' '${f}'>/dev/null 2>&1";
395
395
  unless ($err) {
396
396
  $et->VerboseValue("- $tag", $del);
397
397
  $result = 1;
@@ -403,13 +403,13 @@ sub SetMacOSTags($$$)
403
403
  s/'/'\\''/g foreach @vals;
404
404
  my $opt = $overwrite > 0 ? '-s' : '-a';
405
405
  $val = @vals ? join(',', @vals) : '';
406
- $cmd = "tag $opt '${val}' '${f}'";
406
+ $cmd = "/usr/local/bin/tag $opt '${val}' '${f}'";
407
407
  $et->VPrint(1," - $tag = (all)\n") if $overwrite > 0;
408
408
  undef $val if $val eq '';
409
409
  }
410
410
  } elsif ($tag eq 'XAttrQuarantine') {
411
411
  ($f = $file) =~ s/'/'\\''/g;
412
- $cmd = "xattr -d com.apple.quarantine '${f}'";
412
+ $cmd = "/usr/bin/xattr -d com.apple.quarantine '${f}'";
413
413
  $silentErr = 256; # (will get this error if attribute doesn't exist)
414
414
  } else {
415
415
  ($f = $file) =~ s/(["\\])/\\$1/g; # escape necessary characters for script
@@ -426,7 +426,7 @@ sub SetMacOSTags($$$)
426
426
  $v = $val ? 8 - $val : 0; # convert from label to label index (0 for no label)
427
427
  $attr = 'label index';
428
428
  }
429
- $cmd = qq(osascript -e 'set fp to POSIX file "$f" as alias' -e \\
429
+ $cmd = qq(/usr/bin/osascript -e 'set fp to POSIX file "$f" as alias' -e \\
430
430
  'tell application "Finder" to set $attr of file fp to "$v"');
431
431
  }
432
432
  if (defined $cmd) {
@@ -455,7 +455,7 @@ sub ExtractMDItemTags($$)
455
455
 
456
456
  ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters
457
457
  $et->VPrint(0, '(running mdls)');
458
- my @mdls = `mdls "$fn" 2> /dev/null`; # get MacOS metadata
458
+ my @mdls = `/usr/bin/mdls "$fn" 2> /dev/null`; # get MacOS metadata
459
459
  if ($? or not @mdls) {
460
460
  $et->Warn('Error running "mdls" to extract MDItem tags');
461
461
  return;
@@ -565,7 +565,7 @@ sub ExtractXAttrTags($$)
565
565
 
566
566
  ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters
567
567
  $et->VPrint(0, '(running xattr)');
568
- my @xattr = `xattr -lx "$fn" 2> /dev/null`; # get MacOS extended attributes
568
+ my @xattr = `/usr/bin/xattr -lx "$fn" 2> /dev/null`; # get MacOS extended attributes
569
569
  if ($? or not @xattr) {
570
570
  $? and $et->Warn('Error running "xattr" to extract XAttr tags');
571
571
  return;
@@ -611,7 +611,7 @@ sub GetFileCreateDate($$)
611
611
 
612
612
  ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters
613
613
  $et->VPrint(0, '(running stat)');
614
- my $time = `stat -f '%SB' -t '%Y:%m:%d %H:%M:%S%z' "$fn" 2> /dev/null`;
614
+ my $time = `/usr/bin/stat -f '%SB' -t '%Y:%m:%d %H:%M:%S%z' "$fn" 2> /dev/null`;
615
615
  if ($? or not $time or $time !~ s/([-+]\d{2})(\d{2})\s*$/$1:$2/) {
616
616
  $et->Warn('Error running "stat" to extract FileCreateDate');
617
617
  return;