exiftool_vendored 12.68.0 → 12.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +98 -15
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +10 -10
  7. data/bin/exiftool +32 -25
  8. data/bin/lib/Image/ExifTool/AAC.pm +175 -0
  9. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
  10. data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
  11. data/bin/lib/Image/ExifTool/Canon.pm +87 -20
  12. data/bin/lib/Image/ExifTool/DJI.pm +3 -2
  13. data/bin/lib/Image/ExifTool/DNG.pm +25 -2
  14. data/bin/lib/Image/ExifTool/EXE.pm +54 -6
  15. data/bin/lib/Image/ExifTool/Exif.pm +204 -22
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
  17. data/bin/lib/Image/ExifTool/GIF.pm +5 -1
  18. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  19. data/bin/lib/Image/ExifTool/ID3.pm +76 -10
  20. data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
  21. data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
  22. data/bin/lib/Image/ExifTool/JSON.pm +4 -1
  23. data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  24. data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
  25. data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
  26. data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
  27. data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
  28. data/bin/lib/Image/ExifTool/PNG.pm +8 -13
  29. data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
  30. data/bin/lib/Image/ExifTool/Pentax.pm +15 -6
  31. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
  32. data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
  33. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
  34. data/bin/lib/Image/ExifTool/README +14 -5
  35. data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
  36. data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
  37. data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
  38. data/bin/lib/Image/ExifTool/Sony.pm +177 -37
  39. data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
  40. data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
  41. data/bin/lib/Image/ExifTool/Text.pm +4 -5
  42. data/bin/lib/Image/ExifTool/Validate.pm +23 -20
  43. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  44. data/bin/lib/Image/ExifTool/WriteExif.pl +33 -8
  45. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  46. data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  47. data/bin/lib/Image/ExifTool/Writer.pl +121 -28
  48. data/bin/lib/Image/ExifTool/XMP.pm +67 -2
  49. data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
  50. data/bin/lib/Image/ExifTool.pm +94 -43
  51. data/bin/lib/Image/ExifTool.pod +28 -17
  52. data/bin/perl-Image-ExifTool.spec +9 -9
  53. data/lib/exiftool_vendored/version.rb +1 -1
  54. metadata +3 -2
@@ -122,9 +122,9 @@ my %writableType = (
122
122
  XMP => [ undef, 'WriteXMP' ],
123
123
  );
124
124
 
125
- # RAW file types
125
+ # RAW file types (2 = raw file where we can delete maker notes from ExifIFD)
126
126
  my %rawType = (
127
- '3FR'=> 1, CR3 => 1, IIQ => 1, NEF => 1, RW2 => 1,
127
+ '3FR'=> 1, CR3 => 2, IIQ => 1, NEF => 1, RW2 => 1,
128
128
  ARQ => 1, CRW => 1, K25 => 1, NRW => 1, RWL => 1,
129
129
  ARW => 1, DCR => 1, KDC => 1, ORF => 1, SR2 => 1,
130
130
  ARW => 1, ERF => 1, MEF => 1, PEF => 1, SRF => 1,
@@ -278,6 +278,7 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
278
278
  # ListOnly => [internal use] set only list or non-list tags
279
279
  # SetTags => [internal use] hash ref to return tagInfo refs of set tags
280
280
  # Sanitized => [internal use] set to avoid double-sanitizing the value
281
+ # Fixup => [internal use] fixup information when writing maker notes
281
282
  # Returns: number of tags set (plus error string in list context)
282
283
  # Notes: For tag lists (like Keywords), call repeatedly with the same tag name for
283
284
  # each value in the list. Internally, the new information is stored in
@@ -689,6 +690,12 @@ TAG: foreach $tagInfo (@matchingTags) {
689
690
  $writeProc = $$src{WRITE_PROC} unless $writeProc;
690
691
  }
691
692
  {
693
+ # make sure module is loaded if the writeProc is a string
694
+ unless (ref $writeProc) {
695
+ my $module = $writeProc;
696
+ $module =~ s/::\w+$//;
697
+ eval "require $module";
698
+ }
692
699
  no strict 'refs';
693
700
  next unless $writeProc and &$writeProc();
694
701
  }
@@ -1002,10 +1009,8 @@ TAG: foreach $tagInfo (@matchingTags) {
1002
1009
  $$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
1003
1010
  $$nvHash{WantGroup} = $wantGroup;
1004
1011
  $$nvHash{EditOnly} = 1 if $editOnly;
1005
- # save maker note information if writing maker notes
1006
- if ($$tagInfo{MakerNotes}) {
1007
- $$nvHash{MAKER_NOTE_FIXUP} = $$self{MAKER_NOTE_FIXUP};
1008
- }
1012
+ # save maker note fixup information if writing maker notes
1013
+ $$nvHash{MAKER_NOTE_FIXUP} = $options{Fixup} if $$tagInfo{MakerNotes};
1009
1014
  if ($createOnly) { # create only (never edit)
1010
1015
  # empty item in DelValue list to never edit existing value
1011
1016
  $$nvHash{DelValue} = [ '' ];
@@ -1272,6 +1277,7 @@ sub SetNewValuesFromFile($$;@)
1272
1277
  # +------------------------------------------+
1273
1278
  $srcExifTool->Options(
1274
1279
  Binary => 1,
1280
+ ByteUnit => $$options{ByteUnit},
1275
1281
  Charset => $$options{Charset},
1276
1282
  CharsetEXIF => $$options{CharsetEXIF},
1277
1283
  CharsetFileName => $$options{CharsetFileName},
@@ -1372,8 +1378,8 @@ sub SetNewValuesFromFile($$;@)
1372
1378
  #
1373
1379
  unless (@setTags) {
1374
1380
  # transfer maker note information to this object
1375
- $$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
1376
1381
  $$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
1382
+ my $tagExtra = $$srcExifTool{TAG_EXTRA};
1377
1383
  foreach $tag (@tags) {
1378
1384
  # don't try to set errors or warnings
1379
1385
  next if $tag =~ /^(Error|Warning)\b/;
@@ -1381,10 +1387,13 @@ sub SetNewValuesFromFile($$;@)
1381
1387
  if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
1382
1388
  $$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
1383
1389
  }
1390
+ my $fixup = $$tagExtra{$tag}{Fixup};
1391
+ $opts{Fixup} = $fixup if $fixup;
1384
1392
  # set value for this tag
1385
1393
  my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
1386
1394
  # delete this tag if we couldn't set it
1387
1395
  $n or delete $$info{$tag};
1396
+ delete $opts{Fixup} if $fixup;
1388
1397
  }
1389
1398
  return $info;
1390
1399
  }
@@ -1617,7 +1626,7 @@ SET: foreach $set (@setList) {
1617
1626
  }
1618
1627
  # transfer maker note information if setting this tag
1619
1628
  if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
1620
- $$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
1629
+ $$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
1621
1630
  $$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
1622
1631
  }
1623
1632
  if ($dstTag eq '*') {
@@ -1649,6 +1658,7 @@ SET: foreach $set (@setList) {
1649
1658
  $rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
1650
1659
  $noWarn = 1;
1651
1660
  }
1661
+ delete $$opts{Fixup};
1652
1662
  $rtnInfo{$tag} = $val if $rtn; # tag was set successfully
1653
1663
  }
1654
1664
  }
@@ -3235,9 +3245,15 @@ sub InsertTagValues($$$;$$$)
3235
3245
  $tag = $docGrp . ':' . $tag;
3236
3246
  $lcTag = lc $tag;
3237
3247
  }
3238
- my $et = $self;
3248
+ my ($et, $fileTags) = ($self, $foundTags);
3239
3249
  if ($tag =~ s/(\bfile\d+)://i) {
3240
- $et = $$self{ALT_EXIFTOOL}{ucfirst lc $1} or $et=$self, $tag = 'no_alt_file';
3250
+ $et = $$self{ALT_EXIFTOOL}{ucfirst lc $1};
3251
+ if ($et) {
3252
+ $fileTags = $$et{FoundTags};
3253
+ } else {
3254
+ $et = $self;
3255
+ $tag = 'no_alt_file';
3256
+ }
3241
3257
  }
3242
3258
  if ($lcTag eq 'all') {
3243
3259
  $val = 1; # always some tag available
@@ -3248,11 +3264,11 @@ sub InsertTagValues($$$;$$$)
3248
3264
  ($group, $tag) = ($1, $2);
3249
3265
  if (lc $tag eq 'all') {
3250
3266
  # see if any tag from the specified group exists
3251
- my $match = $et->GroupMatches($group, $foundTags);
3267
+ my $match = $et->GroupMatches($group, $fileTags);
3252
3268
  $val = $match ? 1 : 0;
3253
3269
  } else {
3254
3270
  # find the specified tag
3255
- my @matches = grep /^$tag(\s|$)/i, @$foundTags;
3271
+ my @matches = grep /^$tag(\s|$)/i, @$fileTags;
3256
3272
  @matches = $et->GroupMatches($group, \@matches);
3257
3273
  foreach $tg (@matches) {
3258
3274
  if (defined $val and $tg =~ / \((\d+)\)$/) {
@@ -3272,7 +3288,7 @@ sub InsertTagValues($$$;$$$)
3272
3288
  $val = $et->GetValue($tag, $type);
3273
3289
  unless (defined $val) {
3274
3290
  # check for tag name with different case
3275
- ($tg) = grep /^$tag$/i, @$foundTags;
3291
+ ($tg) = grep /^$tag$/i, @$fileTags;
3276
3292
  if (defined $tg) {
3277
3293
  $val = $et->GetValue($tg, $type);
3278
3294
  $tag = $tg;
@@ -3923,7 +3939,7 @@ sub RemoveNewValuesForGroup($$)
3923
3939
  my $wgrp = $$nvHash{WriteGroup};
3924
3940
  # use group1 if write group is not specific
3925
3941
  $wgrp = $grp1 if $wgrp eq $grp0;
3926
- if (grep /^($grp0|$wgrp)$/i, @groups) {
3942
+ if ($grp0 eq '*' or $wgrp eq '*' or grep /^($grp0|$wgrp)$/i, @groups) {
3927
3943
  $out and print $out "Removed new value for $wgrp:$$tagInfo{Name}\n";
3928
3944
  # remove from linked list
3929
3945
  $self->RemoveNewValueHash($nvHash, $tagInfo);
@@ -4176,6 +4192,7 @@ sub WriteDirectory($$$;$)
4176
4192
  $out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
4177
4193
  # set directory name from default group0 name if not done already
4178
4194
  my $dirName = $$dirInfo{DirName};
4195
+ my $parent = $$dirInfo{Parent} || '';
4179
4196
  my $dataPt = $$dirInfo{DataPt};
4180
4197
  my $grp0 = $$tagTablePtr{GROUPS}{0};
4181
4198
  $dirName or $dirName = $$dirInfo{DirName} = $grp0;
@@ -4183,14 +4200,19 @@ sub WriteDirectory($$$;$)
4183
4200
  my $delGroup = $$self{DEL_GROUP};
4184
4201
  # delete entire directory if specified
4185
4202
  my $grp1 = $dirName;
4186
- $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1}) unless $permanentDir{$grp0};
4203
+ $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1});
4204
+ if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
4205
+ undef $delFlag;
4206
+ }
4187
4207
  # (never delete an entire QuickTime group)
4188
4208
  if ($delFlag) {
4189
4209
  if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
4190
4210
  $self->IsRawType() and
4191
4211
  # allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
4192
4212
  (not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
4193
- $$dirInfo{TagInfo}{Permanent}))
4213
+ $$dirInfo{TagInfo}{Permanent}) and
4214
+ # allow MakerNotes to be deleted from ExifIFD of CR3 file
4215
+ not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
4194
4216
  {
4195
4217
  $self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
4196
4218
  undef $grp1;
@@ -4226,7 +4248,6 @@ sub WriteDirectory($$$;$)
4226
4248
  if ($delFlag == 2 and $right) {
4227
4249
  # also check grandparent because some routines create 2 levels in 1
4228
4250
  my $right2 = $$self{ADD_DIRS}{$right} || '';
4229
- my $parent = $$dirInfo{Parent};
4230
4251
  if (not $parent or $parent eq $right or $parent eq $right2) {
4231
4252
  # prevent duplicate directories from being recreated at the same path
4232
4253
  my $path = join '-', @{$$self{PATH}}, $dirName;
@@ -4284,10 +4305,27 @@ sub WriteDirectory($$$;$)
4284
4305
  last unless $self->IsOverwriting($nvHash, $dataPt ? $$dataPt : '');
4285
4306
  my $verb = 'Writing';
4286
4307
  my $newVal = $self->GetNewValue($nvHash);
4287
- unless (defined $newVal and length $newVal) {
4308
+ if (defined $newVal and length $newVal) {
4309
+ # hack to add back TIFF header when writing MakerNoteCanon to CMT3 in CR3 images
4310
+ if ($$tagInfo{Name} eq 'MakerNoteCanon') {
4311
+ require Image::ExifTool::Canon;
4312
+ if ($tagInfo eq $Image::ExifTool::Canon::uuid{CMT3}) {
4313
+ my $hdr;
4314
+ if (substr($newVal, 0, 1) eq "\0") {
4315
+ $hdr = "MM\0\x2a" . pack('N', 8);
4316
+ } else {
4317
+ $hdr = "II\x2a\0" . pack('V', 8);
4318
+ }
4319
+ $newVal = $hdr . $newVal;
4320
+ }
4321
+ }
4322
+ } else {
4288
4323
  return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
4289
4324
  # don't allow MakerNotes to be removed from RAW files
4290
- if ($blockName eq 'MakerNotes' and $rawType{$$self{FileType}}) {
4325
+ if ($blockName eq 'MakerNotes' and $self->IsRawType() and
4326
+ # but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
4327
+ not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
4328
+ {
4291
4329
  $self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
4292
4330
  return undef;
4293
4331
  }
@@ -4637,9 +4675,18 @@ sub DumpUnknownTrailer($$)
4637
4675
  # account for preview/MPF image trailer
4638
4676
  my $prePos = $$self{VALUE}{PreviewImageStart} || $$self{PreviewImageStart};
4639
4677
  my $preLen = $$self{VALUE}{PreviewImageLength} || $$self{PreviewImageLength};
4678
+ my $hidPos = $$self{VALUE}{HiddenDataOffset};
4679
+ my $hidLen = $$self{VALUE}{HiddenDataLength};
4640
4680
  my $tag = 'PreviewImage';
4641
4681
  my $mpImageNum = 0;
4642
4682
  my (%image, $lastOne);
4683
+ # add HiddenData to list of known trailer blocks
4684
+ if ($hidPos and $hidLen) {
4685
+ # call ReadHiddenData to validate hidden data and fix offset if necessary
4686
+ require Image::ExifTool::Sony;
4687
+ my $datPt = Image::ExifTool::Sony::ReadHiddenData($self, $hidPos, $hidLen);
4688
+ $image{$hidPos} = ['HiddenData', $hidLen] if $datPt;
4689
+ }
4643
4690
  for (;;) {
4644
4691
  # add to Preview block list if valid and in the trailer
4645
4692
  $image{$prePos} = [$tag, $preLen] if $prePos and $preLen and $prePos+$preLen > $pos;
@@ -5754,13 +5801,16 @@ sub WriteJPEG($$)
5754
5801
  }
5755
5802
  }
5756
5803
  # switch to buffered output if required
5757
- if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) {
5804
+ if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer} or $$self{HiddenData}) and
5805
+ not $oldOutfile)
5806
+ {
5758
5807
  $writeBuffer = '';
5759
5808
  $oldOutfile = $outfile;
5760
5809
  $outfile = \$writeBuffer;
5761
5810
  # account for segment, EXIF and TIFF headers
5762
5811
  $$self{PREVIEW_INFO}{Fixup}{Start} += 18 if $$self{PREVIEW_INFO};
5763
5812
  $$self{LeicaTrailer}{Fixup}{Start} += 18 if $$self{LeicaTrailer};
5813
+ $$self{HiddenData}{Fixup}{Start} += 18 if $$self{HiddenData};
5764
5814
  }
5765
5815
  # write as multi-segment
5766
5816
  my $n = WriteMultiSegment($outfile, 0xe1, $exifAPP1hdr, \$buff, 'EXIF');
@@ -5906,7 +5956,9 @@ sub WriteJPEG($$)
5906
5956
  my $delPreview = $$self{DEL_PREVIEW};
5907
5957
  $trailInfo = IdentifyTrailer($raf) unless $$delGroup{Trailer};
5908
5958
  my $nvTrail = $self->GetNewValueHash($Image::ExifTool::Extra{Trailer});
5909
- unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail) {
5959
+ unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail or
5960
+ $$self{HiddenData})
5961
+ {
5910
5962
  # blindly copy the rest of the file
5911
5963
  while ($raf->Read($buff, 65536)) {
5912
5964
  Write($outfile, $buff) or $err = 1, last;
@@ -5936,7 +5988,7 @@ sub WriteJPEG($$)
5936
5988
  $endedWithFF = substr($buff, 65535, 1) eq "\xff" ? 1 : 0;
5937
5989
  }
5938
5990
  # remember position of last data copied
5939
- $endPos = $raf->Tell() - length($buff);
5991
+ $endPos = $$self{TrailerStart} = $raf->Tell() - length($buff);
5940
5992
  # write new trailer if specified
5941
5993
  if ($nvTrail) {
5942
5994
  # access new value directly to avoid copying a potentially very large data block
@@ -5950,6 +6002,34 @@ sub WriteJPEG($$)
5950
6002
  }
5951
6003
  last; # all done
5952
6004
  }
6005
+ # copy HiddenData if necessary
6006
+ if ($$self{HiddenData}) {
6007
+ my $pad;
6008
+ my $hd = $$self{HiddenData};
6009
+ my $hdOff = $$hd{Offset} + $$hd{Base};
6010
+ require Image::ExifTool::Sony;
6011
+ # read HiddenData, updating $hdOff with actual offset if necessary
6012
+ my $dataPt = Image::ExifTool::Sony::ReadHiddenData($self, $hdOff, $$hd{Size});
6013
+ if ($dataPt) {
6014
+ # preserve padding to avoid invalidating MPF pointers (yuk!)
6015
+ my $padLen = $hdOff - $endPos;
6016
+ unless ($padLen >= 0 and $raf->Seek($endPos,0) and $raf->Read($pad,$padLen)==$padLen) {
6017
+ $self->Error('Error reading HiddenData padding',1);
6018
+ $pad = '';
6019
+ }
6020
+ $endPos += length($pad) + length($$dataPt); # update end position
6021
+ } else {
6022
+ $$dataPt = $pad = '';
6023
+ }
6024
+ my $fixup = $$self{HiddenData}{Fixup};
6025
+ # set MakerNote pointer and size (subtract 10 for segment and EXIF headers)
6026
+ $fixup->SetMarkerPointers($outfile, 'HiddenData', length($$outfile) + length($pad) - 10);
6027
+ # clean up and write the buffered data
6028
+ $outfile = $oldOutfile;
6029
+ undef $oldOutfile;
6030
+ Write($outfile, $writeBuffer, $pad, $$dataPt) or $err = 1;
6031
+ undef $writeBuffer;
6032
+ }
5953
6033
  # rewrite existing trailers
5954
6034
  if ($trailInfo) {
5955
6035
  my $tbuf = '';
@@ -6059,7 +6139,7 @@ sub WriteJPEG($$)
6059
6139
  $delPreview = 1; # remove old preview
6060
6140
  }
6061
6141
  }
6062
- # copy over preview image if necessary
6142
+ # copy over preview image (or other data) if necessary
6063
6143
  unless ($delPreview) {
6064
6144
  my $extra;
6065
6145
  if ($trailInfo) {
@@ -6226,13 +6306,16 @@ sub WriteJPEG($$)
6226
6306
  }
6227
6307
  }
6228
6308
  # switch to buffered output if required
6229
- if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) {
6309
+ if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer} or $$self{HiddenData}) and
6310
+ not $oldOutfile)
6311
+ {
6230
6312
  $writeBuffer = '';
6231
6313
  $oldOutfile = $outfile;
6232
6314
  $outfile = \$writeBuffer;
6233
6315
  # must account for segment, EXIF and TIFF headers
6234
6316
  $$self{PREVIEW_INFO}{Fixup}{Start} += 18 if $$self{PREVIEW_INFO};
6235
6317
  $$self{LeicaTrailer}{Fixup}{Start} += 18 if $$self{LeicaTrailer};
6318
+ $$self{HiddenData}{Fixup}{Start} += 18 if $$self{HiddenData};
6236
6319
  }
6237
6320
  # write as multi-segment
6238
6321
  my $n = WriteMultiSegment($outfile, $marker, $exifAPP1hdr, $segDataPt, 'EXIF');
@@ -7067,7 +7150,7 @@ sub WriteBinaryData($$$)
7067
7150
  $newVal = length($data) if defined $data;
7068
7151
  my $format = $$tagInfo{Format} || $$tagTablePtr{FORMAT} || 'int32u';
7069
7152
  if ($format =~ /^int16/ and $newVal > 0xffff) {
7070
- $self->Error("$$tagInfo{DataTag} is too large (64 kB max. for this file)");
7153
+ $self->Error("$$tagInfo{DataTag} is too large (64 KiB max. for this file)");
7071
7154
  }
7072
7155
  }
7073
7156
  my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $entry);
@@ -7097,14 +7180,24 @@ sub WriteBinaryData($$$)
7097
7180
  # ignore if offset is zero (eg. Ricoh DNG uses this to indicate no preview)
7098
7181
  next unless $offset;
7099
7182
  $fixup->AddFixup($entry, $$tagInfo{DataTag}, $format);
7100
- # handle the preview image now if this is a JPEG file
7101
- next unless $$self{FILE_TYPE} eq 'JPEG' and $$tagInfo{DataTag} and
7102
- $$tagInfo{DataTag} eq 'PreviewImage' and defined $$tagInfo{OffsetPair};
7183
+ next unless $$tagInfo{DataTag} and defined $$tagInfo{OffsetPair};
7103
7184
  # NOTE: here we assume there are no var-sized tags between the
7104
7185
  # OffsetPair tags. If this ever becomes possible we must recalculate
7105
7186
  # $varSize for the OffsetPair tag here!
7106
7187
  $entry = $$tagInfo{OffsetPair} * $increment + $varSize;
7107
7188
  my $size = ReadValue($dataPt, $entry, $format, 1, $dirLen-$entry);
7189
+ next unless defined $size;
7190
+ if ($$tagInfo{DataTag} eq 'HiddenData') {
7191
+ $$self{HiddenData} = {
7192
+ Offset => $offset,
7193
+ Size => $size,
7194
+ Fixup => new Image::ExifTool::Fixup,
7195
+ Base => $$dirInfo{Base},
7196
+ };
7197
+ next;
7198
+ }
7199
+ # handle the preview image now if this is a JPEG file
7200
+ next unless $$tagInfo{DataTag} eq 'PreviewImage' and $$self{FILE_TYPE} eq 'JPEG';
7108
7201
  my $previewInfo = $$self{PREVIEW_INFO};
7109
7202
  $previewInfo or $previewInfo = $$self{PREVIEW_INFO} = {
7110
7203
  Fixup => new Image::ExifTool::Fixup,
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
  require Exporter;
52
52
 
53
- $VERSION = '3.60';
53
+ $VERSION = '3.61';
54
54
  @ISA = qw(Exporter);
55
55
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
56
56
 
@@ -201,6 +201,8 @@ my %xmpNS = (
201
201
  nine => 'http://ns.nikon.com/nine/1.0/',
202
202
  hdr_metadata => 'http://ns.adobe.com/hdr-metadata/1.0/',
203
203
  hdrgm => 'http://ns.adobe.com/hdr-gain-map/1.0/',
204
+ # Note: Not included due to namespace prefix conflict with Device:Container
205
+ # Container => 'http://ns.google.com/photos/1.0/container/',
204
206
  );
205
207
 
206
208
  # build reverse namespace lookup
@@ -479,7 +481,7 @@ my %sCorrRangeMask = (
479
481
  LuminanceDepthSampleInfo => { },
480
482
  );
481
483
  # new LR2 crs structures (PH)
482
- my %sCorrectionMask;
484
+ my %sCorrectionMask; # (must define this before assigning because it is self-referential)
483
485
  %sCorrectionMask = (
484
486
  STRUCT_NAME => 'CorrectionMask',
485
487
  NAMESPACE => 'crs',
@@ -919,6 +921,11 @@ my %sRangeMask = (
919
921
  Name => 'hdrgm',
920
922
  SubDirectory => { TagTable => 'Image::ExifTool::XMP::hdrgm' },
921
923
  },
924
+ # Note: Note included due to namespace prefix conflict with Device:Container
925
+ # Container => {
926
+ # Name => 'Container',
927
+ # SubDirectory => { TagTable => 'Image::ExifTool::XMP::Container' },
928
+ # },
922
929
  );
923
930
 
924
931
  # hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm)
@@ -1699,6 +1706,8 @@ my %sPantryItem = (
1699
1706
  ToneCurvePV2012Red => { List => 'Seq' },
1700
1707
  ToneCurvePV2012Green => { List => 'Seq' },
1701
1708
  ToneCurvePV2012Blue => { List => 'Seq' },
1709
+ Highlights2012 => { },
1710
+ Shadows2012 => { },
1702
1711
  },
1703
1712
  },
1704
1713
  }
@@ -1760,6 +1769,62 @@ my %sPantryItem = (
1760
1769
  SDRShadows => { Writable => 'real' },
1761
1770
  SDRWhites => { Writable => 'real' },
1762
1771
  SDRBlend => { Writable => 'real' },
1772
+ # new for ACR 16 (ref forum15305)
1773
+ LensBlur => {
1774
+ Struct => {
1775
+ STRUCT_NAME => 'LensBlur',
1776
+ NAMESPACE => 'crs',
1777
+ # (Note: all the following 'real' values could be limited to 'integer')
1778
+ Active => { Writable => 'boolean' },
1779
+ BlurAmount => { FlatName => 'Amount', Writable => 'real' },
1780
+ BokehAspect => { Writable => 'real' },
1781
+ BokehRotation => { Writable => 'real' },
1782
+ BokehShape => { Writable => 'real' },
1783
+ BokehShapeDetail => { Writable => 'real' },
1784
+ CatEyeAmount => { Writable => 'real' },
1785
+ CatEyeScale => { Writable => 'real' },
1786
+ FocalRange => { }, # (eg. "-48 32 64 144")
1787
+ FocalRangeSource => { Writable => 'real' },
1788
+ HighlightsBoost => { Writable => 'real' },
1789
+ HighlightsThreshold => { Writable => 'real' },
1790
+ SampledArea => { }, # (eg. "0.500000 0.500000 0.500000 0.500000")
1791
+ SampledRange => { }, # (eg. "0 0")
1792
+ SphericalAberration => { Writable => 'real' },
1793
+ SubjectRange => { }, # (eg. "0 57");
1794
+ Version => { },
1795
+ },
1796
+ },
1797
+ DepthMapInfo => {
1798
+ Struct => {
1799
+ STRUCT_NAME => 'DepthMapInfo',
1800
+ NAMESPACE => 'crs',
1801
+ BaseHighlightGuideInputDigest => { },
1802
+ BaseHighlightGuideTable => { },
1803
+ BaseHighlightGuideVersion => { },
1804
+ BaseLayeredDepthInputDigest => { },
1805
+ BaseLayeredDepthTable => { },
1806
+ BaseLayeredDepthVersion => { },
1807
+ BaseRawDepthInputDigest => { },
1808
+ BaseRawDepthTable => { },
1809
+ BaseRawDepthVersion => { },
1810
+ DepthSource => { },
1811
+ },
1812
+ },
1813
+ DepthBasedCorrections => {
1814
+ List => 'Seq',
1815
+ FlatName => 'DepthBasedCorr',
1816
+ Struct => {
1817
+ STRUCT_NAME => 'DepthBasedCorr',
1818
+ NAMESPACE => 'crs',
1819
+ CorrectionActive => { Writable => 'boolean' },
1820
+ CorrectionAmount => { Writable => 'real' },
1821
+ CorrectionMasks => { FlatName => 'Mask', List => 'Seq', Struct => \%sCorrectionMask },
1822
+ CorrectionSyncID => { },
1823
+ LocalCorrectedDepth => { Writable => 'real' },
1824
+ LocalCurveRefineSaturation => { Writable => 'real' },
1825
+ What => { },
1826
+ },
1827
+ },
1763
1828
  );
1764
1829
 
1765
1830
  # Tiff namespace properties (tiff)
@@ -1873,6 +1873,10 @@ my %sSubVersion = (
1873
1873
  ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
1874
1874
  ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
1875
1875
  },
1876
+ HdrPlusMakernote => {
1877
+ ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
1878
+ ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
1879
+ },
1876
1880
  );
1877
1881
 
1878
1882
  # Google creations namespace (ref PH)
@@ -2037,6 +2041,37 @@ my %sSubVersion = (
2037
2041
  },
2038
2042
  );
2039
2043
 
2044
+ # Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
2045
+ # NOTE: Not included because these namespace prefixes conflict with Google's depth-map Device tags!
2046
+ # (see ../pics/GooglePixel8Pro.jpg sample image)
2047
+ # %Image::ExifTool::XMP::Container = (
2048
+ # %xmpTableDefaults,
2049
+ # GROUPS => { 1 => 'XMP-Container', 2 => 'Image' },
2050
+ # NAMESPACE => 'Container',
2051
+ # NOTES => 'Google Container namespace.',
2052
+ # Directory => {
2053
+ # Name => 'ContainerDirectory',
2054
+ # FlatName => 'Directory',
2055
+ # List => 'Seq',
2056
+ # Struct => {
2057
+ # STRUCT_NAME => 'Directory',
2058
+ # Item => {
2059
+ # Namespace => 'Container',
2060
+ # Struct => {
2061
+ # STRUCT_NAME => 'Item',
2062
+ # NAMESPACE => { Item => 'http://ns.google.com/photos/1.0/container/item/'},
2063
+ # Mime => { },
2064
+ # Semantic => { },
2065
+ # Length => { Writable => 'integer' },
2066
+ # Label => { },
2067
+ # Padding => { Writable => 'integer' },
2068
+ # URI => { },
2069
+ # },
2070
+ # },
2071
+ # },
2072
+ # },
2073
+ # );
2074
+
2040
2075
  # Getty Images namespace (ref PH)
2041
2076
  %Image::ExifTool::XMP::GettyImages = (
2042
2077
  %xmpTableDefaults,