exiftool_vendored 12.68.0 → 12.70.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +63 -15
  3. data/bin/META.json +1 -1
  4. data/bin/META.yml +1 -1
  5. data/bin/README +2 -2
  6. data/bin/exiftool +13 -13
  7. data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
  8. data/bin/lib/Image/ExifTool/Canon.pm +68 -16
  9. data/bin/lib/Image/ExifTool/DJI.pm +3 -2
  10. data/bin/lib/Image/ExifTool/DNG.pm +25 -2
  11. data/bin/lib/Image/ExifTool/EXE.pm +54 -6
  12. data/bin/lib/Image/ExifTool/Exif.pm +175 -14
  13. data/bin/lib/Image/ExifTool/FujiFilm.pm +142 -20
  14. data/bin/lib/Image/ExifTool/GIF.pm +5 -1
  15. data/bin/lib/Image/ExifTool/ID3.pm +70 -7
  16. data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
  17. data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
  18. data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  19. data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
  20. data/bin/lib/Image/ExifTool/Nikon.pm +58 -18
  21. data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
  22. data/bin/lib/Image/ExifTool/PNG.pm +8 -13
  23. data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
  24. data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
  25. data/bin/lib/Image/ExifTool/QuickTime.pm +32 -5
  26. data/bin/lib/Image/ExifTool/README +14 -5
  27. data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
  28. data/bin/lib/Image/ExifTool/Sony.pm +95 -34
  29. data/bin/lib/Image/ExifTool/TagLookup.pm +6937 -6714
  30. data/bin/lib/Image/ExifTool/TagNames.pod +812 -332
  31. data/bin/lib/Image/ExifTool/Text.pm +4 -5
  32. data/bin/lib/Image/ExifTool/Validate.pm +23 -20
  33. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  34. data/bin/lib/Image/ExifTool/WriteExif.pl +14 -4
  35. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  36. data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  37. data/bin/lib/Image/ExifTool/Writer.pl +40 -14
  38. data/bin/lib/Image/ExifTool/XMP.pm +67 -2
  39. data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
  40. data/bin/lib/Image/ExifTool.pm +79 -40
  41. data/bin/lib/Image/ExifTool.pod +9 -3
  42. data/bin/perl-Image-ExifTool.spec +1 -1
  43. data/lib/exiftool_vendored/version.rb +1 -1
  44. metadata +2 -2
@@ -25,11 +25,10 @@ $VERSION = '1.04';
25
25
  Although basic text files contain no metadata, the following tags are
26
26
  determined from a simple analysis of the data in TXT and CSV files.
27
27
  Statistics are generated only for 8-bit encodings, but the L<FastScan|../ExifTool.html#FastScan> (-fast)
28
- option may be used to limit processing to the first 64 kB in which case some
29
- tags are not produced. To avoid long processing delays, ExifTool will issue
30
- a minor warning and process only the first 64 kB of any file larger than 20
31
- MB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m)
32
- option is used.
28
+ option may be used to limit processing to the first 64 KiB in which case
29
+ some tags are not produced. To avoid long processing delays, ExifTool will
30
+ issue a minor warning and process only the first 64 KiB of any file larger
31
+ than 20 MiB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m) option is used.
33
32
  },
34
33
  MIMEEncoding => { Groups => { 2 => 'Other' } },
35
34
  Newlines => {
@@ -17,7 +17,7 @@ package Image::ExifTool::Validate;
17
17
  use strict;
18
18
  use vars qw($VERSION %exifSpec);
19
19
 
20
- $VERSION = '1.21';
20
+ $VERSION = '1.23';
21
21
 
22
22
  use Image::ExifTool qw(:Utils);
23
23
  use Image::ExifTool::Exif;
@@ -86,7 +86,7 @@ my %verCheck = (
86
86
  GPS => { GPSVersionID => \%gpsVer },
87
87
  );
88
88
 
89
- # tags standard in various RAW file formats
89
+ # tags standard in various RAW file formats or IFD's
90
90
  my %otherSpec = (
91
91
  CR2 => { 0xc5d8 => 1, 0xc5d9 => 1, 0xc5e0 => 1, 0xc640 => 1, 0xc6dc => 1, 0xc6dd => 1 },
92
92
  NEF => { 0x9216 => 1, 0x9217 => 1 },
@@ -103,6 +103,7 @@ my %otherSpec = (
103
103
  SRW => { 0xa010 => 1, 0xa011 => 1, 0xa101 => 1, 0xa102 => 1 },
104
104
  NRW => { 0x9216 => 1, 0x9217 => 1 },
105
105
  X3F => { 0xa500 => 1 },
106
+ CameraIFD => { All => 1 }, # (exists in JPG and DNG of Leica Q3 images)
106
107
  );
107
108
 
108
109
  # standard format for tags (not necessary for exifSpec or GPS tags where Writable is defined)
@@ -142,20 +143,22 @@ my %stdFormat = (
142
143
  # GeoTiff tags:
143
144
  0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string',
144
145
  0x8480 => 'double', 0x85d8 => 'double', 0x87b0 => 'double',
145
- # DNG tags:
146
- 0xc615 => '(string|int8u)', 0xc6d3 => '',
147
- 0xc61a => '(int16u|int32u|rational64u)', 0xc6f4 => '(string|int8u)',
148
- 0xc61d => 'int(16|32)u', 0xc6f6 => '(string|int8u)',
149
- 0xc61f => '(int16u|int32u|rational64u)', 0xc6f8 => '(string|int8u)',
150
- 0xc620 => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
151
- 0xc628 => '(int16u|rational64u)', 0xc716 => '(string|int8u)',
152
- 0xc634 => 'int8u', 0xc717 => '(string|int8u)',
153
- 0xc640 => '', 0xc718 => '(string|int8u)',
154
- 0xc660 => '', 0xc71e => 'int(16|32)u',
155
- 0xc68b => '(string|int8u)', 0xc71f => 'int(16|32)u',
156
- 0xc68d => 'int(16|32)u', 0xc791 => 'int(16|32)u',
157
- 0xc68e => 'int(16|32)u', 0xc792 => 'int(16|32)u',
158
- 0xc6d2 => '', 0xc793 => '(int16u|int32u|rational64u)',
146
+ # DNG tags: (use '' for non-DNG tags in the range 0xc612-0xcd48)
147
+ 0xc615 => '(string|int8u)', 0xc6f4 => '(string|int8u)',
148
+ 0xc61a => '(int16u|int32u|rational64u)', 0xc6f6 => '(string|int8u)',
149
+ 0xc61d => 'int(16|32)u', 0xc6f8 => '(string|int8u)',
150
+ 0xc61f => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
151
+ 0xc620 => '(int16u|int32u|rational64u)', 0xc716 => '(string|int8u)',
152
+ 0xc628 => '(int16u|rational64u)', 0xc717 => '(string|int8u)',
153
+ 0xc634 => 'int8u', 0xc718 => '(string|int8u)',
154
+ 0xc640 => '', 0xc71e => 'int(16|32)u',
155
+ 0xc660 => '', 0xc71f => 'int(16|32)u',
156
+ 0xc68b => '(string|int8u)', 0xc791 => 'int(16|32)u',
157
+ 0xc68d => 'int(16|32)u', 0xc792 => 'int(16|32)u',
158
+ 0xc68e => 'int(16|32)u', 0xc793 => '(int16u|int32u|rational64u)',
159
+ 0xc6d2 => '', 0xcd43 => 'int(16|32)u',
160
+ 0xc6d3 => '', 0xcd48 => '(string|int8u)',
161
+
159
162
  # Exif 3.0 spec
160
163
  0x10e => 'string|utf8', 0xa430 => 'string|utf8', 0xa439 => 'string|utf8',
161
164
  0x10f => 'string|utf8', 0xa433 => 'string|utf8', 0xa43a => 'string|utf8',
@@ -430,7 +433,7 @@ sub ValidateExif($$$$$$$$)
430
433
  my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD};
431
434
  if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and
432
435
  ($exifSpec{$tag} or $$stdFmt{$tag} or
433
- ($tag >= 0xc612 and $tag <= 0xc7b5 and not defined $$stdFmt{$tag}))) or # (DNG tags)
436
+ ($tag >= 0xc612 and $tag <= 0xcd48 and not defined $$stdFmt{$tag}))) or # (DNG tags)
434
437
  $$tagTablePtr{SHORT_NAME} eq 'GPS::Main')
435
438
  {
436
439
  my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP};
@@ -456,8 +459,8 @@ sub ValidateExif($$$$$$$$)
456
459
  } elsif (not $otherSpec{$$et{FileType}} or
457
460
  (not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
458
461
  {
459
- if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$tagInfo{Unknown}) {
460
- $et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1);
462
+ if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$ti{Unknown}) {
463
+ $et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1) unless $otherSpec{$ifd};
461
464
  }
462
465
  }
463
466
  # change expected count from read Format to Writable size
@@ -478,7 +481,7 @@ sub ValidateExif($$$$$$$$)
478
481
  } elsif (not $otherSpec{$$et{FileType}} or
479
482
  (not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
480
483
  {
481
- $et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1);
484
+ $et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1) unless $otherSpec{$ifd};
482
485
  }
483
486
  }
484
487
 
@@ -142,7 +142,6 @@ sub SaveMakerNotes($)
142
142
  }
143
143
  # save position of maker notes for pointer fixups
144
144
  $fixup->{Shift} += length($makerNotes);
145
- $$et{MAKER_NOTE_FIXUP} = $fixup;
146
145
  $$et{MAKER_NOTE_BYTE_ORDER} = GetByteOrder();
147
146
  # add value data
148
147
  $makerNotes .= $makerInfo->{ValBuff};
@@ -150,7 +149,8 @@ sub SaveMakerNotes($)
150
149
  my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Exif::Main');
151
150
  my $tagInfo = $et->GetTagInfo($tagTablePtr, 0x927c, \$makerNotes);
152
151
  # save the MakerNotes
153
- $et->FoundTag($tagInfo, $makerNotes);
152
+ my $key = $et->FoundTag($tagInfo, $makerNotes);
153
+ $$et{TAG_EXTRA}{$key}{Fixup} = $fixup;
154
154
  # save the garbage collection some work later
155
155
  delete $makerInfo->{Entries};
156
156
  delete $makerInfo->{ValBuff};
@@ -930,8 +930,16 @@ Entry: for (;;) {
930
930
  }
931
931
  }
932
932
  unless ($success) {
933
- return undef if $et->Error("Error reading value for $name entry $index", $inMakerNotes);
934
- ++$index; $oldID = $newID; next; # drop this tag
933
+ my $wrn = sprintf("Error reading value for $name entry $index, ID 0x%.4x", $oldID);
934
+ my $truncOK;
935
+ if ($oldInfo and not $$oldInfo{Unknown}) {
936
+ $wrn .= " $$oldInfo{Name}";
937
+ $truncOK = $$oldInfo{TruncateOK};
938
+ }
939
+ return undef if $et->Error($wrn, $inMakerNotes || $truncOK);
940
+ unless ($truncOK) {
941
+ ++$index; $oldID = $newID; next; # drop this tag
942
+ }
935
943
  }
936
944
  } elsif (not $invalidPreview) {
937
945
  return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
@@ -1094,6 +1102,8 @@ Entry: for (;;) {
1094
1102
  # add, edit or delete this tag
1095
1103
  shift @newTags; # remove from list
1096
1104
  my $curInfo = $set{$newID};
1105
+ # don't allow MakerNotes to be added to ExifIFD of CR3 file
1106
+ next if $newID == 0x927c and $isNew > 0 and $$et{FileType} eq 'CR3';
1097
1107
  unless ($curInfo or $$addDirs{$newID}) {
1098
1108
  # we can finally get the specific tagInfo reference for this tag
1099
1109
  # (because we can now evaluate the Condition statement since all
@@ -1429,8 +1439,8 @@ NoOverwrite: next if $isNew > 0;
1429
1439
  if ($$et{DEL_GROUP}{MakerNotes} and
1430
1440
  ($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
1431
1441
  {
1432
- if ($et->IsRawType()) {
1433
- $et->WarnOnce("Can't delete MakerNotes from $$et{FileType}",1);
1442
+ if ($et->IsRawType() and not ($et->IsRawType() == 2 and $dirName eq 'ExifIFD')) {
1443
+ $et->Warn("Can't delete MakerNotes from $$et{FileType}",1);
1434
1444
  } else {
1435
1445
  if ($isNew <= 0) {
1436
1446
  ++$$et{CHANGED};
@@ -1056,6 +1056,7 @@ sub WriteQuickTime($$$)
1056
1056
  Parent => $dirName,
1057
1057
  DirName => $subName,
1058
1058
  Name => $$tagInfo{Name},
1059
+ TagInfo => $tagInfo,
1059
1060
  DirID => $tag,
1060
1061
  DataPt => \$buff,
1061
1062
  DataLen => $size,
@@ -19,6 +19,8 @@ my %webpMap = (
19
19
  'XMP ' => 'RIFF', # (the RIFF chunk name is 'XMP ')
20
20
  EXIF => 'RIFF',
21
21
  ICCP => 'RIFF',
22
+ C2PA => 'RIFF',
23
+ JUMBF => 'C2PA',
22
24
  XMP => 'XMP ',
23
25
  IFD0 => 'EXIF',
24
26
  IFD1 => 'IFD0',
@@ -66,6 +68,7 @@ sub WriteRIFF($$)
66
68
  $et->InitWriteDirs(\%webpMap);
67
69
  my $addDirs = $$et{ADD_DIRS};
68
70
  my $editDirs = $$et{EDIT_DIRS};
71
+ $$addDirs{IFD0} = 'EXIF' if $$addDirs{EXIF}; # set flag to add IFD0 if adding EXIF (don't ask)
69
72
  my ($createVP8X, $deleteVP8X);
70
73
 
71
74
  # write header
@@ -142,6 +145,17 @@ sub WriteRIFF($$)
142
145
  }
143
146
  # RIFF chunks are padded to an even number of bytes
144
147
  my $len2 = $len + ($len & 0x01);
148
+ # handle incorrect "XMP\0" chunk ID written by Google software
149
+ if ($tag eq "XMP\0") {
150
+ if ($$et{DEL_GROUP}{XMP}) {
151
+ # just ignore this chunk if deleting XMP
152
+ $raf->Seek($len2, 1) or $et->Error('Seek error'), last;
153
+ ++$$et{CHANGED};
154
+ next;
155
+ } else {
156
+ $et->Warn('Incorrect XMP tag ID',1) if $pass;
157
+ }
158
+ }
145
159
  # edit/add/delete necessary metadata chunks (EXIF must come before XMP)
146
160
  if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
147
161
  my $handledTag;
@@ -156,13 +170,12 @@ sub WriteRIFF($$)
156
170
  #
157
171
  # add/edit/delete EXIF/XMP/ICCP (note: EXIF must come before XMP, and ICCP is written elsewhere)
158
172
  #
159
- my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
160
- my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
173
+ my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'JUMBF' );
174
+ my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'Jpeg2000' );
161
175
  my $dir;
162
- foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
176
+ foreach $dir ('EXIF', 'XMP ', 'ICCP', 'C2PA' ) {
163
177
  next unless $tag eq $dir or ($$addDirs{$dir} and
164
178
  ($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
165
- delete $$addDirs{$dir}; # (don't try to add again)
166
179
  my $start;
167
180
  unless ($pass) {
168
181
  # write the EXIF and save the result for the next pass
@@ -170,8 +183,15 @@ sub WriteRIFF($$)
170
183
  if ($tag eq 'EXIF') {
171
184
  # (only need to set directory $start for EXIF)
172
185
  if ($buff =~ /^Exif\0\0/) {
173
- $et->Warn('Improper EXIF header') unless $pass;
174
- $start = 6;
186
+ if ($$et{DEL_GROUP}{EXIF}) {
187
+ # remove incorrect header if rewriting anyway
188
+ $buff = substr($buff, 6);
189
+ $len -= 6;
190
+ $len2 -= 6;
191
+ } else {
192
+ $et->Warn('Improper EXIF header',1) unless $pass;
193
+ $start = 6;
194
+ }
175
195
  } else {
176
196
  $start = 0;
177
197
  }
@@ -189,11 +209,16 @@ sub WriteRIFF($$)
189
209
  Parent => $dir,
190
210
  DirName => $dirName{$dir},
191
211
  );
212
+ # must pass the TagInfo to enable deletion of C2PA information
213
+ if (ref $Image::ExifTool::RIFF::Main{$dir} eq 'HASH') {
214
+ $dirInfo{TagInfo} = $Image::ExifTool::RIFF::Main{$dir};
215
+ }
192
216
  my $tagTablePtr = GetTagTable("Image::ExifTool::$tblName{$dir}::Main");
193
217
  # (override writeProc for EXIF because it has the TIFF header)
194
218
  my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
195
219
  $dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
196
220
  }
221
+ delete $$addDirs{$dir}; # (don't try to add again)
197
222
  if (defined $dirDat{$dir}) {
198
223
  if ($dir eq $tag) {
199
224
  $handledTag = 1; # set flag indicating we edited this tag
@@ -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
@@ -1002,10 +1003,8 @@ TAG: foreach $tagInfo (@matchingTags) {
1002
1003
  $$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
1003
1004
  $$nvHash{WantGroup} = $wantGroup;
1004
1005
  $$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
- }
1006
+ # save maker note fixup information if writing maker notes
1007
+ $$nvHash{MAKER_NOTE_FIXUP} = $options{Fixup} if $$tagInfo{MakerNotes};
1009
1008
  if ($createOnly) { # create only (never edit)
1010
1009
  # empty item in DelValue list to never edit existing value
1011
1010
  $$nvHash{DelValue} = [ '' ];
@@ -1272,6 +1271,7 @@ sub SetNewValuesFromFile($$;@)
1272
1271
  # +------------------------------------------+
1273
1272
  $srcExifTool->Options(
1274
1273
  Binary => 1,
1274
+ ByteUnit => $$options{ByteUnit},
1275
1275
  Charset => $$options{Charset},
1276
1276
  CharsetEXIF => $$options{CharsetEXIF},
1277
1277
  CharsetFileName => $$options{CharsetFileName},
@@ -1372,8 +1372,8 @@ sub SetNewValuesFromFile($$;@)
1372
1372
  #
1373
1373
  unless (@setTags) {
1374
1374
  # transfer maker note information to this object
1375
- $$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
1376
1375
  $$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
1376
+ my $tagExtra = $$srcExifTool{TAG_EXTRA};
1377
1377
  foreach $tag (@tags) {
1378
1378
  # don't try to set errors or warnings
1379
1379
  next if $tag =~ /^(Error|Warning)\b/;
@@ -1381,10 +1381,13 @@ sub SetNewValuesFromFile($$;@)
1381
1381
  if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
1382
1382
  $$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
1383
1383
  }
1384
+ my $fixup = $$tagExtra{$tag}{Fixup};
1385
+ $opts{Fixup} = $fixup if $fixup;
1384
1386
  # set value for this tag
1385
1387
  my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
1386
1388
  # delete this tag if we couldn't set it
1387
1389
  $n or delete $$info{$tag};
1390
+ delete $opts{Fixup} if $fixup;
1388
1391
  }
1389
1392
  return $info;
1390
1393
  }
@@ -1617,7 +1620,7 @@ SET: foreach $set (@setList) {
1617
1620
  }
1618
1621
  # transfer maker note information if setting this tag
1619
1622
  if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
1620
- $$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
1623
+ $$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
1621
1624
  $$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
1622
1625
  }
1623
1626
  if ($dstTag eq '*') {
@@ -1649,6 +1652,7 @@ SET: foreach $set (@setList) {
1649
1652
  $rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
1650
1653
  $noWarn = 1;
1651
1654
  }
1655
+ delete $$opts{Fixup};
1652
1656
  $rtnInfo{$tag} = $val if $rtn; # tag was set successfully
1653
1657
  }
1654
1658
  }
@@ -4176,6 +4180,7 @@ sub WriteDirectory($$$;$)
4176
4180
  $out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
4177
4181
  # set directory name from default group0 name if not done already
4178
4182
  my $dirName = $$dirInfo{DirName};
4183
+ my $parent = $$dirInfo{Parent} || '';
4179
4184
  my $dataPt = $$dirInfo{DataPt};
4180
4185
  my $grp0 = $$tagTablePtr{GROUPS}{0};
4181
4186
  $dirName or $dirName = $$dirInfo{DirName} = $grp0;
@@ -4183,14 +4188,19 @@ sub WriteDirectory($$$;$)
4183
4188
  my $delGroup = $$self{DEL_GROUP};
4184
4189
  # delete entire directory if specified
4185
4190
  my $grp1 = $dirName;
4186
- $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1}) unless $permanentDir{$grp0};
4191
+ $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1});
4192
+ if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
4193
+ undef $delFlag;
4194
+ }
4187
4195
  # (never delete an entire QuickTime group)
4188
4196
  if ($delFlag) {
4189
4197
  if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
4190
4198
  $self->IsRawType() and
4191
4199
  # allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
4192
4200
  (not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
4193
- $$dirInfo{TagInfo}{Permanent}))
4201
+ $$dirInfo{TagInfo}{Permanent}) and
4202
+ # allow MakerNotes to be deleted from ExifIFD of CR3 file
4203
+ not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
4194
4204
  {
4195
4205
  $self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
4196
4206
  undef $grp1;
@@ -4226,7 +4236,6 @@ sub WriteDirectory($$$;$)
4226
4236
  if ($delFlag == 2 and $right) {
4227
4237
  # also check grandparent because some routines create 2 levels in 1
4228
4238
  my $right2 = $$self{ADD_DIRS}{$right} || '';
4229
- my $parent = $$dirInfo{Parent};
4230
4239
  if (not $parent or $parent eq $right or $parent eq $right2) {
4231
4240
  # prevent duplicate directories from being recreated at the same path
4232
4241
  my $path = join '-', @{$$self{PATH}}, $dirName;
@@ -4284,10 +4293,27 @@ sub WriteDirectory($$$;$)
4284
4293
  last unless $self->IsOverwriting($nvHash, $dataPt ? $$dataPt : '');
4285
4294
  my $verb = 'Writing';
4286
4295
  my $newVal = $self->GetNewValue($nvHash);
4287
- unless (defined $newVal and length $newVal) {
4296
+ if (defined $newVal and length $newVal) {
4297
+ # hack to add back TIFF header when writing MakerNoteCanon to CMT3 in CR3 images
4298
+ if ($$tagInfo{Name} eq 'MakerNoteCanon') {
4299
+ require Image::ExifTool::Canon;
4300
+ if ($tagInfo eq $Image::ExifTool::Canon::uuid{CMT3}) {
4301
+ my $hdr;
4302
+ if (substr($newVal, 0, 1) eq "\0") {
4303
+ $hdr = "MM\0\x2a" . pack('N', 8);
4304
+ } else {
4305
+ $hdr = "II\x2a\0" . pack('V', 8);
4306
+ }
4307
+ $newVal = $hdr . $newVal;
4308
+ }
4309
+ }
4310
+ } else {
4288
4311
  return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
4289
4312
  # don't allow MakerNotes to be removed from RAW files
4290
- if ($blockName eq 'MakerNotes' and $rawType{$$self{FileType}}) {
4313
+ if ($blockName eq 'MakerNotes' and $self->IsRawType() and
4314
+ # but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
4315
+ not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
4316
+ {
4291
4317
  $self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
4292
4318
  return undef;
4293
4319
  }
@@ -7067,7 +7093,7 @@ sub WriteBinaryData($$$)
7067
7093
  $newVal = length($data) if defined $data;
7068
7094
  my $format = $$tagInfo{Format} || $$tagTablePtr{FORMAT} || 'int32u';
7069
7095
  if ($format =~ /^int16/ and $newVal > 0xffff) {
7070
- $self->Error("$$tagInfo{DataTag} is too large (64 kB max. for this file)");
7096
+ $self->Error("$$tagInfo{DataTag} is too large (64 KiB max. for this file)");
7071
7097
  }
7072
7098
  }
7073
7099
  my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $entry);
@@ -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,