exiftool-vendored.exe 12.67.0 → 12.70.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 (42) hide show
  1. package/bin/exiftool_files/Changes +79 -10
  2. package/bin/exiftool_files/README +7 -7
  3. package/bin/exiftool_files/exiftool.pl +37 -31
  4. package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +18 -2
  5. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +87 -16
  6. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +3 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/DNG.pm +25 -2
  8. package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +54 -6
  9. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +175 -14
  10. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +158 -20
  11. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
  12. package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +16 -11
  13. package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +70 -7
  14. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +1 -1
  15. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +1 -1
  16. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  17. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +2 -2
  18. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +82 -22
  19. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +7 -1
  20. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +3 -1
  21. package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +22 -9
  22. package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +6 -1
  23. package/bin/exiftool_files/lib/Image/ExifTool/PhotoMechanic.pm +2 -1
  24. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +92 -55
  25. package/bin/exiftool_files/lib/Image/ExifTool/README +14 -5
  26. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +60 -10
  27. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +152 -46
  28. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6955 -6713
  29. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +878 -334
  30. package/bin/exiftool_files/lib/Image/ExifTool/Text.pm +4 -5
  31. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +23 -20
  32. package/bin/exiftool_files/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
  33. package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +14 -4
  34. package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +3 -0
  35. package/bin/exiftool_files/lib/Image/ExifTool/WriteRIFF.pl +31 -6
  36. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +40 -14
  37. package/bin/exiftool_files/lib/Image/ExifTool/XISF.pm +185 -0
  38. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +67 -2
  39. package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +35 -0
  40. package/bin/exiftool_files/lib/Image/ExifTool.pm +92 -45
  41. package/bin/exiftool_files/lib/Image/ExifTool.pod +14 -8
  42. package/package.json +3 -3
@@ -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};
@@ -96,6 +96,8 @@ my %ctboID = (
96
96
  "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac" => 1, # XMP
97
97
  "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16" => 2, # PreviewImage
98
98
  # ID 3 is used for 'mdat' atom (not a uuid)
99
+ # (haven't seen ID 4 yet)
100
+ "\x57\x66\xb8\x29\xbb\x6a\x47\xc5\xbc\xfb\x8b\x9f\x22\x60\xd0\x6d" => 5, # something to do with burst-roll image
99
101
  );
100
102
 
101
103
  # mark UserData tags that don't have ItemList counterparts as Preferred
@@ -1054,6 +1056,7 @@ sub WriteQuickTime($$$)
1054
1056
  Parent => $dirName,
1055
1057
  DirName => $subName,
1056
1058
  Name => $$tagInfo{Name},
1059
+ TagInfo => $tagInfo,
1057
1060
  DirID => $tag,
1058
1061
  DataPt => \$buff,
1059
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);
@@ -0,0 +1,185 @@
1
+ #------------------------------------------------------------------------------
2
+ # File: XISF.pm
3
+ #
4
+ # Description: Read Extensible Image Serialization Format metadata
5
+ #
6
+ # Revisions: 2023-10-10 - P. Harvey Created
7
+ #
8
+ # References: 1) https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html
9
+ #------------------------------------------------------------------------------
10
+
11
+ package Image::ExifTool::XISF;
12
+
13
+ use strict;
14
+ use vars qw($VERSION);
15
+ use Image::ExifTool qw(:DataAccess :Utils);
16
+ use Image::ExifTool::XMP;
17
+
18
+ $VERSION = '1.00';
19
+
20
+ # XISF tags (ref 1)
21
+ %Image::ExifTool::XISF::Main = (
22
+ GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
23
+ VARS => { LONG_TAGS => 1 },
24
+ NOTES => q{
25
+ This table lists some standard Extensible Image Serialization Format (XISF)
26
+ tags, but ExifTool will extract any other tags found. See
27
+ L<https://pixinsight.com/xisf/> for the specification.
28
+ },
29
+ ImageGeometry => { },
30
+ ImageSampleFormat => { },
31
+ ImageBounds => { },
32
+ ImageImageType => { Name => 'ImageType' },
33
+ ImageColorSpace => { Name => 'ColorSpace' },
34
+ ImageLocation => { },
35
+ ImageResolutionHorizontal => 'XResolution',
36
+ ImageResolutionVertical => 'YResolution',
37
+ ImageResolutionUnit => 'ResolutionUnit',
38
+ ImageICCProfile => {
39
+ Name => 'ICC_Profile',
40
+ ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
41
+ Binary => 1,
42
+ },
43
+ ImageICCProfileLocation => { Name => 'ICCProfileLocation' },
44
+ ImagePixelStorage => { },
45
+ ImageOffset => { Name => 'ImagePixelOffset' },
46
+ ImageOrientation => { Name => 'Orientation' },
47
+ ImageId => { Name => 'ImageID' },
48
+ ImageUuid => { Name => 'UUID' },
49
+ ImageData => { Binary => 1 },
50
+ 'CreationTime' => {
51
+ Name => 'CreateDate',
52
+ Shift => 'Time',
53
+ Groups => { 2 => 'Time' },
54
+ ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
55
+ PrintConv => '$self->ConvertDateTime($val)',
56
+ },
57
+ CreatorApplication => { },
58
+ Abstract => { },
59
+ AccessRights => { },
60
+ Authors => { Groups => { 2 => 'Author' } },
61
+ BibliographicReferences => { },
62
+ BriefDescription => { },
63
+ CompressionLevel => { },
64
+ CompressionCodecs => { },
65
+ Contributors => { Groups => { 2 => 'Author' } },
66
+ Copyright => { Groups => { 2 => 'Author' } },
67
+ CreatorModule => { },
68
+ CreatorOS => { },
69
+ Description => { },
70
+ Keywords => { },
71
+ Languages => { },
72
+ License => { },
73
+ OriginalCreationTime => {
74
+ Name => 'DateTimeOriginal',
75
+ Description => 'Date/Time Original',
76
+ Shift => 'Time',
77
+ Groups => { 2 => 'Time' },
78
+ ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
79
+ PrintConv => '$self->ConvertDateTime($val)',
80
+ },
81
+ RelatedResources => { },
82
+ Title => { },
83
+ );
84
+
85
+ #------------------------------------------------------------------------------
86
+ # Handle properties in XISF metadata structures
87
+ # Inputs: 0) attribute list ref, 1) attr hash ref,
88
+ # 2) property name ref, 3) property value ref
89
+ # Returns: true if value was changed
90
+ sub HandleXISFAttrs($$$$)
91
+ {
92
+ my ($attrList, $attrs, $prop, $valPt) = @_;
93
+ return 0 unless defined $$attrs{id};
94
+ my ($changed, $a);
95
+ # use "id" as the tag name, "value" as the value, and ignore "type"
96
+ $$prop = $$attrs{id};
97
+ $$prop =~ s/^XISF://; # remove XISF namespace
98
+ if (defined $$attrs{value}) {
99
+ $$valPt = $$attrs{value};
100
+ $changed = 1;
101
+ }
102
+ my @attrs = @$attrList;
103
+ @$attrList = ( );
104
+ foreach $a (@attrs) {
105
+ if ($a eq 'id' or $a eq 'value' or $a eq 'type') {
106
+ delete $$attrs{$a};
107
+ } else {
108
+ push @$attrList, $a;
109
+ }
110
+ }
111
+ return $changed;
112
+ }
113
+
114
+ #------------------------------------------------------------------------------
115
+ # Read information in a XISF document
116
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref
117
+ # Returns: 1 on success, 0 if this wasn't a valid XISF file
118
+ sub ProcessXISF($$)
119
+ {
120
+ my ($et, $dirInfo) = @_;
121
+ my $raf = $$dirInfo{RAF};
122
+ my $buff;
123
+
124
+ return 0 unless $raf->Read($buff, 16) == 16 and $buff =~ /^XISF0100/;
125
+ $et->SetFileType();
126
+ SetByteOrder('II');
127
+ my $tagTablePtr = GetTagTable('Image::ExifTool::XISF::Main');
128
+ my $hdrLen = Get32u(\$buff, 8);
129
+ $raf->Read($buff, $hdrLen) == $hdrLen or $et->Warn('Error reading XISF header'), return 1;
130
+ $et->FoundTag(XML => $buff);
131
+ my %dirInfo = (
132
+ DataPt => \$buff,
133
+ IgnoreProp => { xisf => 1, Metadata => 1, Property => 1 },
134
+ XMPParseOpts => { AttrProc => \&HandleXISFAttrs },
135
+ );
136
+ Image::ExifTool::XMP::ProcessXMP($et, \%dirInfo, $tagTablePtr);
137
+ my $geo = $$et{VALUE}{ImageGeometry};
138
+ if ($geo) {
139
+ my ($w, $h, $n) = split /:/, $geo;
140
+ $et->FoundTag(ImageWidth => $w);
141
+ $et->FoundTag(ImageHeight => $h);
142
+ $et->FoundTag(NumPlanes => $n);
143
+ }
144
+ return 1;
145
+ }
146
+
147
+ 1; # end
148
+
149
+ __END__
150
+
151
+ =head1 NAME
152
+
153
+ Image::ExifTool::XISF - Read Extensible Image Serialization Format metadata
154
+
155
+ =head1 SYNOPSIS
156
+
157
+ This module is used by Image::ExifTool
158
+
159
+ =head1 DESCRIPTION
160
+
161
+ This module contains definitions required by Image::ExifTool to read meta
162
+ information from XISF (Extensible Image Serialization Format) images.
163
+
164
+ =head1 AUTHOR
165
+
166
+ Copyright 2003-2023, Phil Harvey (philharvey66 at gmail.com)
167
+
168
+ This library is free software; you can redistribute it and/or modify it
169
+ under the same terms as Perl itself.
170
+
171
+ =head1 REFERENCES
172
+
173
+ =over 4
174
+
175
+ =item L<https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html>
176
+
177
+ =back
178
+
179
+ =head1 SEE ALSO
180
+
181
+ L<Image::ExifTool::TagNames/XISF Tags>,
182
+ L<Image::ExifTool(3pm)|Image::ExifTool>
183
+
184
+ =cut
185
+