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.
- checksums.yaml +4 -4
- data/bin/Changes +42 -0
- data/bin/MANIFEST +2 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +2 -2
- data/bin/lib/Image/ExifTool.pm +16 -10
- data/bin/lib/Image/ExifTool.pod +5 -22
- data/bin/lib/Image/ExifTool/Canon.pm +8 -2
- data/bin/lib/Image/ExifTool/Exif.pm +3 -2
- data/bin/lib/Image/ExifTool/JPEG.pm +8 -1
- data/bin/lib/Image/ExifTool/Lang/ru.pm +642 -630
- data/bin/lib/Image/ExifTool/Nikon.pm +50 -21
- data/bin/lib/Image/ExifTool/PNG.pm +128 -56
- data/bin/lib/Image/ExifTool/QuickTime.pm +3 -3
- data/bin/lib/Image/ExifTool/README +3 -0
- data/bin/lib/Image/ExifTool/RIFF.pm +2 -2
- data/bin/lib/Image/ExifTool/Sigma.pm +4 -1
- data/bin/lib/Image/ExifTool/Sony.pm +13 -5
- data/bin/lib/Image/ExifTool/TagLookup.pm +2 -2
- data/bin/lib/Image/ExifTool/TagNames.pod +12 -9
- data/bin/lib/Image/ExifTool/WritePNG.pl +0 -15
- data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -1
- data/bin/lib/Image/ExifTool/Writer.pl +17 -0
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -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.
|
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,
|
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,
|
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
|
-
|
4470
|
-
|
4471
|
-
|
4472
|
-
|
4473
|
-
|
4474
|
-
|
4475
|
-
|
4476
|
-
|
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
|
-
|
6145
|
-
|
6146
|
-
|
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
|
-
#
|
6171
|
+
# (may not be reliable and is found elsewhere)
|
6156
6172
|
#0x2ea2 => {
|
6157
6173
|
# Name => 'Rotation',
|
6158
|
-
# Condition => '$$self{Model} =~ /\bD500\b/
|
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 => '
|
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.
|
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
|
-
|
834
|
-
|
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
|
-
|
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
|
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
|
-
|
1261
|
-
$
|
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
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
$
|
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
|
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
|
-
|
1315
|
-
|
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
|
-
|
1356
|
-
|
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
|
-
|
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)
|
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
|
-
|
1382
|
-
|
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
|
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',
|