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