exiftool-vendored.pl 12.45.0 → 12.50.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.
- package/bin/Changes +122 -6
- package/bin/MANIFEST +12 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +45 -44
- package/bin/config_files/acdsee.config +2 -1
- package/bin/config_files/frameCount.config +56 -0
- package/bin/config_files/tiff_version.config +1 -1
- package/bin/exiftool +89 -75
- package/bin/lib/Image/ExifTool/Apple.pm +6 -2
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +17 -9
- package/bin/lib/Image/ExifTool/Canon.pm +31 -14
- package/bin/lib/Image/ExifTool/CanonRaw.pm +8 -1
- package/bin/lib/Image/ExifTool/Exif.pm +13 -8
- package/bin/lib/Image/ExifTool/FLAC.pm +17 -3
- package/bin/lib/Image/ExifTool/FlashPix.pm +4 -2
- package/bin/lib/Image/ExifTool/FujiFilm.pm +31 -5
- package/bin/lib/Image/ExifTool/Geotag.pm +1 -1
- package/bin/lib/Image/ExifTool/ICC_Profile.pm +1 -1
- package/bin/lib/Image/ExifTool/ICO.pm +143 -0
- package/bin/lib/Image/ExifTool/ID3.pm +5 -5
- package/bin/lib/Image/ExifTool/IPTC.pm +5 -1
- package/bin/lib/Image/ExifTool/M2TS.pm +98 -8
- package/bin/lib/Image/ExifTool/MIE.pm +9 -3
- package/bin/lib/Image/ExifTool/MISB.pm +494 -0
- package/bin/lib/Image/ExifTool/MakerNotes.pm +3 -1
- package/bin/lib/Image/ExifTool/Nikon.pm +220 -109
- package/bin/lib/Image/ExifTool/NikonSettings.pm +5 -3
- package/bin/lib/Image/ExifTool/Olympus.pm +2 -1
- package/bin/lib/Image/ExifTool/Panasonic.pm +21 -4
- package/bin/lib/Image/ExifTool/PanasonicRaw.pm +12 -5
- package/bin/lib/Image/ExifTool/Pentax.pm +7 -2
- package/bin/lib/Image/ExifTool/Photoshop.pm +29 -3
- package/bin/lib/Image/ExifTool/QuickTime.pm +78 -10
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +76 -5
- package/bin/lib/Image/ExifTool/README +5 -1
- package/bin/lib/Image/ExifTool/RIFF.pm +106 -9
- package/bin/lib/Image/ExifTool/Samsung.pm +2 -2
- package/bin/lib/Image/ExifTool/Sigma.pm +27 -1
- package/bin/lib/Image/ExifTool/SigmaRaw.pm +37 -13
- package/bin/lib/Image/ExifTool/Sony.pm +35 -16
- package/bin/lib/Image/ExifTool/TagInfoXML.pm +3 -1
- package/bin/lib/Image/ExifTool/TagLookup.pm +4700 -4520
- package/bin/lib/Image/ExifTool/TagNames.pod +4796 -4463
- package/bin/lib/Image/ExifTool/Text.pm +3 -4
- package/bin/lib/Image/ExifTool/Torrent.pm +2 -3
- package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +7 -0
- package/bin/lib/Image/ExifTool/WriteExif.pl +19 -1
- package/bin/lib/Image/ExifTool/WriteRIFF.pl +359 -0
- package/bin/lib/Image/ExifTool/Writer.pl +6 -2
- package/bin/lib/Image/ExifTool/XMP.pm +72 -57
- package/bin/lib/Image/ExifTool/XMP2.pl +9 -1
- package/bin/lib/Image/ExifTool.pm +81 -18
- package/bin/lib/Image/ExifTool.pod +64 -60
- package/bin/perl-Image-ExifTool.spec +43 -43
- package/bin/pp_build_exe.args +7 -4
- package/package.json +2 -2
|
@@ -14,9 +14,8 @@ package Image::ExifTool::Text;
|
|
|
14
14
|
use strict;
|
|
15
15
|
use vars qw($VERSION);
|
|
16
16
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
17
|
-
use Image::ExifTool::XMP;
|
|
18
17
|
|
|
19
|
-
$VERSION = '1.
|
|
18
|
+
$VERSION = '1.04';
|
|
20
19
|
|
|
21
20
|
# Text tags
|
|
22
21
|
%Image::ExifTool::Text::Main = (
|
|
@@ -97,7 +96,7 @@ sub ProcessTXT($$)
|
|
|
97
96
|
$nl =~ tr/\0//d; # remove nulls from newline sequence
|
|
98
97
|
$isBOM = 1; # (we don't recognize UTF-16/UTF-32 without one)
|
|
99
98
|
} else {
|
|
100
|
-
$isUTF8 = Image::ExifTool::
|
|
99
|
+
$isUTF8 = Image::ExifTool::IsUTF8($dataPt, 1);
|
|
101
100
|
if ($isUTF8 == 0) {
|
|
102
101
|
$enc = 'us-ascii';
|
|
103
102
|
} elsif ($isUTF8 > 0) {
|
|
@@ -183,7 +182,7 @@ sub ProcessTXT($$)
|
|
|
183
182
|
next if $raf->Tell() < 65536;
|
|
184
183
|
# continue to check encoding after the first 64 kB
|
|
185
184
|
if ($isUTF8 >= 0) { # (if ascii or utf8)
|
|
186
|
-
$isUTF8 = Image::ExifTool::
|
|
185
|
+
$isUTF8 = Image::ExifTool::IsUTF8(\$buff);
|
|
187
186
|
if ($isUTF8 > 0) {
|
|
188
187
|
$enc = 'utf-8';
|
|
189
188
|
} elsif ($isUTF8 < 0) {
|
|
@@ -13,9 +13,8 @@ package Image::ExifTool::Torrent;
|
|
|
13
13
|
use strict;
|
|
14
14
|
use vars qw($VERSION);
|
|
15
15
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
16
|
-
use Image::ExifTool::XMP;
|
|
17
16
|
|
|
18
|
-
$VERSION = '1.
|
|
17
|
+
$VERSION = '1.06';
|
|
19
18
|
|
|
20
19
|
sub ReadBencode($$$);
|
|
21
20
|
sub ExtractTags($$$;$$@);
|
|
@@ -169,7 +168,7 @@ sub ReadBencode($$$)
|
|
|
169
168
|
if (length($value) > 256) {
|
|
170
169
|
$val = \$value;
|
|
171
170
|
} elsif ($value =~ /[^\t\x20-\x7e]/) {
|
|
172
|
-
if (Image::ExifTool::
|
|
171
|
+
if (Image::ExifTool::IsUTF8(\$value) >= 0) {
|
|
173
172
|
$val = $et->Decode($value, 'UTF8');
|
|
174
173
|
} else {
|
|
175
174
|
$val = \$value;
|
|
@@ -271,6 +271,13 @@ sub WriteCanonRaw($$$)
|
|
|
271
271
|
$raf->Seek($blockStart+$blockSize-4, 0) or return 0;
|
|
272
272
|
$raf->Read($buff, 4) == 4 or return 0;
|
|
273
273
|
my $dirOffset = Get32u(\$buff,0) + $blockStart;
|
|
274
|
+
# avoid infinite recursion
|
|
275
|
+
$$et{ProcessedCanonRaw} or $$et{ProcessedCanonRaw} = { };
|
|
276
|
+
if ($$et{ProcessedCanonRaw}{$dirOffset}) {
|
|
277
|
+
$et->Error("Double-referenced $$dirInfo{DirName} directory");
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
$$et{ProcessedCanonRaw}{$dirOffset} = 1;
|
|
274
281
|
$raf->Seek($dirOffset, 0) or return 0;
|
|
275
282
|
$raf->Read($buff, 2) == 2 or return 0;
|
|
276
283
|
my $entries = Get16u(\$buff,0); # get number of entries in directory
|
|
@@ -725,7 +725,7 @@ Entry: for (;;) {
|
|
|
725
725
|
$readFormat = $oldFormat = Get16u($dataPt, $entry+2);
|
|
726
726
|
$readCount = $oldCount = Get32u($dataPt, $entry+4);
|
|
727
727
|
undef $oldImageData;
|
|
728
|
-
if ($oldFormat < 1 or $oldFormat > 13) {
|
|
728
|
+
if ($oldFormat < 1 or $oldFormat > 13 and not ($oldFormat == 16 and $$et{Make} eq 'Apple' and $inMakerNotes)) {
|
|
729
729
|
my $msg = "Bad format ($oldFormat) for $name entry $index";
|
|
730
730
|
# patch to preserve invalid directory entries in SubIFD3 of
|
|
731
731
|
# various Kodak Z-series cameras (Z812, Z1085IS, Z1275)
|
|
@@ -2244,6 +2244,7 @@ NoOverwrite: next if $isNew > 0;
|
|
|
2244
2244
|
}
|
|
2245
2245
|
} else {
|
|
2246
2246
|
last unless @writeLater;
|
|
2247
|
+
# finally, copy all deferred data
|
|
2247
2248
|
@offsetList = @writeLater;
|
|
2248
2249
|
}
|
|
2249
2250
|
my $offsetPair;
|
|
@@ -2337,6 +2338,23 @@ NoOverwrite: next if $isNew > 0;
|
|
|
2337
2338
|
$size = length($buff);
|
|
2338
2339
|
Set32u($size, \$newData, $byteCountPos);
|
|
2339
2340
|
} elsif ($ifd < 0) {
|
|
2341
|
+
# hack for fixed-offset data (Panasonic GH6)
|
|
2342
|
+
if ($$offsetPair[0][6]) {
|
|
2343
|
+
if ($count > 1) {
|
|
2344
|
+
$et->Error("Can't handle fixed offsets with count > 1");
|
|
2345
|
+
} else {
|
|
2346
|
+
my $fixedOffset = Get32u(\$newData, $offsets);
|
|
2347
|
+
my $padToFixedOffset = $fixedOffset - ($newOffset + $dpos);
|
|
2348
|
+
if ($padToFixedOffset < 0) {
|
|
2349
|
+
$et->Error('Metadata too large to fit before fixed-offset image data');
|
|
2350
|
+
} else {
|
|
2351
|
+
# add necessary padding before raw data
|
|
2352
|
+
push @imageData, [$offset+$dbase+$dpos, 0, $padToFixedOffset];
|
|
2353
|
+
$newOffset += $padToFixedOffset;
|
|
2354
|
+
$et->Warn("Adding $padToFixedOffset bytes of padding before fixed-offset image data", 1);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2340
2358
|
# pad if necessary (but don't pad contiguous image blocks)
|
|
2341
2359
|
my $pad = 0;
|
|
2342
2360
|
++$pad if ($blockSize + $size) & 0x01 and ($n+1 >= $count or
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#------------------------------------------------------------------------------
|
|
2
|
+
# File: WriteRIFF.pl
|
|
3
|
+
#
|
|
4
|
+
# Description: Write RIFF-format files
|
|
5
|
+
#
|
|
6
|
+
# Revisions: 2020-09-26 - P. Harvey Created
|
|
7
|
+
#
|
|
8
|
+
# Notes: Currently writes only WEBP files
|
|
9
|
+
#
|
|
10
|
+
# References: https://developers.google.com/speed/webp/docs/riff_container
|
|
11
|
+
#------------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
package Image::ExifTool::RIFF;
|
|
14
|
+
|
|
15
|
+
use strict;
|
|
16
|
+
|
|
17
|
+
# map of where information is stored in WebP image
|
|
18
|
+
my %webpMap = (
|
|
19
|
+
'XMP ' => 'RIFF', # (the RIFF chunk name is 'XMP ')
|
|
20
|
+
EXIF => 'RIFF',
|
|
21
|
+
ICCP => 'RIFF',
|
|
22
|
+
XMP => 'XMP ',
|
|
23
|
+
IFD0 => 'EXIF',
|
|
24
|
+
IFD1 => 'IFD0',
|
|
25
|
+
ICC_Profile => 'ICCP',
|
|
26
|
+
ExifIFD => 'IFD0',
|
|
27
|
+
GPS => 'IFD0',
|
|
28
|
+
SubIFD => 'IFD0',
|
|
29
|
+
GlobParamIFD => 'IFD0',
|
|
30
|
+
PrintIM => 'IFD0',
|
|
31
|
+
InteropIFD => 'ExifIFD',
|
|
32
|
+
MakerNotes => 'ExifIFD',
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
#------------------------------------------------------------------------------
|
|
36
|
+
# Write RIFF file (currently WebP-type only)
|
|
37
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref
|
|
38
|
+
# Returns: 1 on success, 0 if this wasn't a valid RIFF file, or -1 if
|
|
39
|
+
# an output file was specified and a write error occurred
|
|
40
|
+
sub WriteRIFF($$)
|
|
41
|
+
{
|
|
42
|
+
my ($et, $dirInfo) = @_;
|
|
43
|
+
$et or return 1; # allow dummy access to autoload this package
|
|
44
|
+
my $outfile = $$dirInfo{OutFile};
|
|
45
|
+
my $outsize = 0;
|
|
46
|
+
my $raf = $$dirInfo{RAF};
|
|
47
|
+
my ($buff, $err, $pass, %has, %dirDat, $imageWidth, $imageHeight);
|
|
48
|
+
|
|
49
|
+
# do this in 2 passes so we can set the size of the containing RIFF chunk
|
|
50
|
+
# without having to buffer the output (also to set the WebP_Flags)
|
|
51
|
+
for ($pass=0; ; ++$pass) {
|
|
52
|
+
my %doneDir;
|
|
53
|
+
# verify this is a valid RIFF file
|
|
54
|
+
return 0 unless $raf->Read($buff, 12) == 12;
|
|
55
|
+
return 0 unless $buff =~ /^(RIFF|RF64)....(.{4})/s;
|
|
56
|
+
|
|
57
|
+
unless ($1 eq 'RIFF' and $2 eq 'WEBP') {
|
|
58
|
+
my $type = $2;
|
|
59
|
+
$type =~ tr/-_a-zA-Z//dc;
|
|
60
|
+
$et->Error("Can't currently write $1 $type files");
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
SetByteOrder('II');
|
|
64
|
+
|
|
65
|
+
# determine which directories we must write for this file type
|
|
66
|
+
$et->InitWriteDirs(\%webpMap);
|
|
67
|
+
my $addDirs = $$et{ADD_DIRS};
|
|
68
|
+
my $editDirs = $$et{EDIT_DIRS};
|
|
69
|
+
my ($createVP8X, $deleteVP8X);
|
|
70
|
+
|
|
71
|
+
# write header
|
|
72
|
+
if ($pass) {
|
|
73
|
+
my $needsVP8X = ($has{ANIM} or $has{'XMP '} or $has{EXIF} or
|
|
74
|
+
$has{ALPH} or $has{ICCP});
|
|
75
|
+
if ($has{VP8X} and not $needsVP8X and $$et{CHANGED}) {
|
|
76
|
+
$deleteVP8X = 1; # delete the VP8X chunk
|
|
77
|
+
$outsize -= 18; # account for missing VP8X
|
|
78
|
+
} elsif ($needsVP8X and not $has{VP8X}) {
|
|
79
|
+
if (defined $imageWidth) {
|
|
80
|
+
++$$et{CHANGED};
|
|
81
|
+
$createVP8X = 1; # add VP8X chunk
|
|
82
|
+
$outsize += 18; # account for VP8X size
|
|
83
|
+
} else {
|
|
84
|
+
$et->Warn('Error getting image size for required VP8X chunk');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
# finally we can set the overall RIFF chunk size:
|
|
88
|
+
Set32u($outsize - 8, \$buff, 4);
|
|
89
|
+
Write($outfile, $buff) or $err = 1;
|
|
90
|
+
# create VP8X chunk if necessary
|
|
91
|
+
if ($createVP8X) {
|
|
92
|
+
$et->VPrint(0," Adding required VP8X chunk (Extended WEBP)\n");
|
|
93
|
+
my $flags = 0;
|
|
94
|
+
$flags |= 0x02 if $has{ANIM};
|
|
95
|
+
$flags |= 0x04 if $has{'XMP '};
|
|
96
|
+
$flags |= 0x08 if $has{EXIF};
|
|
97
|
+
$flags |= 0x10 if $has{ALPH};
|
|
98
|
+
$flags |= 0x20 if $has{ICCP};
|
|
99
|
+
Write($outfile, 'VP8X', pack('V3v', 10, $flags,
|
|
100
|
+
($imageWidth-1) | ((($imageHeight-1) & 0xff) << 24),
|
|
101
|
+
($imageHeight-1) >> 8));
|
|
102
|
+
# write ICCP after VP8X
|
|
103
|
+
Write($outfile, $dirDat{ICCP}) or $err = 1 if $dirDat{ICCP};
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
$outsize += length $buff;
|
|
107
|
+
}
|
|
108
|
+
my $pos = 12;
|
|
109
|
+
#
|
|
110
|
+
# Read chunks in RIFF image
|
|
111
|
+
#
|
|
112
|
+
for (;;) {
|
|
113
|
+
my ($tag, $len);
|
|
114
|
+
my $num = $raf->Read($buff, 8);
|
|
115
|
+
if ($num < 8) {
|
|
116
|
+
$num and $et->Error('RIFF format error'), return 1;
|
|
117
|
+
# all done if we hit end of file unless we need to add EXIF or XMP
|
|
118
|
+
last unless $$addDirs{EXIF} or $$addDirs{'XMP '} or $$addDirs{ICCP};
|
|
119
|
+
# continue to add required EXIF or XMP chunks
|
|
120
|
+
$num = $len = 0;
|
|
121
|
+
$buff = $tag = '';
|
|
122
|
+
} else {
|
|
123
|
+
$pos += 8;
|
|
124
|
+
($tag, $len) = unpack('a4V', $buff);
|
|
125
|
+
if ($len <= 0) {
|
|
126
|
+
if ($len < 0) {
|
|
127
|
+
$et->Error('Invalid chunk length');
|
|
128
|
+
return 1;
|
|
129
|
+
} elsif ($tag eq "\0\0\0\0") {
|
|
130
|
+
# avoid reading through corrupted files filled with nulls because it takes forever
|
|
131
|
+
$et->Error('Encountered empty null chunk. Processing aborted');
|
|
132
|
+
return 1;
|
|
133
|
+
} else { # (just in case a tag may have no data)
|
|
134
|
+
if ($pass) {
|
|
135
|
+
Write($outfile, $buff) or $err = 1;
|
|
136
|
+
} else {
|
|
137
|
+
$outsize += length $buff;
|
|
138
|
+
}
|
|
139
|
+
next;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
# RIFF chunks are padded to an even number of bytes
|
|
144
|
+
my $len2 = $len + ($len & 0x01);
|
|
145
|
+
# edit/add/delete necessary metadata chunks (EXIF must come before XMP)
|
|
146
|
+
if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
|
|
147
|
+
my $handledTag;
|
|
148
|
+
if ($len2) {
|
|
149
|
+
$et->Warn("Duplicate '${tag}' chunk") if $doneDir{$tag} and not $pass;
|
|
150
|
+
$doneDir{$tag} = 1;
|
|
151
|
+
$raf->Read($buff, $len2) == $len2 or $et->Error("Truncated '${tag}' chunk"), last;
|
|
152
|
+
$pos += $len2; # update current position
|
|
153
|
+
} else {
|
|
154
|
+
$buff = '';
|
|
155
|
+
}
|
|
156
|
+
#
|
|
157
|
+
# add/edit/delete EXIF/XMP/ICCP (note: EXIF must come before XMP, and ICCP is written elsewhere)
|
|
158
|
+
#
|
|
159
|
+
my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
|
160
|
+
my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
|
161
|
+
my $dir;
|
|
162
|
+
foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
|
|
163
|
+
next unless $tag eq $dir or ($$addDirs{$dir} and
|
|
164
|
+
($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
|
|
165
|
+
delete $$addDirs{$dir}; # (don't try to add again)
|
|
166
|
+
my $start;
|
|
167
|
+
unless ($pass) {
|
|
168
|
+
# write the EXIF and save the result for the next pass
|
|
169
|
+
my $dataPt = \$buff;
|
|
170
|
+
if ($tag eq 'EXIF') {
|
|
171
|
+
# (only need to set directory $start for EXIF)
|
|
172
|
+
if ($buff =~ /^Exif\0\0/) {
|
|
173
|
+
$et->Warn('Improper EXIF header') unless $pass;
|
|
174
|
+
$start = 6;
|
|
175
|
+
} else {
|
|
176
|
+
$start = 0;
|
|
177
|
+
}
|
|
178
|
+
} elsif ($dir ne $tag) {
|
|
179
|
+
# create from scratch
|
|
180
|
+
my $buf2 = '';
|
|
181
|
+
$dataPt = \$buf2;
|
|
182
|
+
}
|
|
183
|
+
# write the new directory to memory
|
|
184
|
+
my %dirInfo = (
|
|
185
|
+
DataPt => $dataPt,
|
|
186
|
+
DataPos => 0, # (relative to Base)
|
|
187
|
+
DirStart => $start,
|
|
188
|
+
Base => $pos - $len2,
|
|
189
|
+
Parent => $dir,
|
|
190
|
+
DirName => $dirName{$dir},
|
|
191
|
+
);
|
|
192
|
+
my $tagTablePtr = GetTagTable("Image::ExifTool::$tblName{$dir}::Main");
|
|
193
|
+
# (override writeProc for EXIF because it has the TIFF header)
|
|
194
|
+
my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
|
|
195
|
+
$dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
|
|
196
|
+
}
|
|
197
|
+
if (defined $dirDat{$dir}) {
|
|
198
|
+
if ($dir eq $tag) {
|
|
199
|
+
$handledTag = 1; # set flag indicating we edited this tag
|
|
200
|
+
# increment CHANGED count if we are deleting the directory
|
|
201
|
+
++$$et{CHANGED} unless length $dirDat{$dir};
|
|
202
|
+
}
|
|
203
|
+
if (length $dirDat{$dir}) {
|
|
204
|
+
if ($pass) {
|
|
205
|
+
# write metadata chunk now (but not ICCP because it was added earlier)
|
|
206
|
+
Write($outfile, $dirDat{$dir}) or $err = 1 unless $dir eq 'ICCP';
|
|
207
|
+
} else {
|
|
208
|
+
# preserve (incorrect EXIF) header if it existed
|
|
209
|
+
my $hdr = $start ? substr($buff,0,$start) : '';
|
|
210
|
+
# (don't overwrite $len here because it may be XMP length)
|
|
211
|
+
my $dirLen = length($dirDat{$dir}) + length($hdr);
|
|
212
|
+
# add chunk header and padding
|
|
213
|
+
my $pad = $dirLen & 0x01 ? "\0" : '';
|
|
214
|
+
$dirDat{$dir} = $dir . Set32u($dirLen) . $hdr . $dirDat{$dir} . $pad;
|
|
215
|
+
$outsize += length($dirDat{$dir});
|
|
216
|
+
$has{$dir} = 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
#
|
|
222
|
+
# just copy XMP, EXIF or ICC if nothing changed
|
|
223
|
+
#
|
|
224
|
+
if (not $handledTag and length $buff) {
|
|
225
|
+
# write the chunk without changes
|
|
226
|
+
if ($pass) {
|
|
227
|
+
Write($outfile, $tag, Set32u($len), $buff) or $err = 1;
|
|
228
|
+
} else {
|
|
229
|
+
$outsize += 8 + length($buff);
|
|
230
|
+
$has{$tag} = 1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
next;
|
|
234
|
+
}
|
|
235
|
+
$pos += $len2; # set read position at end of chunk data
|
|
236
|
+
#
|
|
237
|
+
# update necessary flags in VP8X chunk
|
|
238
|
+
#
|
|
239
|
+
if ($tag eq 'VP8X') {
|
|
240
|
+
my $buf2;
|
|
241
|
+
if ($len2 < 10 or $raf->Read($buf2, $len2) != $len2) {
|
|
242
|
+
$et->Error('Truncated VP8X chunk');
|
|
243
|
+
return 1;
|
|
244
|
+
}
|
|
245
|
+
if ($pass) {
|
|
246
|
+
if ($deleteVP8X) {
|
|
247
|
+
$et->VPrint(0," Deleting unnecessary VP8X chunk (Standard WEBP)\n");
|
|
248
|
+
next;
|
|
249
|
+
}
|
|
250
|
+
# ...but first set the VP8X flags
|
|
251
|
+
my $flags = Get32u(\$buf2, 0);
|
|
252
|
+
$flags &= ~0x2c; # (reset flags for everything we can write)
|
|
253
|
+
$flags |= 0x04 if $has{'XMP '};
|
|
254
|
+
$flags |= 0x08 if $has{EXIF};
|
|
255
|
+
$flags |= 0x20 if $has{ICCP};
|
|
256
|
+
Set32u($flags, \$buf2, 0);
|
|
257
|
+
Write($outfile, $buff, $buf2) or $err = 1;
|
|
258
|
+
} else {
|
|
259
|
+
# get the image size
|
|
260
|
+
$imageWidth = (Get32u(\$buf2, 4) & 0xffffff) + 1;
|
|
261
|
+
$imageHeight = (Get32u(\$buf2, 6) >> 8) + 1;
|
|
262
|
+
$outsize += 8 + $len2;
|
|
263
|
+
$has{$tag} = 1;
|
|
264
|
+
}
|
|
265
|
+
# write ICCP after VP8X
|
|
266
|
+
Write($outfile, $dirDat{ICCP}) or $err = 1 if $dirDat{ICCP};
|
|
267
|
+
next;
|
|
268
|
+
}
|
|
269
|
+
#
|
|
270
|
+
# just copy all other chunks
|
|
271
|
+
#
|
|
272
|
+
if ($pass) {
|
|
273
|
+
# write chunk header (still in $buff)
|
|
274
|
+
Write($outfile, $buff) or $err = 1;
|
|
275
|
+
} else {
|
|
276
|
+
$outsize += length $buff;
|
|
277
|
+
$has{$tag} = 1;
|
|
278
|
+
}
|
|
279
|
+
unless ($pass or defined $imageWidth) {
|
|
280
|
+
# get WebP image size from VP8 or VP8L header
|
|
281
|
+
if ($tag eq 'VP8 ' and $len2 >= 16) {
|
|
282
|
+
$raf->Read($buff, 16) == 16 or $et->Error('Truncated VP8 chunk'), return 1;
|
|
283
|
+
$outsize += 16;
|
|
284
|
+
if ($buff =~ /^...\x9d\x01\x2a/s) {
|
|
285
|
+
$imageWidth = Get16u(\$buff, 6) & 0x3fff;
|
|
286
|
+
$imageHeight = Get16u(\$buff, 8) & 0x3fff;
|
|
287
|
+
}
|
|
288
|
+
$len2 -= 16;
|
|
289
|
+
} elsif ($tag eq 'VP8L' and $len2 >= 6) {
|
|
290
|
+
$raf->Read($buff, 6) == 6 or $et->Error('Truncated VP8L chunk'), return 1;
|
|
291
|
+
$outsize += 6;
|
|
292
|
+
if ($buff =~ /^\x2f/s) {
|
|
293
|
+
$imageWidth = (Get16u(\$buff, 1) & 0x3fff) + 1;
|
|
294
|
+
$imageHeight = ((Get32u(\$buff, 2) >> 6) & 0x3fff) + 1;
|
|
295
|
+
}
|
|
296
|
+
$len2 -= 6;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if ($pass) {
|
|
300
|
+
# copy the chunk data in 64k blocks
|
|
301
|
+
while ($len2) {
|
|
302
|
+
my $num = $len2;
|
|
303
|
+
$num = 65536 if $num > 65536;
|
|
304
|
+
$raf->Read($buff, $num) == $num or $et->Error('Truncated RIFF chunk'), last;
|
|
305
|
+
Write($outfile, $buff) or $err = 1, last;
|
|
306
|
+
$len2 -= $num;
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
$raf->Seek($len2, 1) or $et->Error('Seek error'), last;
|
|
310
|
+
$outsize += $len2;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
last if $pass;
|
|
314
|
+
$raf->Seek(0,0) or $et->Error('Seek error'), last;
|
|
315
|
+
}
|
|
316
|
+
return $err ? -1 : 1;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
1; # end
|
|
320
|
+
|
|
321
|
+
__END__
|
|
322
|
+
|
|
323
|
+
=head1 NAME
|
|
324
|
+
|
|
325
|
+
Image::ExifTool::WriteRIFF.pl - Write RIFF-format files
|
|
326
|
+
|
|
327
|
+
=head1 SYNOPSIS
|
|
328
|
+
|
|
329
|
+
This file is autoloaded by Image::ExifTool::RIFF.
|
|
330
|
+
|
|
331
|
+
=head1 DESCRIPTION
|
|
332
|
+
|
|
333
|
+
This file contains routines to write metadata to RIFF-format files.
|
|
334
|
+
|
|
335
|
+
=head1 NOTES
|
|
336
|
+
|
|
337
|
+
Currently writes only WebP files.
|
|
338
|
+
|
|
339
|
+
=head1 AUTHOR
|
|
340
|
+
|
|
341
|
+
Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com)
|
|
342
|
+
|
|
343
|
+
This library is free software; you can redistribute it and/or modify it
|
|
344
|
+
under the same terms as Perl itself.
|
|
345
|
+
|
|
346
|
+
=head1 REFERENCES
|
|
347
|
+
|
|
348
|
+
=over 4
|
|
349
|
+
|
|
350
|
+
=item L<https://developers.google.com/speed/webp/docs/riff_container>
|
|
351
|
+
|
|
352
|
+
=back
|
|
353
|
+
|
|
354
|
+
=head1 SEE ALSO
|
|
355
|
+
|
|
356
|
+
L<Image::ExifTool::Photoshop(3pm)|Image::ExifTool::RIFF>,
|
|
357
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
|
358
|
+
|
|
359
|
+
=cut
|
|
@@ -115,7 +115,9 @@ my %writableType = (
|
|
|
115
115
|
PS => [ 'PostScript', 'WritePS' ],
|
|
116
116
|
PSD => 'Photoshop',
|
|
117
117
|
RAF => [ 'FujiFilm', 'WriteRAF' ],
|
|
118
|
+
RIFF=> [ 'RIFF', 'WriteRIFF'],
|
|
118
119
|
VRD => 'CanonVRD',
|
|
120
|
+
WEBP=> [ 'RIFF', 'WriteRIFF'],
|
|
119
121
|
X3F => 'SigmaRaw',
|
|
120
122
|
XMP => [ undef, 'WriteXMP' ],
|
|
121
123
|
);
|
|
@@ -240,7 +242,7 @@ my %intRange = (
|
|
|
240
242
|
'int64s' => [-9223372036854775808, 9223372036854775807],
|
|
241
243
|
);
|
|
242
244
|
# lookup for file types with block-writable EXIF
|
|
243
|
-
my %blockExifTypes = map { $_ => 1 } qw(JPEG PNG JP2 MIE EXIF FLIF MOV MP4);
|
|
245
|
+
my %blockExifTypes = map { $_ => 1 } qw(JPEG PNG JP2 MIE EXIF FLIF MOV MP4 RIFF);
|
|
244
246
|
|
|
245
247
|
my $maxSegmentLen = 0xfffd; # maximum length of data in a JPEG segment
|
|
246
248
|
my $maxXMPLen = $maxSegmentLen; # maximum length of XMP data in JPEG
|
|
@@ -4244,7 +4246,9 @@ sub WriteDirectory($$$;$)
|
|
|
4244
4246
|
SetByteOrder($saveOrder);
|
|
4245
4247
|
if ($out) {
|
|
4246
4248
|
print $out " Deleting $name\n" if defined $newData and not length $newData;
|
|
4247
|
-
|
|
4249
|
+
if ($$self{CHANGED} == $oldChanged and $$self{OPTIONS}{Verbose} > 2) {
|
|
4250
|
+
print $out "$$self{INDENT} [nothing changed in $dirName]\n";
|
|
4251
|
+
}
|
|
4248
4252
|
}
|
|
4249
4253
|
return $newData;
|
|
4250
4254
|
}
|