exiftool_vendored 11.57.0 → 11.60.0

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

Potentially problematic release.


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

@@ -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',