exiftool_vendored 11.99.0 → 12.11.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +201 -2
  3. data/bin/MANIFEST +8 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +43 -42
  7. data/bin/exiftool +172 -99
  8. data/bin/lib/Image/ExifTool.pm +170 -117
  9. data/bin/lib/Image/ExifTool.pod +132 -97
  10. data/bin/lib/Image/ExifTool/AIFF.pm +2 -2
  11. data/bin/lib/Image/ExifTool/APE.pm +2 -2
  12. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +21 -10
  13. data/bin/lib/Image/ExifTool/Canon.pm +202 -13
  14. data/bin/lib/Image/ExifTool/CanonCustom.pm +82 -16
  15. data/bin/lib/Image/ExifTool/DPX.pm +56 -2
  16. data/bin/lib/Image/ExifTool/DarwinCore.pm +22 -3
  17. data/bin/lib/Image/ExifTool/EXE.pm +8 -5
  18. data/bin/lib/Image/ExifTool/Exif.pm +15 -6
  19. data/bin/lib/Image/ExifTool/Font.pm +9 -2
  20. data/bin/lib/Image/ExifTool/GIF.pm +6 -1
  21. data/bin/lib/Image/ExifTool/GeoTiff.pm +2 -0
  22. data/bin/lib/Image/ExifTool/Geotag.pm +2 -2
  23. data/bin/lib/Image/ExifTool/GoPro.pm +48 -22
  24. data/bin/lib/Image/ExifTool/H264.pm +1 -1
  25. data/bin/lib/Image/ExifTool/ID3.pm +86 -12
  26. data/bin/lib/Image/ExifTool/IPTC.pm +1 -0
  27. data/bin/lib/Image/ExifTool/Import.pm +12 -9
  28. data/bin/lib/Image/ExifTool/JSON.pm +27 -4
  29. data/bin/lib/Image/ExifTool/Lang/de.pm +3 -1
  30. data/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  31. data/bin/lib/Image/ExifTool/M2TS.pm +1 -1
  32. data/bin/lib/Image/ExifTool/MPF.pm +2 -2
  33. data/bin/lib/Image/ExifTool/MacOS.pm +154 -38
  34. data/bin/lib/Image/ExifTool/Matroska.pm +3 -1
  35. data/bin/lib/Image/ExifTool/Minolta.pm +7 -2
  36. data/bin/lib/Image/ExifTool/Nikon.pm +143 -17
  37. data/bin/lib/Image/ExifTool/Olympus.pm +40 -17
  38. data/bin/lib/Image/ExifTool/PNG.pm +14 -3
  39. data/bin/lib/Image/ExifTool/PPM.pm +5 -5
  40. data/bin/lib/Image/ExifTool/Panasonic.pm +148 -14
  41. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +34 -0
  42. data/bin/lib/Image/ExifTool/Parrot.pm +2 -1
  43. data/bin/lib/Image/ExifTool/Pentax.pm +11 -3
  44. data/bin/lib/Image/ExifTool/Photoshop.pm +2 -1
  45. data/bin/lib/Image/ExifTool/QuickTime.pm +240 -37
  46. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +419 -60
  47. data/bin/lib/Image/ExifTool/README +25 -21
  48. data/bin/lib/Image/ExifTool/RSRC.pm +17 -11
  49. data/bin/lib/Image/ExifTool/Radiance.pm +7 -2
  50. data/bin/lib/Image/ExifTool/Ricoh.pm +19 -1
  51. data/bin/lib/Image/ExifTool/Shift.pl +1 -0
  52. data/bin/lib/Image/ExifTool/SigmaRaw.pm +40 -33
  53. data/bin/lib/Image/ExifTool/Sony.pm +423 -39
  54. data/bin/lib/Image/ExifTool/Stim.pm +2 -2
  55. data/bin/lib/Image/ExifTool/TagLookup.pm +5798 -5675
  56. data/bin/lib/Image/ExifTool/TagNames.pod +575 -100
  57. data/bin/lib/Image/ExifTool/Validate.pm +4 -4
  58. data/bin/lib/Image/ExifTool/WriteExif.pl +1 -0
  59. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +30 -21
  60. data/bin/lib/Image/ExifTool/Writer.pl +49 -24
  61. data/bin/lib/Image/ExifTool/XMP.pm +99 -17
  62. data/bin/lib/Image/ExifTool/XMP2.pl +1 -0
  63. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  64. data/bin/lib/Image/ExifTool/ZISRAW.pm +123 -0
  65. data/bin/perl-Image-ExifTool.spec +42 -41
  66. data/lib/exiftool_vendored/version.rb +1 -1
  67. metadata +9 -8
@@ -17,7 +17,7 @@ package Image::ExifTool::Validate;
17
17
  use strict;
18
18
  use vars qw($VERSION %exifSpec);
19
19
 
20
- $VERSION = '1.17';
20
+ $VERSION = '1.18';
21
21
 
22
22
  use Image::ExifTool qw(:Utils);
23
23
  use Image::ExifTool::Exif;
@@ -214,11 +214,11 @@ my %validValue = (
214
214
  IFD0 => {
215
215
  0x100 => 'defined $val', # ImageWidth
216
216
  0x101 => 'defined $val', # ImageLength
217
- 0x102 => 'defined $val', # BitsPerSample
217
+ # (default is 1) 0x102 => 'defined $val', # BitsPerSample
218
218
  0x103 => q{
219
219
  not defined $val or $val =~ /^(1|5|6|32773)$/ or
220
220
  ($val == 2 and (not defined $val{0x102} or $val{0x102} == 1));
221
- }, # Compression
221
+ }, # Compression
222
222
  0x106 => '$val =~ /^[0123]$/', # PhotometricInterpretation
223
223
  0x111 => 'defined $val', # StripOffsets
224
224
  # SamplesPerPixel
@@ -237,7 +237,7 @@ my %validValue = (
237
237
  0x117 => 'defined $val', # StripByteCounts
238
238
  0x11a => 'defined $val', # XResolution
239
239
  0x11b => 'defined $val', # YResolution
240
- 0x128 => '$val =~ /^[123]$/', # ResolutionUnit
240
+ 0x128 => 'not defined $val or $val =~ /^[123]$/', # ResolutionUnit
241
241
  # ColorMap (must be palette image with correct number of colors)
242
242
  0x140 => q{
243
243
  return '' if defined $val{0x106} and $val{0x106} == 3 xor defined $val;
@@ -1832,6 +1832,7 @@ NoOverwrite: next if $isNew > 0;
1832
1832
  warn "Internal error writing offsets for $$newInfo{Name}\n";
1833
1833
  return undef;
1834
1834
  }
1835
+ $newValuePt = \$newValue;
1835
1836
  }
1836
1837
  $offsetInfo or $offsetInfo = $offsetInfo[$ifd] = { };
1837
1838
  # save location of valuePtr in new directory
@@ -144,7 +144,7 @@ sub PrintInvGPSCoordinates($)
144
144
  $v[2] = Image::ExifTool::ToFloat($v[2]) * ($below ? -1 : 1) if @v == 3;
145
145
  return "@v";
146
146
  }
147
- return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?$/; # already in ISO6709 format?
147
+ return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?\/?$/; # already in ISO6709 format?
148
148
  return undef;
149
149
  }
150
150
 
@@ -159,15 +159,16 @@ sub ConvInvISO6709($)
159
159
  my @a = split ' ', $val;
160
160
  if (@a == 2 or @a == 3) {
161
161
  # latitude must have 2 digits before the decimal, and longitude 3,
162
- # and all values must start with a "+" or "-"
163
- my @fmt = ('%s%02d','%s%03d','%s%d');
162
+ # and all values must start with a "+" or "-", and Google Photos
163
+ # requires at least 3 digits after the decimal point
164
+ my @fmt = ('%s%02d.%s%s','%s%03d.%s%s','%s%d.%s%s');
164
165
  foreach (@a) {
165
166
  return undef unless Image::ExifTool::IsFloat($_);
166
- $_ =~ s/^([-+]?)(\d+)/sprintf(shift(@fmt), $1 || '+', $2)/e;
167
+ $_ =~ s/^([-+]?)(\d+)\.?(\d*)/sprintf(shift(@fmt),$1||'+',$2,$3,length($3)<3 ? '0'x(3-length($3)) : '')/e;
167
168
  }
168
- return join '', @a;
169
+ return join '', @a, '/';
169
170
  }
170
- return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?$/; # already in ISO6709 format?
171
+ return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?\/?$/; # already in ISO6709 format?
171
172
  return undef;
172
173
  }
173
174
 
@@ -300,15 +301,19 @@ sub CheckQTValue($$$)
300
301
 
301
302
  #------------------------------------------------------------------------------
302
303
  # Format QuickTime value for writing
303
- # Inputs: 0) ExifTool ref, 1) value ref, 2) Format (or undef)
304
+ # Inputs: 0) ExifTool ref, 1) value ref, 2) Format (or undef), 3) Writable (or undef)
304
305
  # Returns: Flags for QT data type, and reformats value as required
305
- sub FormatQTValue($$;$)
306
+ sub FormatQTValue($$;$$)
306
307
  {
307
- my ($et, $valPt, $format) = @_;
308
+ my ($et, $valPt, $format, $writable) = @_;
308
309
  my $flags;
309
310
  if ($format and $format ne 'string') {
310
311
  $$valPt = WriteValue($$valPt, $format);
311
- $flags = $qtFormat{$format} || 0;
312
+ if ($writable and $qtFormat{$writable}) {
313
+ $flags = $qtFormat{$writable};
314
+ } else {
315
+ $flags = $qtFormat{$format} || 0;
316
+ }
312
317
  } elsif ($$valPt =~ /^\xff\xd8\xff/) {
313
318
  $flags = 0x0d; # JPG
314
319
  } elsif ($$valPt =~ /^(\x89P|\x8aM|\x8bJ)NG\r\n\x1a\n/) {
@@ -1122,9 +1127,9 @@ sub WriteQuickTime($$$)
1122
1127
  my $newVal = $et->GetNewValue($nvHash);
1123
1128
  next unless defined $newVal;
1124
1129
  my $prVal = $newVal;
1125
- my $flags = FormatQTValue($et, \$newVal, $format);
1130
+ my $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable});
1126
1131
  next unless defined $newVal;
1127
- my ($ctry, $lang) = (0, $undLang);
1132
+ my ($ctry, $lang) = (0, 0);
1128
1133
  if ($$ti{LangCode}) {
1129
1134
  unless ($$ti{LangCode} =~ /^([A-Z]{3})?[-_]?([A-Z]{2})?$/i) {
1130
1135
  $et->Warn("Invalid language code for $$ti{Name}");
@@ -1180,7 +1185,11 @@ sub WriteQuickTime($$$)
1180
1185
  } else {
1181
1186
  if ($format) {
1182
1187
  # update flags for the format we are writing
1183
- $flags = $qtFormat{$format} if $qtFormat{$format};
1188
+ if ($$tagInfo{Writable} and $qtFormat{$$tagInfo{Writable}}) {
1189
+ $flags = $qtFormat{$$tagInfo{Writable}};
1190
+ } elsif ($qtFormat{$format}) {
1191
+ $flags = $qtFormat{$format};
1192
+ }
1184
1193
  } else {
1185
1194
  $format = QuickTimeFormat($flags, $len);
1186
1195
  }
@@ -1199,12 +1208,13 @@ sub WriteQuickTime($$$)
1199
1208
  }
1200
1209
  my $prVal = $newVal;
1201
1210
  # format new value for writing (and get new flags)
1202
- $flags = FormatQTValue($et, \$newVal, $format);
1211
+ $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable});
1203
1212
  my $grp = $et->GetGroup($langInfo, 1);
1204
1213
  $et->VerboseValue("- $grp:$$langInfo{Name}", $val);
1205
1214
  $et->VerboseValue("+ $grp:$$langInfo{Name}", $prVal);
1206
1215
  $newData = substr($buff, 0, $pos-16) unless defined $newData;
1207
- $newData .= pack('Na4Nnn', length($newVal)+16, $type, $flags, $ctry, $lang);
1216
+ my $wLang = $lang eq $undLang ? 0 : $lang;
1217
+ $newData .= pack('Na4Nnn', length($newVal)+16, $type, $flags, $ctry, $wLang);
1208
1218
  $newData .= $newVal;
1209
1219
  ++$$et{CHANGED};
1210
1220
  } elsif (defined $newData) {
@@ -1268,10 +1278,11 @@ sub WriteQuickTime($$$)
1268
1278
  # add back necessary header and encode as necessary
1269
1279
  if (defined $lang) {
1270
1280
  $newData = $et->Encode($newData, $lang < 0x400 ? $charsetQuickTime : 'UTF8');
1281
+ my $wLang = $lang eq $undLang ? 0 : $lang;
1271
1282
  if ($$tagInfo{IText} and $$tagInfo{IText} == 6) {
1272
- $newData = pack('Nn', 0, $lang) . $newData . "\0";
1283
+ $newData = pack('Nn', 0, $wLang) . $newData . "\0";
1273
1284
  } else {
1274
- $newData = pack('nn', length($newData), $lang) . $newData;
1285
+ $newData = pack('nn', length($newData), $wLang) . $newData;
1275
1286
  }
1276
1287
  } elsif (not $format or $format =~ /^string/ and
1277
1288
  not $$tagInfo{Binary} and not $$tagInfo{ValueConv})
@@ -1406,9 +1417,9 @@ sub WriteQuickTime($$$)
1406
1417
  my $newVal = $et->GetNewValue($nvHash);
1407
1418
  next unless defined $newVal;
1408
1419
  my $prVal = $newVal;
1409
- my $flags = FormatQTValue($et, \$newVal, $$tagInfo{Format});
1420
+ my $flags = FormatQTValue($et, \$newVal, $$tagInfo{Format}, $$tagInfo{Writable});
1410
1421
  next unless defined $newVal;
1411
- my ($ctry, $lang) = (0,0);
1422
+ my ($ctry, $lang) = (0, 0);
1412
1423
  # handle alternate languages
1413
1424
  if ($$tagInfo{LangCode}) {
1414
1425
  $tag = substr($tag, 0, 4); # strip language code from tag ID
@@ -1424,10 +1435,8 @@ sub WriteQuickTime($$$)
1424
1435
  }
1425
1436
  if ($$dirInfo{HasData}) {
1426
1437
  # add 'data' header
1427
- $lang or $lang = $undLang;
1428
1438
  $newVal = pack('Na4Nnn',16+length($newVal),'data',$flags,$ctry,$lang).$newVal;
1429
1439
  } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) {
1430
- $lang or $lang = $undLang;
1431
1440
  if ($ctry) {
1432
1441
  my $grp = $et->GetGroup($tagInfo,1);
1433
1442
  $et->Warn("Can't use country code for $grp:$$tagInfo{Name}");
@@ -359,21 +359,25 @@ sub SetNewValue($;$$%)
359
359
  my $convType = $options{Type} || ($$self{OPTIONS}{PrintConv} ? 'PrintConv' : 'ValueConv');
360
360
 
361
361
  # filter value if necessary
362
- $self->Filter($$self{OPTIONS}{FilterW}, \$value) if $convType eq 'PrintConv';
362
+ $self->Filter($$self{OPTIONS}{FilterW}, \$value) or return 0 if $convType eq 'PrintConv';
363
363
 
364
364
  my (@wantGroup, $family2);
365
365
  my $wantGroup = $options{Group};
366
366
  if ($wantGroup) {
367
367
  foreach (split /:/, $wantGroup) {
368
368
  next unless length($_) and /^(\d+)?(.*)/; # separate family number and group name
369
- my ($f, $g) = ($1, lc $2);
369
+ my ($f, $g) = ($1, $2);
370
+ my $lcg = lc $g;
370
371
  # save group/family unless '*' or 'all'
371
- push @wantGroup, [ $f, $g ] unless $g eq '*' or $g eq 'all';
372
- if (defined $f) {
373
- $f > 2 and return 0; # only allow family 0, 1 or 2
374
- $family2 = 1 if $f == 2; # set flag indicating family 2 was used
372
+ push @wantGroup, [ $f, $lcg ] unless $lcg eq '*' or $lcg eq 'all';
373
+ if ($g =~ s/^ID-//i) { # family 7 is a tag ID
374
+ return 0 if defined $f and $f ne 7;
375
+ $wantGroup[-1] = [ 7, $g ]; # group name with 'ID-' removed and case preserved
376
+ } elsif (defined $f) {
377
+ $f > 2 and return 0; # only allow family 0, 1 or 2
378
+ $family2 = 1 if $f == 2; # set flag indicating family 2 was used
375
379
  } else {
376
- $family2 = 1 if $family2groups{$g};
380
+ $family2 = 1 if $family2groups{$lcg};
377
381
  }
378
382
  }
379
383
  undef $wantGroup unless @wantGroup;
@@ -622,6 +626,8 @@ TAG: foreach $tagInfo (@matchingTags) {
622
626
  next;
623
627
  }
624
628
  next if $lcWant eq lc $grp[2];
629
+ } elsif ($fam == 7) {
630
+ next if IsSameID($$tagInfo{TagID}, $lcWant);
625
631
  } elsif ($fam != 1 and not $$tagInfo{AllowGroup}) {
626
632
  next if $lcWant eq lc $grp[$fam];
627
633
  if ($wgAll and not $fam and $allFam0{$lcWant}) {
@@ -1258,6 +1264,7 @@ sub SetNewValuesFromFile($$;@)
1258
1264
  Filter => $$options{Filter},
1259
1265
  FixBase => $$options{FixBase},
1260
1266
  GlobalTimeShift => $$options{GlobalTimeShift},
1267
+ HexTagIDs => $$options{HexTagIDs},
1261
1268
  IgnoreMinorErrors=>$$options{IgnoreMinorErrors},
1262
1269
  Lang => $$options{Lang},
1263
1270
  LargeFileSupport=> $$options{LargeFileSupport},
@@ -1409,7 +1416,9 @@ sub SetNewValuesFromFile($$;@)
1409
1416
  foreach (split /:/, $grp) {
1410
1417
  # save family/groups in list (ignoring 'all' and '*')
1411
1418
  next unless length($_) and /^(\d+)?(.*)/;
1412
- push @fg, [ $1, $2 ] unless $2 eq '*' or $2 eq 'all';
1419
+ my ($f, $g) = ($1, $2);
1420
+ $f = 7 if $g =~ s/^ID-//i;
1421
+ push @fg, [ $f, $g ] unless $g eq '*' or $g eq 'all';
1413
1422
  }
1414
1423
  }
1415
1424
  # allow ValueConv to be specified by a '#' on the tag name
@@ -1475,10 +1484,12 @@ SET: foreach $set (@setList) {
1475
1484
  }
1476
1485
  foreach (@{$$set[0]}) {
1477
1486
  my ($f, $g) = @$_;
1478
- if (defined $f) {
1479
- next SET unless defined $grp[$f] and $g eq $grp[$f];
1480
- } else {
1487
+ if (not defined $f) {
1481
1488
  next SET unless $grp{$g};
1489
+ } elsif ($f == 7) {
1490
+ next SET unless IsSameID($srcExifTool->GetTagID($tag), $g);
1491
+ } else {
1492
+ next SET unless defined $grp[$f] and $g eq $grp[$f];
1482
1493
  }
1483
1494
  }
1484
1495
  }
@@ -1598,21 +1609,25 @@ sub GetNewValue($$;$)
1598
1609
  $nvHash = $self->GetNewValueHash($tagInfo);
1599
1610
  } else {
1600
1611
  # separate group from tag name
1601
- $group = $1 if $tag =~ s/(.*)://;
1612
+ my @groups;
1613
+ @groups = split ':', $1 if $tag =~ s/(.*)://;
1602
1614
  my @tagInfoList = FindTagInfo($tag);
1603
1615
  # decide which tag we want
1604
1616
  GNV_TagInfo: foreach $tagInfo (@tagInfoList) {
1605
1617
  my $nvh = $self->GetNewValueHash($tagInfo) or next;
1606
- # select tag in specified group if necessary
1607
- while ($group and $group ne $$nvh{WriteGroup}) {
1618
+ # select tag in specified group(s) if necessary
1619
+ foreach (@groups) {
1620
+ next if $_ eq $$nvh{WriteGroup};
1608
1621
  my @grps = $self->GetGroup($tagInfo);
1609
1622
  if ($grps[0] eq $$nvh{WriteGroup}) {
1610
1623
  # check family 1 group only if WriteGroup is not specific
1611
- last if $group eq $grps[1];
1624
+ next if $_ eq $grps[1];
1612
1625
  } else {
1613
1626
  # otherwise check family 0 group
1614
- last if $group eq $grps[0];
1627
+ next if $_ eq $grps[0];
1615
1628
  }
1629
+ # also check family 7
1630
+ next if /^ID-(.*)/i and IsSameID($$tagInfo{TagID}, $1);
1616
1631
  # step to next entry in list
1617
1632
  $nvh = $$nvh{Next} or next GNV_TagInfo;
1618
1633
  }
@@ -2007,7 +2022,7 @@ sub SetFileName($$;$$$)
2007
2022
 
2008
2023
  #------------------------------------------------------------------------------
2009
2024
  # Set file permissions, group/user id and various MDItem tags from new tag values
2010
- # Inputs: 0) Exiftool ref, 1) file name or glob (must be a name for MDItem tags)
2025
+ # Inputs: 0) ExifTool ref, 1) file name or glob (must be a name for MDItem tags)
2011
2026
  # Returns: 1=something was set OK, 0=didn't try, -1=error (and warning set)
2012
2027
  # Notes: There may be errors even if 1 is returned
2013
2028
  sub SetSystemTags($$)
@@ -3269,7 +3284,7 @@ sub IsSameFile($$$)
3269
3284
 
3270
3285
  #------------------------------------------------------------------------------
3271
3286
  # Is this a raw file type?
3272
- # Inputs: 0) Exiftool ref
3287
+ # Inputs: 0) ExifTool ref
3273
3288
  # Returns: true if FileType is a type of RAW image
3274
3289
  sub IsRawType($)
3275
3290
  {
@@ -4020,6 +4035,7 @@ sub WriteDirectory($$$;$)
4020
4035
  if ($dataPt or $$dirInfo{RAF}) {
4021
4036
  ++$$self{CHANGED};
4022
4037
  $out and print $out " Deleting $grp1\n";
4038
+ $self->Warn('ICC_Profile deleted. Image colors may be affected') if $grp1 eq 'ICC_Profile';
4023
4039
  # can no longer validate TIFF_END if deleting an entire IFD
4024
4040
  delete $$self{TIFF_END} if $dirName =~ /IFD/;
4025
4041
  }
@@ -4691,17 +4707,17 @@ sub InverseDateTime($$;$$)
4691
4707
  {
4692
4708
  my ($self, $val, $tzFlag, $dateOnly) = @_;
4693
4709
  my ($rtnVal, $tz);
4710
+ my $fmt = $$self{OPTIONS}{DateFormat};
4694
4711
  # strip off timezone first if it exists
4695
- if ($val =~ s/([+-])(\d{1,2}):?(\d{2})\s*(DST)?$//i) {
4712
+ if (not $fmt and $val =~ s/([+-])(\d{1,2}):?(\d{2})\s*(DST)?$//i) {
4696
4713
  $tz = sprintf("$1%.2d:$3", $2);
4697
- } elsif ($val =~ s/Z$//i) {
4714
+ } elsif (not $fmt and $val =~ s/Z$//i) {
4698
4715
  $tz = 'Z';
4699
4716
  } else {
4700
4717
  $tz = '';
4701
4718
  # allow special value of 'now'
4702
4719
  return $self->TimeNow($tzFlag) if lc($val) eq 'now';
4703
4720
  }
4704
- my $fmt = $$self{OPTIONS}{DateFormat};
4705
4721
  # only convert date if a format was specified and the date is recognizable
4706
4722
  if ($fmt) {
4707
4723
  unless (defined $strptimeLib) {
@@ -5525,7 +5541,11 @@ sub WriteJPEG($$)
5525
5541
  my $buff = $self->WriteDirectory(\%dirInfo, $tagTablePtr, \&WriteTIFF);
5526
5542
  if (defined $buff and length $buff) {
5527
5543
  if (length($buff) + length($exifAPP1hdr) > $maxSegmentLen) {
5528
- $self->Warn('Creating multi-segment EXIF',1);
5544
+ if ($self->Options('NoMultiExif')) {
5545
+ $self->Error('EXIF is too large for JPEG segment');
5546
+ } else {
5547
+ $self->Warn('Creating multi-segment EXIF',1);
5548
+ }
5529
5549
  }
5530
5550
  # switch to buffered output if required
5531
5551
  if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) {
@@ -5891,6 +5911,7 @@ sub WriteJPEG($$)
5891
5911
  # group delete of APP segments
5892
5912
  if ($$delGroup{$dirName}) {
5893
5913
  $verbose and print $out " Deleting $dirName segment\n";
5914
+ $self->Warn('ICC_Profile deleted. Image colors may be affected') if $dirName eq 'ICC_Profile';
5894
5915
  ++$$self{CHANGED};
5895
5916
  next Marker;
5896
5917
  }
@@ -5997,7 +6018,11 @@ sub WriteJPEG($$)
5997
6018
  # delete segment if IFD contains no entries
5998
6019
  length $$segDataPt or $del = 1, last;
5999
6020
  if (length($$segDataPt) + length($exifAPP1hdr) > $maxSegmentLen) {
6000
- $self->Warn('Writing multi-segment EXIF',1);
6021
+ if ($self->Options('NoMultiExif')) {
6022
+ $self->Error('EXIF is too large for JPEG segment');
6023
+ } else {
6024
+ $self->Warn('Writing multi-segment EXIF',1);
6025
+ }
6001
6026
  }
6002
6027
  # switch to buffered output if required
6003
6028
  if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) {
@@ -6779,7 +6804,7 @@ sub WriteBinaryData($$$)
6779
6804
  my $val = ReadValue($dataPt, $entry, $format, $count, $dirLen-$entry);
6780
6805
  next unless defined $val;
6781
6806
  my $nvHash = $self->GetNewValueHash($tagInfo, $$self{CUR_WRITE_GROUP});
6782
- next unless $self->IsOverwriting($nvHash, $val);
6807
+ next unless $self->IsOverwriting($nvHash, $val) > 0;
6783
6808
  my $newVal = $self->GetNewValue($nvHash);
6784
6809
  next unless defined $newVal; # can't delete from a binary table
6785
6810
  # update DataMember with new value if necessary
@@ -25,7 +25,8 @@
25
25
  # 10) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf (Oct 2008)
26
26
  # 11) http://www.extensis.com/en/support/kb_article.jsp?articleNumber=6102211
27
27
  # 12) http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf
28
- # 13) http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf
28
+ # 13) http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf (changed to
29
+ # http://www.cipa.jp/std/documents/e/DC-X010-2017.pdf)
29
30
  #
30
31
  # Notes: - Property qualifiers are handled as if they were separate
31
32
  # properties (with no associated namespace).
@@ -49,7 +50,7 @@ use Image::ExifTool::Exif;
49
50
  use Image::ExifTool::GPS;
50
51
  require Exporter;
51
52
 
52
- $VERSION = '3.32';
53
+ $VERSION = '3.36';
53
54
  @ISA = qw(Exporter);
54
55
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
55
56
 
@@ -889,6 +890,7 @@ my %sRetouchArea = (
889
890
  ModifyDate => { Groups => { 2 => 'Time' }, %dateTimeInfo, Priority => 0 },
890
891
  Nickname => { },
891
892
  Rating => { Writable => 'real', Notes => 'a value from 0 to 5, or -1 for "rejected"' },
893
+ RatingPercent=>{ Writable => 'real', Avoid => 1, Notes => 'non-standard' },
892
894
  Thumbnails => {
893
895
  FlatName => 'Thumbnail',
894
896
  Struct => \%sThumbnail,
@@ -1144,7 +1146,7 @@ my %sPantryItem = (
1144
1146
  LayerText => { },
1145
1147
  },
1146
1148
  },
1147
- TransmissionReference => { },
1149
+ TransmissionReference => { Notes => 'Now used as a job identifier' },
1148
1150
  Urgency => {
1149
1151
  Writable => 'integer',
1150
1152
  Notes => 'should be in the range 1-8 to conform with the XMP spec',
@@ -1289,11 +1291,11 @@ my %sPantryItem = (
1289
1291
  SharpenDetail => { Writable => 'integer' },
1290
1292
  SharpenEdgeMasking => { Writable => 'integer' },
1291
1293
  SharpenRadius => { Writable => 'real' },
1292
- SplitToningBalance => { Writable => 'integer' },
1293
- SplitToningHighlightHue => { Writable => 'integer' },
1294
- SplitToningHighlightSaturation => { Writable => 'integer' },
1295
- SplitToningShadowHue => { Writable => 'integer' },
1296
- SplitToningShadowSaturation => { Writable => 'integer' },
1294
+ SplitToningBalance => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' },
1295
+ SplitToningHighlightHue => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' },
1296
+ SplitToningHighlightSaturation => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' },
1297
+ SplitToningShadowHue => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' },
1298
+ SplitToningShadowSaturation => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' },
1297
1299
  Vibrance => { Writable => 'integer' },
1298
1300
  # new tags written by LR 1.4 (not sure in what version they first appeared)
1299
1301
  GrayMixerRed => { Writable => 'integer' },
@@ -1482,9 +1484,71 @@ my %sPantryItem = (
1482
1484
  Struct => {
1483
1485
  STRUCT_NAME => 'Look',
1484
1486
  NAMESPACE => 'crs',
1485
- Name => { },
1487
+ Name => { },
1488
+ Amount => { },
1489
+ Cluster => { },
1490
+ UUID => { },
1491
+ SupportsMonochrome => { },
1492
+ SupportsAmount => { },
1493
+ SupportsOutputReferred => { },
1494
+ Copyright => { },
1495
+ Group => { Writable => 'lang-alt' },
1496
+ Parameters => {
1497
+ Struct => {
1498
+ STRUCT_NAME => 'LookParms',
1499
+ NAMESPACE => 'crs',
1500
+ Version => { },
1501
+ ProcessVersion => { },
1502
+ Clarity2012 => { },
1503
+ ConvertToGrayscale => { },
1504
+ CameraProfile => { },
1505
+ LookTable => { },
1506
+ ToneCurvePV2012 => { List => 'Seq' },
1507
+ },
1508
+ },
1486
1509
  }
1487
1510
  },
1511
+ # more again (ref forum11258)
1512
+ GrainSeed => { },
1513
+ ClipboardOrientation => { Writable => 'integer' },
1514
+ ClipboardAspectRatio => { Writable => 'integer' },
1515
+ PresetType => { },
1516
+ Cluster => { },
1517
+ UUID => { Avoid => 1 },
1518
+ SupportsAmount => { Writable => 'boolean' },
1519
+ SupportsColor => { Writable => 'boolean' },
1520
+ SupportsMonochrome => { Writable => 'boolean' },
1521
+ SupportsHighDynamicRange=> { Writable => 'boolean' },
1522
+ SupportsNormalDynamicRange=> { Writable => 'boolean' },
1523
+ SupportsSceneReferred => { Writable => 'boolean' },
1524
+ SupportsOutputReferred => { Writable => 'boolean' },
1525
+ CameraModelRestriction => { },
1526
+ Copyright => { Avoid => 1 },
1527
+ ContactInfo => { },
1528
+ GrainSeed => { Writable => 'integer' },
1529
+ Name => { Writable => 'lang-alt', Avoid => 1 },
1530
+ ShortName => { Writable => 'lang-alt' },
1531
+ SortName => { Writable => 'lang-alt' },
1532
+ Group => { Writable => 'lang-alt', Avoid => 1 },
1533
+ Description => { Writable => 'lang-alt', Avoid => 1 },
1534
+ # new for DNG converter 13.0
1535
+ LookName => { NotFlat => 1 }, # (grr... conflicts with "Name" element of "Look" struct!)
1536
+ # new for Lightroom CC 2021 (ref forum11745)
1537
+ ColorGradeMidtoneHue => { Writable => 'integer' },
1538
+ ColorGradeMidtoneSat => { Writable => 'integer' },
1539
+ ColorGradeShadowLum => { Writable => 'integer' },
1540
+ ColorGradeMidtoneLum => { Writable => 'integer' },
1541
+ ColorGradeHighlightLum => { Writable => 'integer' },
1542
+ ColorGradeBlending => { Writable => 'integer' },
1543
+ ColorGradeGlobalHue => { Writable => 'integer' },
1544
+ ColorGradeGlobalSat => { Writable => 'integer' },
1545
+ ColorGradeGlobalLum => { Writable => 'integer' },
1546
+ # new for Adobe Camera Raw 13 (ref forum11745)
1547
+ LensProfileIsEmbedded => { Writable => 'boolean'},
1548
+ AutoToneDigest => { },
1549
+ AutoToneDigestNoSat => { },
1550
+ ToggleStyleDigest => { },
1551
+ ToggleStyleAmount => { Writable => 'integer' },
1488
1552
  );
1489
1553
 
1490
1554
  # Tiff namespace properties (tiff)
@@ -2042,7 +2106,7 @@ my %sPantryItem = (
2042
2106
  PRIORITY => 0, # not as reliable as actual EXIF tags
2043
2107
  NOTES => q{
2044
2108
  EXIF tags added by the EXIF 2.31 for XMP specification (see
2045
- L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf>).
2109
+ L<http://www.cipa.jp/std/documents/e/DC-X010-2017.pdf>).
2046
2110
  },
2047
2111
  Gamma => { Writable => 'rational' },
2048
2112
  PhotographicSensitivity => { Writable => 'integer' },
@@ -2747,8 +2811,9 @@ sub AddFlattenedTags($;$$)
2747
2811
  if ($flatInfo) {
2748
2812
  ref $flatInfo eq 'HASH' or warn("$flatInfo is not a HASH!\n"), next; # (to be safe)
2749
2813
  # pre-defined flattened tags should have Flat flag set
2750
- if (not defined $$flatInfo{Flat} and $Image::ExifTool::debug) {
2751
- warn "Missing Flat flag for $$flatInfo{Name}\n";
2814
+ if (not defined $$flatInfo{Flat}) {
2815
+ next if $$flatInfo{NotFlat};
2816
+ warn "Missing Flat flag for $$flatInfo{Name}\n" if $Image::ExifTool::debug;
2752
2817
  }
2753
2818
  $$flatInfo{Flat} = 0;
2754
2819
  # copy all missing entries from field information
@@ -2935,13 +3000,15 @@ sub PrintLensID(@)
2935
3000
  # for Pentax, CS4 stores an int16u, but we use 2 x int8u
2936
3001
  $id = join(' ', unpack('C*', pack('n', $id)));
2937
3002
  }
2938
- my $str = $$printConv{$id} || "Unknown ($id)";
2939
3003
  # Nikon is a special case because Adobe doesn't store the full LensID
3004
+ # (Apple Photos does, but we have to convert back to hex)
2940
3005
  if ($mk eq 'Nikon') {
2941
- my $hex = sprintf("%.2X", $id);
3006
+ $id = sprintf('%X', $id);
3007
+ $id = "0$id" if length($id) & 0x01; # pad with leading 0 if necessary
3008
+ $id =~ s/(..)/$1 /g and $id =~ s/ $//; # put spaces between bytes
2942
3009
  my (%newConv, %used);
2943
3010
  my $i = 0;
2944
- foreach (grep /^$hex /, keys %$printConv) {
3011
+ foreach (grep /^$id/, keys %$printConv) {
2945
3012
  my $lens = $$printConv{$_};
2946
3013
  next if $used{$lens}; # avoid duplicates
2947
3014
  $used{$lens} = 1;
@@ -2950,6 +3017,7 @@ sub PrintLensID(@)
2950
3017
  }
2951
3018
  $printConv = \%newConv;
2952
3019
  }
3020
+ my $str = $$printConv{$id} || "Unknown ($id)";
2953
3021
  return Image::ExifTool::Exif::PrintLensID($et, $str, $printConv,
2954
3022
  undef, $id, $focalLength, $sa, $maxAv, $sf, $lf, $lensModel);
2955
3023
  }
@@ -3187,8 +3255,9 @@ NoLoop:
3187
3255
  #} elsif (grep / /, @$props) {
3188
3256
  # $$tagInfo{List} = 1;
3189
3257
  }
3258
+ # save property list for verbose "adding" message unless this tag already exists
3259
+ $added = \@tagList unless $$tagTablePtr{$tagID};
3190
3260
  AddTagToTable($tagTablePtr, $tagID, $tagInfo);
3191
- $added = 1;
3192
3261
  last;
3193
3262
  }
3194
3263
  # decode value if necessary (et:encoding was used before exiftool 7.71)
@@ -3272,8 +3341,16 @@ NoLoop:
3272
3341
  }
3273
3342
  if ($$et{OPTIONS}{Verbose}) {
3274
3343
  if ($added) {
3344
+ my $props;
3345
+ if (@$added > 1) {
3346
+ $$tagInfo{Flat} = 0; # this is a flattened tag
3347
+ my @props = map { $$_[0] } @$added;
3348
+ $props = ' (' . join('/',@props) . ')';
3349
+ } else {
3350
+ $props = '';
3351
+ }
3275
3352
  my $g1 = $et->GetGroup($key, 1);
3276
- $et->VPrint(0, $$et{INDENT}, "[adding $g1:$tag]\n");
3353
+ $et->VPrint(0, $$et{INDENT}, "[adding $g1:$tag]$props\n");
3277
3354
  }
3278
3355
  my $tagID = join('/',@$props);
3279
3356
  $et->VerboseInfo($tagID, $tagInfo, Value => $rawVal || $val);
@@ -3531,6 +3608,11 @@ sub ParseXMPElement($$$;$$$$)
3531
3608
  # add svg namespace prefix if missing to ignore these entries in the tag name
3532
3609
  $$propList[-1] = "svg:$prop";
3533
3610
  }
3611
+ } elsif ($$et{XmpIgnoreProps}) { # ignore specified properties for tag name
3612
+ foreach (@{$$et{XmpIgnoreProps}}) {
3613
+ last unless @$propList;
3614
+ pop @$propList if $_ eq $$propList[0];
3615
+ }
3534
3616
  }
3535
3617
 
3536
3618
  # handle properties inside element attributes (RDF shorthand format):