exiftool_vendored 12.42.0 → 12.52.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 +226 -6
- data/bin/MANIFEST +14 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +45 -44
- data/bin/config_files/acdsee.config +2 -1
- data/bin/config_files/frameCount.config +56 -0
- data/bin/config_files/tiff_version.config +1 -1
- data/bin/exiftool +116 -97
- data/bin/fmt_files/gpx.fmt +3 -0
- data/bin/fmt_files/gpx_wpt.fmt +3 -0
- data/bin/lib/Image/ExifTool/Apple.pm +16 -3
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +23 -12
- data/bin/lib/Image/ExifTool/Canon.pm +66 -37
- data/bin/lib/Image/ExifTool/CanonRaw.pm +8 -1
- data/bin/lib/Image/ExifTool/CanonVRD.pm +7 -8
- data/bin/lib/Image/ExifTool/Casio.pm +3 -3
- data/bin/lib/Image/ExifTool/DJI.pm +2 -1
- data/bin/lib/Image/ExifTool/DarwinCore.pm +13 -1
- data/bin/lib/Image/ExifTool/EXE.pm +9 -1
- data/bin/lib/Image/ExifTool/Exif.pm +17 -12
- data/bin/lib/Image/ExifTool/FLAC.pm +17 -3
- data/bin/lib/Image/ExifTool/FLIR.pm +9 -7
- data/bin/lib/Image/ExifTool/FlashPix.pm +26 -3
- data/bin/lib/Image/ExifTool/FujiFilm.pm +51 -4
- data/bin/lib/Image/ExifTool/GPS.pm +31 -5
- data/bin/lib/Image/ExifTool/Geotag.pm +36 -8
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +3 -2
- data/bin/lib/Image/ExifTool/ICO.pm +143 -0
- data/bin/lib/Image/ExifTool/ID3.pm +6 -6
- data/bin/lib/Image/ExifTool/IPTC.pm +5 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -0
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +24 -3
- data/bin/lib/Image/ExifTool/LNK.pm +5 -2
- data/bin/lib/Image/ExifTool/Lang/de.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/fr.pm +6015 -759
- data/bin/lib/Image/ExifTool/Lang/sk.pm +1927 -0
- data/bin/lib/Image/ExifTool/M2TS.pm +98 -8
- data/bin/lib/Image/ExifTool/MIE.pm +9 -3
- data/bin/lib/Image/ExifTool/MISB.pm +494 -0
- data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -1
- data/bin/lib/Image/ExifTool/Matroska.pm +272 -48
- data/bin/lib/Image/ExifTool/Motorola.pm +8 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +746 -382
- data/bin/lib/Image/ExifTool/NikonCustom.pm +139 -106
- data/bin/lib/Image/ExifTool/NikonSettings.pm +5 -3
- data/bin/lib/Image/ExifTool/Olympus.pm +6 -4
- data/bin/lib/Image/ExifTool/PNG.pm +8 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +21 -4
- data/bin/lib/Image/ExifTool/PanasonicRaw.pm +25 -5
- data/bin/lib/Image/ExifTool/Parrot.pm +96 -2
- data/bin/lib/Image/ExifTool/Pentax.pm +7 -2
- data/bin/lib/Image/ExifTool/Photoshop.pm +29 -3
- data/bin/lib/Image/ExifTool/QuickTime.pm +166 -13
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +161 -22
- data/bin/lib/Image/ExifTool/README +15 -4
- data/bin/lib/Image/ExifTool/RIFF.pm +106 -9
- data/bin/lib/Image/ExifTool/Samsung.pm +2 -2
- data/bin/lib/Image/ExifTool/Sigma.pm +27 -1
- data/bin/lib/Image/ExifTool/SigmaRaw.pm +37 -13
- data/bin/lib/Image/ExifTool/Sony.pm +75 -47
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +13 -6
- data/bin/lib/Image/ExifTool/TagLookup.pm +4791 -4519
- data/bin/lib/Image/ExifTool/TagNames.pod +2056 -1446
- data/bin/lib/Image/ExifTool/Text.pm +3 -4
- data/bin/lib/Image/ExifTool/Torrent.pm +2 -3
- data/bin/lib/Image/ExifTool/Validate.pm +3 -3
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +7 -0
- data/bin/lib/Image/ExifTool/WriteExif.pl +100 -23
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +2 -6
- data/bin/lib/Image/ExifTool/WritePhotoshop.pl +5 -5
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +12 -7
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +359 -0
- data/bin/lib/Image/ExifTool/WriteXMP.pl +15 -1
- data/bin/lib/Image/ExifTool/Writer.pl +46 -18
- data/bin/lib/Image/ExifTool/XMP.pm +78 -59
- data/bin/lib/Image/ExifTool/XMP2.pl +19 -4
- data/bin/lib/Image/ExifTool/ZIP.pm +19 -7
- data/bin/lib/Image/ExifTool.pm +146 -38
- data/bin/lib/Image/ExifTool.pod +83 -69
- data/bin/perl-Image-ExifTool.spec +43 -43
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +10 -4
|
@@ -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
|
|
@@ -561,7 +561,21 @@ sub AddStructType($$$$;$)
|
|
|
561
561
|
}
|
|
562
562
|
|
|
563
563
|
#------------------------------------------------------------------------------
|
|
564
|
-
#
|
|
564
|
+
# Process SphericalVideoXML (see XMP-GSpherical tags documentation)
|
|
565
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
|
566
|
+
# Returns: SphericalVideoXML data
|
|
567
|
+
sub ProcessGSpherical($$$)
|
|
568
|
+
{
|
|
569
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
|
570
|
+
# extract SphericalVideoXML as a block if requested
|
|
571
|
+
if ($$et{REQ_TAG_LOOKUP}{sphericalvideoxml}) {
|
|
572
|
+
$et->FoundTag(SphericalVideoXML => substr(${$$dirInfo{DataPt}}, 16));
|
|
573
|
+
}
|
|
574
|
+
return Image::ExifTool::XMP::ProcessXMP($et, $dirInfo, $tagTablePtr);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
#------------------------------------------------------------------------------
|
|
578
|
+
# Hack to use XMP writer for SphericalVideoXML (see XMP-GSpherical tags documentation)
|
|
565
579
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
|
566
580
|
# Returns: SphericalVideoXML data
|
|
567
581
|
sub WriteGSpherical($$$)
|
|
@@ -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
|
|
@@ -705,9 +707,13 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
705
707
|
$writeGroup or $writeGroup = $group0;
|
|
706
708
|
# get priority for this group
|
|
707
709
|
unless ($priority) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
710
|
+
if ($$tagInfo{Avoid} and $$tagInfo{WriteAlso}) {
|
|
711
|
+
$priority = 0;
|
|
712
|
+
} else {
|
|
713
|
+
$priority = $$self{WRITE_PRIORITY}{lc($writeGroup)};
|
|
714
|
+
unless ($priority) {
|
|
715
|
+
$priority = $$self{WRITE_PRIORITY}{lc($group0)} || 0;
|
|
716
|
+
}
|
|
711
717
|
}
|
|
712
718
|
}
|
|
713
719
|
# adjust priority based on Preferred level for this tag
|
|
@@ -828,6 +834,8 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
828
834
|
$tag = $$tagInfo{Name}; # get tag name for warnings
|
|
829
835
|
my $lcTag = lc $tag;
|
|
830
836
|
my $pref = $preferred{$lcTag} || { };
|
|
837
|
+
# don't write Avoid-ed tags with side effect unless preferred
|
|
838
|
+
next if not $$pref{$tagInfo} and $$tagInfo{Avoid} and $$tagInfo{WriteAlso};
|
|
831
839
|
my $shift = $options{Shift};
|
|
832
840
|
my $addValue = $options{AddValue};
|
|
833
841
|
if (defined $shift) {
|
|
@@ -969,16 +977,18 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
969
977
|
$self->GetNewValueHash($tagInfo, $writeGroup, 'delete', $options{ProtectSaved});
|
|
970
978
|
# also delete related tag previous new values
|
|
971
979
|
if ($$tagInfo{WriteAlso}) {
|
|
980
|
+
$$self{INDENT2} = '+';
|
|
972
981
|
my ($wgrp, $wtag);
|
|
973
982
|
if ($$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All' and $writeGroup) {
|
|
974
983
|
$wgrp = $writeGroup . ':';
|
|
975
984
|
} else {
|
|
976
985
|
$wgrp = '';
|
|
977
986
|
}
|
|
978
|
-
foreach $wtag (keys %{$$tagInfo{WriteAlso}}) {
|
|
987
|
+
foreach $wtag (sort keys %{$$tagInfo{WriteAlso}}) {
|
|
979
988
|
my ($n,$e) = $self->SetNewValue($wgrp . $wtag, undef, Replace=>2);
|
|
980
989
|
$numSet += $n;
|
|
981
990
|
}
|
|
991
|
+
$$self{INDENT2} = '';
|
|
982
992
|
}
|
|
983
993
|
$options{Replace} == 2 and ++$numSet, next;
|
|
984
994
|
}
|
|
@@ -1020,7 +1030,7 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
1020
1030
|
require 'Image/ExifTool/XMPStruct.pl';
|
|
1021
1031
|
$_ = Image::ExifTool::XMP::SerializeStruct($_);
|
|
1022
1032
|
}
|
|
1023
|
-
print $out "$verb $wgrp1:$tag$fromList if value is '${_}'\n";
|
|
1033
|
+
print $out "$$self{INDENT2}$verb $wgrp1:$tag$fromList if value is '${_}'\n";
|
|
1024
1034
|
}
|
|
1025
1035
|
}
|
|
1026
1036
|
}
|
|
@@ -1084,15 +1094,25 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
1084
1094
|
push @{$$nvHash{Value}}, ref $val eq 'ARRAY' ? @$val : $val;
|
|
1085
1095
|
}
|
|
1086
1096
|
if ($verbose > 1) {
|
|
1087
|
-
my $ifExists
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1097
|
+
my $ifExists;
|
|
1098
|
+
if ($$tagInfo{IsComposite}) {
|
|
1099
|
+
# (composite tags don't technically exist in the file)
|
|
1100
|
+
if ($$tagInfo{WriteAlso}) {
|
|
1101
|
+
$ifExists = ' (+' . join(',+',sort keys %{$$tagInfo{WriteAlso}}) . '):';
|
|
1102
|
+
} else {
|
|
1103
|
+
$ifExists = '';
|
|
1104
|
+
}
|
|
1105
|
+
} else {
|
|
1106
|
+
$ifExists = $$nvHash{IsCreating} ? ( $createOnly ?
|
|
1107
|
+
($$nvHash{IsCreating} == 2 ?
|
|
1108
|
+
" if $writeGroup exists and tag doesn't" :
|
|
1109
|
+
" if tag doesn't exist") :
|
|
1110
|
+
($$nvHash{IsCreating} == 2 ? " if $writeGroup exists" : '')) :
|
|
1092
1111
|
(($$nvHash{DelValue} and @{$$nvHash{DelValue}}) ?
|
|
1093
|
-
|
|
1112
|
+
' if tag was deleted' : ' if tag exists');
|
|
1113
|
+
}
|
|
1094
1114
|
my $verb = ($shift ? 'Shifting' : ($addValue ? 'Adding' : 'Writing'));
|
|
1095
|
-
print $out "$verb $wgrp1:$tag$ifExists\n";
|
|
1115
|
+
print $out "$$self{INDENT2}$verb $wgrp1:$tag$ifExists\n";
|
|
1096
1116
|
}
|
|
1097
1117
|
}
|
|
1098
1118
|
} elsif ($permanent) {
|
|
@@ -1107,7 +1127,7 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
|
1107
1127
|
$self->GetNewValueHash($tagInfo, $writeGroup, 'delete');
|
|
1108
1128
|
my $nvHash = $self->GetNewValueHash($tagInfo, $writeGroup, 'create');
|
|
1109
1129
|
$$nvHash{WantGroup} = $wantGroup;
|
|
1110
|
-
$verbose > 1 and print $out "Deleting $wgrp1:$tag\n";
|
|
1130
|
+
$verbose > 1 and print $out "$$self{INDENT2}Deleting $wgrp1:$tag\n";
|
|
1111
1131
|
}
|
|
1112
1132
|
$$setTags{$tagInfo} = 1 if $setTags;
|
|
1113
1133
|
$prioritySet = 1 if $$pref{$tagInfo};
|
|
@@ -1116,6 +1136,7 @@ WriteAlso:
|
|
|
1116
1136
|
# also write related tags
|
|
1117
1137
|
my $writeAlso = $$tagInfo{WriteAlso};
|
|
1118
1138
|
if ($writeAlso) {
|
|
1139
|
+
$$self{INDENT2} = '+'; # indicate related tag with a leading "+"
|
|
1119
1140
|
my ($wgrp, $wtag, $n);
|
|
1120
1141
|
if ($$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All' and $writeGroup) {
|
|
1121
1142
|
$wgrp = $writeGroup . ':';
|
|
@@ -1123,7 +1144,7 @@ WriteAlso:
|
|
|
1123
1144
|
$wgrp = '';
|
|
1124
1145
|
}
|
|
1125
1146
|
local $SIG{'__WARN__'} = \&SetWarning;
|
|
1126
|
-
foreach $wtag (keys %$writeAlso) {
|
|
1147
|
+
foreach $wtag (sort keys %$writeAlso) {
|
|
1127
1148
|
my %opts = (
|
|
1128
1149
|
Type => 'ValueConv',
|
|
1129
1150
|
Protected => $protected | 0x02,
|
|
@@ -1135,7 +1156,7 @@ WriteAlso:
|
|
|
1135
1156
|
SetTags => \%alsoWrote, # remember tags already written
|
|
1136
1157
|
);
|
|
1137
1158
|
undef $evalWarning;
|
|
1138
|
-
#### eval WriteAlso ($val)
|
|
1159
|
+
#### eval WriteAlso ($val,%opts)
|
|
1139
1160
|
my $v = eval $$writeAlso{$wtag};
|
|
1140
1161
|
# we wanted to do the eval in case there are side effect, but we
|
|
1141
1162
|
# don't want to write a value for a tag that is being deleted:
|
|
@@ -1157,6 +1178,7 @@ WriteAlso:
|
|
|
1157
1178
|
}
|
|
1158
1179
|
}
|
|
1159
1180
|
}
|
|
1181
|
+
$$self{INDENT2} = '';
|
|
1160
1182
|
}
|
|
1161
1183
|
}
|
|
1162
1184
|
# print warning if we couldn't set our priority tag
|
|
@@ -1270,6 +1292,7 @@ sub SetNewValuesFromFile($$;@)
|
|
|
1270
1292
|
GlobalTimeShift => $$options{GlobalTimeShift},
|
|
1271
1293
|
HexTagIDs => $$options{HexTagIDs},
|
|
1272
1294
|
IgnoreMinorErrors=>$$options{IgnoreMinorErrors},
|
|
1295
|
+
IgnoreTags => $$options{IgnoreTags},
|
|
1273
1296
|
Lang => $$options{Lang},
|
|
1274
1297
|
LargeFileSupport=> $$options{LargeFileSupport},
|
|
1275
1298
|
List => 1,
|
|
@@ -4241,7 +4264,12 @@ sub WriteDirectory($$$;$)
|
|
|
4241
4264
|
$$self{DIR_NAME} = $oldDir;
|
|
4242
4265
|
@$self{'Compression','SubfileType'} = @save;
|
|
4243
4266
|
SetByteOrder($saveOrder);
|
|
4244
|
-
|
|
4267
|
+
if ($out) {
|
|
4268
|
+
print $out " Deleting $name\n" if defined $newData and not length $newData;
|
|
4269
|
+
if ($$self{CHANGED} == $oldChanged and $$self{OPTIONS}{Verbose} > 2) {
|
|
4270
|
+
print $out "$$self{INDENT} [nothing changed in $dirName]\n";
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4245
4273
|
return $newData;
|
|
4246
4274
|
}
|
|
4247
4275
|
|
|
@@ -4530,7 +4558,7 @@ sub DumpUnknownTrailer($$)
|
|
|
4530
4558
|
# add to Preview block list if valid and in the trailer
|
|
4531
4559
|
$image{$prePos} = [$tag, $preLen] if $prePos and $preLen and $prePos+$preLen > $pos;
|
|
4532
4560
|
last if $lastOne; # checked all images
|
|
4533
|
-
# look for MPF images (in the
|
|
4561
|
+
# look for MPF images (in the proper order)
|
|
4534
4562
|
++$mpImageNum;
|
|
4535
4563
|
$prePos = $$self{VALUE}{"MPImageStart ($mpImageNum)"};
|
|
4536
4564
|
if (defined $prePos) {
|