exiftool_vendored 11.57.0 → 11.60.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.
@@ -60,7 +60,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
60
60
  use Image::ExifTool::Exif;
61
61
  use Image::ExifTool::GPS;
62
62
 
63
- $VERSION = '3.67';
63
+ $VERSION = '3.68';
64
64
 
65
65
  sub LensIDConv($$$);
66
66
  sub ProcessNikonAVI($$$);
@@ -1719,7 +1719,7 @@ my %binaryDataAttrs = (
1719
1719
  TagTable => 'Image::ExifTool::Nikon::ShotInfoD500',
1720
1720
  DecryptStart => 4,
1721
1721
  DecryptLen => 0x2c24 + 12,
1722
- DecryptMore => 'Get32u(\$data, 0xa0) + 12',
1722
+ DecryptMore => 'Get32u(\$data, 0xa8) + 0x2ea5 - 0x2c90',
1723
1723
  ByteOrder => 'LittleEndian',
1724
1724
  },
1725
1725
  },
@@ -1730,7 +1730,7 @@ my %binaryDataAttrs = (
1730
1730
  TagTable => 'Image::ExifTool::Nikon::ShotInfoD500',
1731
1731
  DecryptStart => 4,
1732
1732
  DecryptLen => 0x2cb2 + 4,
1733
- DecryptMore => 'Get32u(\$data, 0xa0) + 12',
1733
+ DecryptMore => 'Get32u(\$data, 0xa8) + 0x2ea5 - 0x2c90',
1734
1734
  ByteOrder => 'LittleEndian',
1735
1735
  },
1736
1736
  },
@@ -4466,16 +4466,18 @@ my %nikonFocalConversions = (
4466
4466
  RawConv => '$$self{NewLensData} = 1 unless $val =~ /^.\0+$/s; undef',
4467
4467
  Hidden => 1,
4468
4468
  },
4469
- #0x30 => {
4470
- # Name => 'LensID', ? (NC)
4471
- # Condition => '$$self{NewLensData}',
4472
- # Format => 'int16u',
4473
- # PrintConv => {
4474
- # 1 => 'Nikkor Z 24-70mm f/4 S',
4475
- # 4 => 'Nikkor Z 35mm f/1.8 S',
4476
- # 9 => 'Nikkor Z 50mm f/1.8 S',
4477
- # },
4478
- #},
4469
+ 0x30 => {
4470
+ Name => 'LensID',
4471
+ Condition => '$$self{NewLensData}',
4472
+ Format => 'int16u',
4473
+ PrintConv => {
4474
+ 1 => 'Nikkor Z 24-70mm f/4 S',
4475
+ 2 => 'Nikkor Z 14-30mm f/4 S',
4476
+ 4 => 'Nikkor Z 35mm f/1.8 S',
4477
+ 9 => 'Nikkor Z 50mm f/1.8 S',
4478
+ 13 => 'Nikkor Z 24-70mm f/2.8 S',
4479
+ },
4480
+ },
4479
4481
  0x36 => {
4480
4482
  Name => 'MaxAperture',
4481
4483
  Condition => '$$self{NewLensData}',
@@ -5685,8 +5687,8 @@ my %nikonFocalConversions = (
5685
5687
  WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted,
5686
5688
  CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
5687
5689
  VARS => { ID_LABEL => 'Index' },
5688
- DATAMEMBER => [ 0x04, 0x10, 0x14, 0x2c, 0x50, 0x58, 0xa0, 0xb0,
5689
- 0x07b0, 0x086c, 0x0e7c, 0x0eea, 0x2c23 ],
5690
+ DATAMEMBER => [ 0x04, 0x10, 0x14, 0x2c, 0x50, 0x58, 0xa0, 0xa8, 0xb0,
5691
+ 0x07b0, 0x086c, 0x0e7c, 0x0eea, 0x2c23, 0x2c8f ],
5690
5692
  IS_SUBDIR => [ 0x0eeb ],
5691
5693
  WRITABLE => 1,
5692
5694
  FIRST_ENTRY => 0,
@@ -5752,6 +5754,14 @@ my %nikonFocalConversions = (
5752
5754
  Hidden => 1,
5753
5755
  RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', # (ignore if 0)
5754
5756
  },
5757
+ 0xa8 => {
5758
+ Name => 'OtherOffset',
5759
+ DataMember => 'OtherOffset',
5760
+ Format => 'int32u',
5761
+ Writable => 0,
5762
+ Hidden => 1,
5763
+ RawConv => '$$self{OtherOffset} = $val || 0x10000000; undef', # (ignore if 0)
5764
+ },
5755
5765
  #
5756
5766
  # Tag ID's below are the offsets for a D500 JPEG image, but these offsets change
5757
5767
  # for various image types according to the offset table above
@@ -6141,9 +6151,15 @@ my %nikonFocalConversions = (
6141
6151
  PrintConv => 'sprintf("%.1f", $val)',
6142
6152
  PrintConvInv => '$val',
6143
6153
  },
6144
- # note: DecryptLen currently set to OrientationOffset + 12
6145
-
6146
- # (not sure about how this moves around)
6154
+ ### 0x2c90 - OtherInfo start (D500 firmware 1.20d)
6155
+ 0x2c8f => {
6156
+ Name => 'Hook7',
6157
+ Hidden => 1,
6158
+ RawConv => 'undef',
6159
+ # account for variable location of OtherInfo data
6160
+ Hook => '$varSize = $$self{OtherOffset} - 0x2c90',
6161
+ },
6162
+ # (needs testing)
6147
6163
  #0x2cb2 => {
6148
6164
  # Name => 'ExtendedPhotoShootingBanks',
6149
6165
  # Mask => 0x01,
@@ -6152,10 +6168,10 @@ my %nikonFocalConversions = (
6152
6168
  # 1 => 'Off',
6153
6169
  # },
6154
6170
  #},
6155
- # don't decode this because it is duplicate information and moves around with firmware versions
6171
+ # (may not be reliable and is found elsewhere)
6156
6172
  #0x2ea2 => {
6157
6173
  # Name => 'Rotation',
6158
- # Condition => '$$self{Model} =~ /\bD500\b/ and $$self{FirmwareVersion} =~ /^1.1/',
6174
+ # Condition => '$$self{Model} =~ /\bD500\b/',
6159
6175
  # Notes => 'D500 firmware 1.1x',
6160
6176
  # Mask => 0x30,
6161
6177
  # PrintConv => {
@@ -6165,6 +6181,19 @@ my %nikonFocalConversions = (
6165
6181
  # 3 => 'Rotate 180',
6166
6182
  # },
6167
6183
  #},
6184
+ 0x2ea4 => {
6185
+ Name => 'NikonMeteringMode',
6186
+ Condition => '$$self{Model} =~ /\bD500\b/', # (didn't seem to work for D5, but I need more samples)
6187
+ Notes => 'D500 only',
6188
+ Mask => 0x03,
6189
+ PrintConv => {
6190
+ 0 => 'Matrix',
6191
+ 1 => 'Center',
6192
+ 2 => 'Spot',
6193
+ 3 => 'Highlight'
6194
+ },
6195
+ },
6196
+ # note: DecryptLen currently set to OtherOffset + 0x2ea5 - 0x2c90
6168
6197
  );
6169
6198
  # shot information for the D610 firmware 1.00 (encrypted) - ref PH
6170
6199
  %Image::ExifTool::Nikon::ShotInfoD610 = (
@@ -6370,7 +6399,7 @@ my %nikonFocalConversions = (
6370
6399
  },
6371
6400
  },
6372
6401
  0x175e => {
6373
- Name => 'D810MeteringMode',
6402
+ Name => 'NikonMeteringMode',
6374
6403
  Mask => 0x03,
6375
6404
  PrintConv => {
6376
6405
  0 => 'Matrix',
@@ -19,6 +19,14 @@
19
19
  # decompress then decode the ASCII/hex profile information before
20
20
  # you can edit it, then you have to ASCII/hex-encode, recompress
21
21
  # and calculate a CRC before you can write it out again. gaaaak.
22
+ #
23
+ # Although XMP is allowed after the IDAT chunk according to the
24
+ # PNG specifiction, some apps (Apple Spotlight and Preview for
25
+ # OS X 10.8.5 and Adobe Photoshop CC 14.0) ignore it unless it
26
+ # comes before IDAT. As of version 11.58, ExifTool uses a 2-pass
27
+ # writing algorithm to allow it to be compatible with XMP after
28
+ # IDAT while writing it before IDAT. (PNG and EXIF are still
29
+ # written after IDAT.)
22
30
  #------------------------------------------------------------------------------
23
31
 
24
32
  package Image::ExifTool::PNG;
@@ -27,7 +35,7 @@ use strict;
27
35
  use vars qw($VERSION $AUTOLOAD %stdCase);
28
36
  use Image::ExifTool qw(:DataAccess :Utils);
29
37
 
30
- $VERSION = '1.47';
38
+ $VERSION = '1.50';
31
39
 
32
40
  sub ProcessPNG_tEXt($$$);
33
41
  sub ProcessPNG_iTXt($$$);
@@ -502,9 +510,7 @@ my %unreg = ( Notes => 'unregistered' );
502
510
  XMP specification, and is where ExifTool will add a new XMP chunk if the
503
511
  image didn't already contain XMP
504
512
  },
505
- SubDirectory => {
506
- TagTable => 'Image::ExifTool::XMP::Main',
507
- },
513
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
508
514
  },
509
515
  'Raw profile type APP1' => [
510
516
  {
@@ -791,7 +797,7 @@ sub FoundPNG($$$$;$$$$)
791
797
  my $tagName = $$tagInfo{Name};
792
798
  my $processed;
793
799
  if ($$tagInfo{SubDirectory}) {
794
- if ($$et{OPTIONS}{Validate} and $$tagInfo{NonStandard}) {
800
+ if ($$et{OPTIONS}{Validate} and $$tagInfo{NonStandard} and not $wasCompressed) {
795
801
  $et->Warn("Non-standard $$tagInfo{NonStandard} in PNG $tag chunk", 1);
796
802
  }
797
803
  my $subdir = $$tagInfo{SubDirectory};
@@ -830,23 +836,11 @@ sub FoundPNG($$$$;$$$$)
830
836
  return 1 unless $$et{EDIT_DIRS}{$dirName};
831
837
  $$outBuff = $et->WriteDirectory(\%subdirInfo, $subTable);
832
838
  if ($tagName eq 'XMP' and $$outBuff) {
833
- if ($$et{FoundIDAT} and $$et{DEL_GROUP}{XMP}) {
834
- $et->VPrint(0,' Deleting XMP');
835
- $$outBuff = '';
836
- } else {
837
- # make sure the XMP is marked as read-only
838
- Image::ExifTool::XMP::ValidateXMP($outBuff,'r');
839
- }
839
+ # make sure the XMP is marked as read-only
840
+ Image::ExifTool::XMP::ValidateXMP($outBuff,'r');
840
841
  }
841
842
  DoneDir($et, $dirName, $outBuff, $$tagInfo{NonStandard});
842
843
  } else {
843
- # issue warning for standard XMP after IDAT (PNGEarlyXMP option)
844
- if ($tagName eq 'XMP' and not $$tagInfo{NonStandard} and
845
- $$et{FoundIDAT} and $$et{FoundIDAT} == 2)
846
- {
847
- $et->Warn('XMP found after PNG IDAT');
848
- $$et{FoundIDAT} = 1;
849
- }
850
844
  $processed = $et->ProcessDirectory(\%subdirInfo, $subTable, $processProc);
851
845
  }
852
846
  $compressed = 1; # pretend this is compressed since it is binary data
@@ -1148,6 +1142,7 @@ sub ProcessPNG_tEXt($$$)
1148
1142
  my ($et, $dirInfo, $tagTablePtr) = @_;
1149
1143
  my ($tag, $val) = split /\0/, ${$$dirInfo{DataPt}}, 2;
1150
1144
  my $outBuff = $$dirInfo{OutBuff};
1145
+ $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $$et{OPTIONS}{Verbose};
1151
1146
  return FoundPNG($et, $tagTablePtr, $tag, $val, undef, $outBuff, 'Latin');
1152
1147
  }
1153
1148
 
@@ -1166,6 +1161,7 @@ sub ProcessPNG_iTXt($$$)
1166
1161
  # set compressed flag so we will decompress it in FoundPNG()
1167
1162
  $compressed and $compressed = 2 + $meth;
1168
1163
  my $outBuff = $$dirInfo{OutBuff};
1164
+ $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $$et{OPTIONS}{Verbose};
1169
1165
  return FoundPNG($et, $tagTablePtr, $tag, $val, $compressed, $outBuff, 'UTF8', $lang);
1170
1166
  }
1171
1167
 
@@ -1234,14 +1230,14 @@ sub ProcessPNG($$)
1234
1230
  my $datChunk = '';
1235
1231
  my $datCount = 0;
1236
1232
  my $datBytes = 0;
1237
- my ($sig, $err);
1233
+ my ($sig, $err, $xmp, $foundXMP, $foundIDAT, $editingXMP, $deletingXMP);
1238
1234
 
1239
1235
  # check to be sure this is a valid PNG/MNG/JNG image
1240
1236
  return 0 unless $raf->Read($sig,8) == 8 and $pngLookup{$sig};
1241
1237
 
1242
- $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode
1238
+ # disable buffering in FastScan mode
1239
+ $$raf{NoBuffer} = 1 if $et->Options('FastScan') and not $outfile;
1243
1240
 
1244
- my $earlyXMP = $et->Options('PNGEarlyXMP');
1245
1241
  if ($outfile) {
1246
1242
  delete $$et{TextChunkType};
1247
1243
  Write($outfile, $sig) or $err = 1 if $outfile;
@@ -1251,16 +1247,13 @@ sub ProcessPNG($$)
1251
1247
  \%Image::ExifTool::PNG::TextualData);
1252
1248
  # NOTE: PNGDoneTag and PNGDoneDir are used to keep track of metadata added
1253
1249
  # before the PNG IEND chunk is encountered. Currently this is implemented
1254
- # only for XMP (written before IDAT with the PNGEarlyXMP option), but
1255
- # may be implemented in the future for other types - PH
1250
+ # only for XMP, but may be implemented in the future for other types - PH
1256
1251
  $$et{PNGDoneTag} = { };
1257
1252
  $$et{PNGDoneDir} = { };
1258
1253
  # initialize with same directories, with PNG tags taking priority
1259
1254
  $et->InitWriteDirs(\%pngMap,'PNG');
1260
- # write XMP before IDAT if we would delete it later anyway
1261
- $earlyXMP = 1 if $$et{DEL_GROUP}{XMP};
1262
- } elsif ($$et{OPTIONS}{Validate}) {
1263
- $earlyXMP = 1; # warn about XMP after IDAT when validating
1255
+ $editingXMP = $$et{EDIT_DIRS}{XMP};
1256
+ $deletingXMP = $$et{DEL_GROUP}{XMP};
1264
1257
  }
1265
1258
  my ($fileType, $hdrChunk, $endChunk) = @{$pngLookup{$sig}};
1266
1259
  $et->SetFileType($fileType); # set the FileType tag
@@ -1271,9 +1264,34 @@ sub ProcessPNG($$)
1271
1264
  $mngTablePtr = GetTagTable('Image::ExifTool::MNG::Main');
1272
1265
  }
1273
1266
  my $verbose = $et->Options('Verbose');
1267
+ my $validate = $et->Options('Validate');
1274
1268
  my $out = $et->Options('TextOut');
1275
1269
  my ($hbuf, $dbuf, $cbuf, $wasHdr, $wasEnd);
1276
1270
 
1271
+ # scan ahead for XMP if we are editing it
1272
+ if ($outfile and $editingXMP and not $deletingXMP) {
1273
+ while ($raf->Read($hbuf,8) == 8) {
1274
+ my ($len, $chunk) = unpack('Na4',$hbuf);
1275
+ last if $len > 0x7fffffff;
1276
+ if ($chunk ne 'iTXt' or $len < 22) {
1277
+ $raf->Seek($len + 4, 1) or last;
1278
+ next;
1279
+ }
1280
+ $raf->Read($dbuf, 18) == 18 or last;
1281
+ unless ($dbuf eq "XML:com.adobe.xmp\0") { # is this XMP?
1282
+ $raf->Seek($len - 18 + 4, 1) or last;
1283
+ next;
1284
+ };
1285
+ $raf->Read($dbuf, $len - 18) == $len - 18 or last;
1286
+ my ($compressed, $meth) = unpack('CC', $dbuf);
1287
+ $compressed and $et->Error('XMP is compressed'), last;
1288
+ my ($lang, $trans);
1289
+ ($lang, $trans, $xmp) = split /\0/, substr($dbuf, 2), 3;
1290
+ last;
1291
+ }
1292
+ $raf->Seek(8,0) or $et->Error('Error seeking in file'), return -1;
1293
+ }
1294
+
1277
1295
  # process the PNG/MNG/JNG chunks
1278
1296
  undef $noCompressLib;
1279
1297
  for (;;) {
@@ -1298,25 +1316,52 @@ sub ProcessPNG($$)
1298
1316
  my $s = $datCount > 1 ? 's' : '';
1299
1317
  print $out "$fileType $datChunk ($datCount chunk$s, total $datBytes bytes)\n";
1300
1318
  $datCount = $datBytes = 0;
1301
- $datChunk = '';
1302
1319
  }
1303
- if ($chunk =~ /^(IDAT|JDAT|JDAA)$/) {
1304
- $datChunk = $chunk;
1305
- $datCount++;
1306
- $datBytes += $len;
1320
+ }
1321
+ unless ($wasHdr) {
1322
+ if ($chunk eq $hdrChunk) {
1323
+ $wasHdr = 1;
1324
+ } elsif ($hdrChunk eq 'IHDR' and $chunk eq 'CgBI') {
1325
+ $et->Warn('Non-standard PNG image (Apple iPhone format)');
1326
+ } else {
1327
+ $et->Warn("$fileType image did not start with $hdrChunk");
1328
+ last;
1307
1329
  }
1308
1330
  }
1331
+ if ($chunk =~ /^(IDAT|JDAT|JDAA)$/) {
1332
+ $datChunk = $chunk;
1333
+ $datCount++;
1334
+ $datBytes += $len;
1335
+ } else {
1336
+ $datChunk = '';
1337
+ }
1309
1338
  if ($outfile) {
1339
+ # add XMP before any data chunk, or before IEND/MEND if no data
1340
+ if ($datChunk or $chunk eq $endChunk) {
1341
+ if ($xmp) {
1342
+ # rewrite existing XMP
1343
+ my $tbl = GetTagTable('Image::ExifTool::PNG::TextualData');
1344
+ my $buf;
1345
+ FoundPNG($et, $tbl, 'XML:com.adobe.xmp', $xmp, 0, \$buf, 'UTF8', '');
1346
+ my $outBuff = defined $buf ? \$buf : \$xmp;
1347
+ if (length $$outBuff) {
1348
+ my $hdr = pack('Na4', length($$outBuff), 'iTXt');
1349
+ my $crc = CalculateCRC(\$hdr, undef, 4);
1350
+ $crc = CalculateCRC($outBuff, $crc);
1351
+ Write($outfile, $hdr, $$outBuff, pack('N',$crc)) or $err = 1;
1352
+ }
1353
+ undef $xmp; # done with this XMP
1354
+ } elsif ($$et{ADD_DIRS}{XMP}) {
1355
+ # add new XMP if necessary
1356
+ AddChunks($et, $outfile, 'XMP') or $err = 1;
1357
+ }
1358
+ }
1310
1359
  if ($chunk eq $endChunk) {
1311
- # add any new chunks immediately before the IEND/MEND chunk
1360
+ # add other new chunks immediately before the IEND/MEND chunk
1312
1361
  AddChunks($et, $outfile) or $err = 1;
1313
1362
  } elsif ($chunk eq 'PLTE' or $chunk eq 'IDAT') {
1314
- if ($chunk eq 'IDAT') {
1315
- # add XMP before IDAT if specified
1316
- AddChunks($et, $outfile, 'XMP') or $err = 1 if $earlyXMP;
1317
- # pHYs comes before IDAT
1318
- AddChunks($et, $outfile, 'PNG-pHYs') or $err = 1;
1319
- }
1363
+ # pHYs must come before IDAT
1364
+ AddChunks($et, $outfile, 'PNG-pHYs') or $err = 1 if $chunk eq 'IDAT';
1320
1365
  # iCCP chunk must come before PLTE and IDAT
1321
1366
  # (ignore errors -- will add later as text profile if this fails)
1322
1367
  Add_iCCP($et, $outfile);
@@ -1352,34 +1397,61 @@ sub ProcessPNG($$)
1352
1397
  }
1353
1398
  next;
1354
1399
  }
1355
- # set FoundIDAT flag: 1=after IDAT, 2=after IDAT and warn about late XMP
1356
- $$et{FoundIDAT} = $earlyXMP ? 2 : 1 if $chunk eq 'IDAT';
1400
+ if ($datChunk) {
1401
+ $foundIDAT = 1 if $chunk eq 'IDAT'; # set flag indicating IDAT was found
1402
+ # skip over data chunks if possible
1403
+ unless ($verbose or $validate or $outfile) {
1404
+ $raf->Seek($len + 4, 1) or $et->Warn('Seek error'), last;
1405
+ next;
1406
+ }
1407
+ }
1357
1408
  # read chunk data and CRC
1358
1409
  unless ($raf->Read($dbuf,$len)==$len and $raf->Read($cbuf, 4)==4) {
1359
1410
  $et->Warn("Corrupted $fileType image") unless $wasEnd;
1360
1411
  last;
1361
1412
  }
1362
- unless ($wasHdr) {
1363
- if ($chunk eq $hdrChunk) {
1364
- $wasHdr = 1;
1365
- } elsif ($hdrChunk eq 'IHDR' and $chunk eq 'CgBI') {
1366
- $et->Warn('Non-standard PNG image (Apple iPhone format)');
1367
- } else {
1368
- $et->Warn("$fileType image did not start with $hdrChunk");
1369
- last;
1370
- }
1371
- }
1372
- if ($verbose) {
1413
+ if ($verbose or $validate or $outfile) {
1373
1414
  # check CRC when in verbose mode (since we don't care about speed)
1374
1415
  my $crc = CalculateCRC(\$hbuf, undef, 4);
1375
1416
  $crc = CalculateCRC(\$dbuf, $crc);
1376
- $crc == unpack('N',$cbuf) or $et->Warn("Bad CRC for $chunk chunk") unless $wasEnd;
1417
+ unless ($crc == unpack('N',$cbuf)) {
1418
+ my $msg = "Bad CRC for $chunk chunk";
1419
+ $outfile ? $et->Error($msg, 1) : $et->Warn($msg);
1420
+ }
1377
1421
  if ($datChunk) {
1378
1422
  Write($outfile, $hbuf, $dbuf, $cbuf) or $err = 1 if $outfile;
1379
1423
  next;
1380
1424
  }
1381
- print $out "$fileType $chunk ($len bytes):\n";
1382
- $et->VerboseDump(\$dbuf, Addr => $raf->Tell() - $len - 4) if $verbose > 2;
1425
+ if ($verbose) {
1426
+ print $out "$fileType $chunk ($len bytes):\n";
1427
+ $et->VerboseDump(\$dbuf, Addr => $raf->Tell() - $len - 4) if $verbose > 2;
1428
+ }
1429
+ }
1430
+ if ($chunk eq 'iTXt' and $dbuf =~ /^XML:com.adobe.xmp\0/) {
1431
+ $foundXMP = ($foundXMP || 0) + 1;
1432
+ if ($outfile and $editingXMP) {
1433
+ # handle this standard XMP iTXt chunk
1434
+ my $editNow;
1435
+ if ($deletingXMP) {
1436
+ # just fall through
1437
+ } elsif ($foundXMP > 1) {
1438
+ $et->Error('Multiple XMP chunks', 1) if $foundXMP == 2;
1439
+ } elsif ($foundIDAT) {
1440
+ $et->WarnOnce('XMP found after PNG IDAT. Fixed.');
1441
+ } elsif ($xmp) {
1442
+ # the XMP is already before IDAT, so edit it now
1443
+ $editNow = 1;
1444
+ undef $xmp; # (don't write again later)
1445
+ }
1446
+ unless ($editNow) {
1447
+ ++$$et{CHANGED};
1448
+ print $out " Deleting XMP\n" if $verbose;
1449
+ next;
1450
+ }
1451
+ } else {
1452
+ $et->WarnOnce('XMP found after PNG IDAT') if $foundIDAT;
1453
+ $et->Warn('Multiple XMP chunks') if $foundXMP == 2;
1454
+ }
1383
1455
  }
1384
1456
  # translate case of chunk name if necessary
1385
1457
  if (not $$tagTablePtr{$chunk}) {
@@ -1337,8 +1337,8 @@ my %eeBox = (
1337
1337
  L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are
1338
1338
  preferred over these, so to create the tag when a same-named ItemList tag
1339
1339
  exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet>
1340
- on the command line), or the PREFERRED level must be changed via the config
1341
- file.
1340
+ on the command line), or the PREFERRED level must be changed via
1341
+ L<the config file|../config.html#PREF>.
1342
1342
  },
1343
1343
  "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } },
1344
1344
  "\xa9day" => {
@@ -5568,7 +5568,7 @@ my %eeBox = (
5568
5568
  preferred when writing, so to create a tag when a same-named tag exists in
5569
5569
  either of these tables, either the "Keys" location must be specified (eg.
5570
5570
  C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be
5571
- changed via the config file.
5571
+ changed via L<the config file|../config.html#PREF>.
5572
5572
  },
5573
5573
  version => 'Version',
5574
5574
  album => 'Album',