1 | #------------------------------------------------------------------------------
|
---|
2 | # File: MIE.pm
|
---|
3 | #
|
---|
4 | # Description: Read/write MIE meta information
|
---|
5 | #
|
---|
6 | # Revisions: 11/18/2005 - P. Harvey Created
|
---|
7 | #------------------------------------------------------------------------------
|
---|
8 |
|
---|
9 | package Image::ExifTool::MIE;
|
---|
10 |
|
---|
11 | use strict;
|
---|
12 | use vars qw($VERSION %tableDefaults);
|
---|
13 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
14 | use Image::ExifTool::Exif;
|
---|
15 | use Image::ExifTool::GPS;
|
---|
16 |
|
---|
17 | $VERSION = '1.34';
|
---|
18 |
|
---|
19 | sub ProcessMIE($$);
|
---|
20 | sub ProcessMIEGroup($$$);
|
---|
21 | sub WriteMIEGroup($$$);
|
---|
22 | sub CheckMIE($$$);
|
---|
23 | sub GetLangInfo($$);
|
---|
24 |
|
---|
25 | # local variables
|
---|
26 | my $hasZlib; # 1=Zlib available, 0=no Zlib
|
---|
27 | my %mieCode; # reverse lookup for MIE format names
|
---|
28 | my $doneMieMap; # flag indicating we added user-defined groups to %mieMap
|
---|
29 |
|
---|
30 | # MIE format codes
|
---|
31 | my %mieFormat = (
|
---|
32 | 0x00 => 'undef',
|
---|
33 | 0x10 => 'MIE',
|
---|
34 | 0x18 => 'MIE',
|
---|
35 | 0x20 => 'string', # ASCII (ISO 8859-1)
|
---|
36 | 0x28 => 'utf8',
|
---|
37 | 0x29 => 'utf16',
|
---|
38 | 0x2a => 'utf32',
|
---|
39 | 0x30 => 'string_list',
|
---|
40 | 0x38 => 'utf8_list',
|
---|
41 | 0x39 => 'utf16_list',
|
---|
42 | 0x3a => 'utf32_list',
|
---|
43 | 0x40 => 'int8u',
|
---|
44 | 0x41 => 'int16u',
|
---|
45 | 0x42 => 'int32u',
|
---|
46 | 0x43 => 'int64u',
|
---|
47 | 0x48 => 'int8s',
|
---|
48 | 0x49 => 'int16s',
|
---|
49 | 0x4a => 'int32s',
|
---|
50 | 0x4b => 'int64s',
|
---|
51 | 0x52 => 'rational32u',
|
---|
52 | 0x53 => 'rational64u',
|
---|
53 | 0x5a => 'rational32s',
|
---|
54 | 0x5b => 'rational64s',
|
---|
55 | 0x61 => 'fixed16u',
|
---|
56 | 0x62 => 'fixed32u',
|
---|
57 | 0x69 => 'fixed16s',
|
---|
58 | 0x6a => 'fixed32s',
|
---|
59 | 0x72 => 'float',
|
---|
60 | 0x73 => 'double',
|
---|
61 | 0x80 => 'free',
|
---|
62 | );
|
---|
63 |
|
---|
64 | # map of MIE directory locations
|
---|
65 | my %mieMap = (
|
---|
66 | 'MIE-Meta' => 'MIE',
|
---|
67 | 'MIE-Audio' => 'MIE-Meta',
|
---|
68 | 'MIE-Camera' => 'MIE-Meta',
|
---|
69 | 'MIE-Doc' => 'MIE-Meta',
|
---|
70 | 'MIE-Geo' => 'MIE-Meta',
|
---|
71 | 'MIE-Image' => 'MIE-Meta',
|
---|
72 | 'MIE-MakerNotes' => 'MIE-Meta',
|
---|
73 | 'MIE-Preview' => 'MIE-Meta',
|
---|
74 | 'MIE-Thumbnail' => 'MIE-Meta',
|
---|
75 | 'MIE-Video' => 'MIE-Meta',
|
---|
76 | 'MIE-Flash' => 'MIE-Camera',
|
---|
77 | 'MIE-Lens' => 'MIE-Camera',
|
---|
78 | 'MIE-Orient' => 'MIE-Camera',
|
---|
79 | 'MIE-Extender' => 'MIE-Lens',
|
---|
80 | 'MIE-GPS' => 'MIE-Geo',
|
---|
81 | 'MIE-UTM' => 'MIE-Geo',
|
---|
82 | 'MIE-Canon' => 'MIE-MakerNotes',
|
---|
83 | EXIF => 'MIE-Meta',
|
---|
84 | XMP => 'MIE-Meta',
|
---|
85 | IPTC => 'MIE-Meta',
|
---|
86 | ICC_Profile => 'MIE-Meta',
|
---|
87 | ID3 => 'MIE-Meta',
|
---|
88 | CanonVRD => 'MIE-Canon',
|
---|
89 | IFD0 => 'EXIF',
|
---|
90 | IFD1 => 'IFD0',
|
---|
91 | ExifIFD => 'IFD0',
|
---|
92 | GPS => 'IFD0',
|
---|
93 | SubIFD => 'IFD0',
|
---|
94 | GlobParamIFD => 'IFD0',
|
---|
95 | PrintIM => 'IFD0',
|
---|
96 | InteropIFD => 'ExifIFD',
|
---|
97 | MakerNotes => 'ExifIFD',
|
---|
98 | );
|
---|
99 |
|
---|
100 | # convenience variables for common tagInfo entries
|
---|
101 | my %binaryConv = (
|
---|
102 | Writable => 'undef',
|
---|
103 | Binary => 1,
|
---|
104 | );
|
---|
105 | my %dateInfo = (
|
---|
106 | Shift => 'Time',
|
---|
107 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
108 | PrintConvInv => '$self->InverseDateTime($val)',
|
---|
109 | );
|
---|
110 | my %noYes = ( 0 => 'No', 1 => 'Yes' );
|
---|
111 | my %offOn = ( 0 => 'Off', 1 => 'On' );
|
---|
112 |
|
---|
113 | # default entries for MIE tag tables
|
---|
114 | %tableDefaults = (
|
---|
115 | PROCESS_PROC => \&ProcessMIE,
|
---|
116 | WRITE_PROC => \&ProcessMIE,
|
---|
117 | CHECK_PROC => \&CheckMIE,
|
---|
118 | LANG_INFO => \&GetLangInfo,
|
---|
119 | WRITABLE => 'string',
|
---|
120 | PREFERRED => 1,
|
---|
121 | );
|
---|
122 |
|
---|
123 | # MIE info
|
---|
124 | %Image::ExifTool::MIE::Main = (
|
---|
125 | %tableDefaults,
|
---|
126 | GROUPS => { 1 => 'MIE-Main' },
|
---|
127 | WRITE_GROUP => 'MIE-Main',
|
---|
128 | NOTES => q{
|
---|
129 | MIE is a flexible format which may be used as a stand-alone meta information
|
---|
130 | format, for encapsulation of other files and information, or as a trailer
|
---|
131 | appended to other file formats. The tables below represent currently
|
---|
132 | defined MIE tags, however ExifTool will also extract any other information
|
---|
133 | present in a MIE file.
|
---|
134 |
|
---|
135 | When writing MIE information, some special features are supported:
|
---|
136 |
|
---|
137 | 1) String values may be written as ASCII (ISO 8859-1) or UTF-8. ExifTool
|
---|
138 | automatically detects the presence of wide characters and treats the string
|
---|
139 | appropriately. Internally, UTF-8 text may be converted to UTF-16 or UTF-32
|
---|
140 | and stored in this format in the file if it is more compact.
|
---|
141 |
|
---|
142 | 2) All MIE string-value tags support localized text. Localized values are
|
---|
143 | written by adding a language/country code to the tag name in the form
|
---|
144 | C<TAG-xx_YY>, where C<TAG> is the tag name, C<xx> is a 2-character lower
|
---|
145 | case ISO 639-1 language code, and C<YY> is a 2-character upper case ISO
|
---|
146 | 3166-1 alpha 2 country code (ie. C<Title-en_US>). But as usual, the user
|
---|
147 | interface is case-insensitive, and ExifTool will write the correct case to
|
---|
148 | the file.
|
---|
149 |
|
---|
150 | 3) Some numerical MIE tags allow units of measurement to be specified. For
|
---|
151 | these tags, units may be added in brackets immediately following the value
|
---|
152 | (ie. C<55(mi/h)>). If no units are specified, the default units are
|
---|
153 | written.
|
---|
154 | },
|
---|
155 | '0Type' => {
|
---|
156 | Name => 'SubfileType',
|
---|
157 | Notes => q{
|
---|
158 | the capitalized common extension for this type of file. If the extension
|
---|
159 | has a dot-3 abbreviation, then the longer version is used here. For
|
---|
160 | instance, JPEG and TIFF are used, not JPG and TIF
|
---|
161 | },
|
---|
162 | },
|
---|
163 | '0Vers' => {
|
---|
164 | Name => 'MIEVersion',
|
---|
165 | Notes => 'version 1.1 is assumed if not specified',
|
---|
166 | },
|
---|
167 | '1Directory' => {
|
---|
168 | Name => 'SubfileDirectory',
|
---|
169 | Notes => 'original directory for the file',
|
---|
170 | },
|
---|
171 | '1Name' => {
|
---|
172 | Name => 'SubfileName',
|
---|
173 | Notes => 'the file name, including extension if it exists',
|
---|
174 | },
|
---|
175 | '2MIME' => { Name => 'SubfileMIMEType' },
|
---|
176 | Meta => {
|
---|
177 | SubDirectory => {
|
---|
178 | TagTable => 'Image::ExifTool::MIE::Meta',
|
---|
179 | DirName => 'MIE-Meta',
|
---|
180 | },
|
---|
181 | },
|
---|
182 | data => {
|
---|
183 | Name => 'SubfileData',
|
---|
184 | Notes => 'the subfile data',
|
---|
185 | %binaryConv,
|
---|
186 | },
|
---|
187 | rsrc => {
|
---|
188 | Name => 'SubfileResource',
|
---|
189 | Notes => 'subfile resource fork if it exists',
|
---|
190 | %binaryConv,
|
---|
191 | },
|
---|
192 | zmd5 => {
|
---|
193 | Name => 'MD5Digest',
|
---|
194 | Notes => q{
|
---|
195 | 16-byte MD5 digest written in binary form or as a 32-character hex-encoded
|
---|
196 | ASCII string. Value is an MD5 digest of the entire 0MIE group as it would be
|
---|
197 | with the digest value itself set to all null bytes
|
---|
198 | },
|
---|
199 | },
|
---|
200 | zmie => {
|
---|
201 | Name => 'TrailerSignature',
|
---|
202 | Writable => 'undef',
|
---|
203 | Notes => q{
|
---|
204 | used as the last element in the main "0MIE" group to identify a MIE trailer
|
---|
205 | when appended to another type of file. ExifTool will create this tag if set
|
---|
206 | to any value, but always with an empty data block
|
---|
207 | },
|
---|
208 | ValueConvInv => '""', # data block must be empty
|
---|
209 | },
|
---|
210 | );
|
---|
211 |
|
---|
212 | # MIE meta information group
|
---|
213 | %Image::ExifTool::MIE::Meta = (
|
---|
214 | %tableDefaults,
|
---|
215 | GROUPS => { 1 => 'MIE-Meta', 2 => 'Image' },
|
---|
216 | WRITE_GROUP => 'MIE-Meta',
|
---|
217 | Audio => {
|
---|
218 | SubDirectory => {
|
---|
219 | TagTable => 'Image::ExifTool::MIE::Audio',
|
---|
220 | DirName => 'MIE-Audio',
|
---|
221 | },
|
---|
222 | },
|
---|
223 | Camera => {
|
---|
224 | SubDirectory => {
|
---|
225 | TagTable => 'Image::ExifTool::MIE::Camera',
|
---|
226 | DirName => 'MIE-Camera',
|
---|
227 | },
|
---|
228 | },
|
---|
229 | Document => {
|
---|
230 | SubDirectory => {
|
---|
231 | TagTable => 'Image::ExifTool::MIE::Doc',
|
---|
232 | DirName => 'MIE-Doc',
|
---|
233 | },
|
---|
234 | },
|
---|
235 | EXIF => {
|
---|
236 | SubDirectory => {
|
---|
237 | TagTable => 'Image::ExifTool::Exif::Main',
|
---|
238 | ProcessProc => \&Image::ExifTool::ProcessTIFF,
|
---|
239 | WriteProc => \&Image::ExifTool::WriteTIFF,
|
---|
240 | },
|
---|
241 | },
|
---|
242 | Geo => {
|
---|
243 | SubDirectory => {
|
---|
244 | TagTable => 'Image::ExifTool::MIE::Geo',
|
---|
245 | DirName => 'MIE-Geo',
|
---|
246 | },
|
---|
247 | },
|
---|
248 | ICCProfile => {
|
---|
249 | Name => 'ICC_Profile',
|
---|
250 | SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
|
---|
251 | },
|
---|
252 | ID3 => { SubDirectory => { TagTable => 'Image::ExifTool::ID3::Main' } },
|
---|
253 | IPTC => { SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' } },
|
---|
254 | Image => {
|
---|
255 | SubDirectory => {
|
---|
256 | TagTable => 'Image::ExifTool::MIE::Image',
|
---|
257 | DirName => 'MIE-Image',
|
---|
258 | },
|
---|
259 | },
|
---|
260 | MakerNotes => {
|
---|
261 | SubDirectory => {
|
---|
262 | TagTable => 'Image::ExifTool::MIE::MakerNotes',
|
---|
263 | DirName => 'MIE-MakerNotes',
|
---|
264 | },
|
---|
265 | },
|
---|
266 | Preview => {
|
---|
267 | SubDirectory => {
|
---|
268 | TagTable => 'Image::ExifTool::MIE::Preview',
|
---|
269 | DirName => 'MIE-Preview',
|
---|
270 | },
|
---|
271 | },
|
---|
272 | Thumbnail => {
|
---|
273 | SubDirectory => {
|
---|
274 | TagTable => 'Image::ExifTool::MIE::Thumbnail',
|
---|
275 | DirName => 'MIE-Thumbnail',
|
---|
276 | },
|
---|
277 | },
|
---|
278 | Video => {
|
---|
279 | SubDirectory => {
|
---|
280 | TagTable => 'Image::ExifTool::MIE::Video',
|
---|
281 | DirName => 'MIE-Video',
|
---|
282 | },
|
---|
283 | },
|
---|
284 | XMP => { SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' } },
|
---|
285 | );
|
---|
286 |
|
---|
287 | # MIE document information
|
---|
288 | %Image::ExifTool::MIE::Doc = (
|
---|
289 | %tableDefaults,
|
---|
290 | GROUPS => { 1 => 'MIE-Doc', 2 => 'Document' },
|
---|
291 | WRITE_GROUP => 'MIE-Doc',
|
---|
292 | NOTES => 'Information describing the main document, image or file.',
|
---|
293 | Author => { Groups => { 2 => 'Author' } },
|
---|
294 | Comment => { },
|
---|
295 | Contributors=> { Groups => { 2 => 'Author' }, List => 1 },
|
---|
296 | Copyright => { Groups => { 2 => 'Author' } },
|
---|
297 | CreateDate => { Groups => { 2 => 'Time' }, %dateInfo },
|
---|
298 | EMail => { Groups => { 2 => 'Author' } },
|
---|
299 | Keywords => { List => 1 },
|
---|
300 | ModifyDate => { Groups => { 2 => 'Time' }, %dateInfo },
|
---|
301 | OriginalDate=> {
|
---|
302 | Name => 'DateTimeOriginal',
|
---|
303 | Description => 'Date/Time Original',
|
---|
304 | Groups => { 2 => 'Time' },
|
---|
305 | %dateInfo,
|
---|
306 | },
|
---|
307 | Phone => { Name => 'PhoneNumber', Groups => { 2 => 'Author' } },
|
---|
308 | References => { List => 1 },
|
---|
309 | Software => { },
|
---|
310 | Title => { },
|
---|
311 | URL => { },
|
---|
312 | );
|
---|
313 |
|
---|
314 | # MIE geographic information
|
---|
315 | %Image::ExifTool::MIE::Geo = (
|
---|
316 | %tableDefaults,
|
---|
317 | GROUPS => { 1 => 'MIE-Geo', 2 => 'Location' },
|
---|
318 | WRITE_GROUP => 'MIE-Geo',
|
---|
319 | NOTES => 'Information related to geographic location.',
|
---|
320 | Address => { },
|
---|
321 | City => { },
|
---|
322 | Country => { },
|
---|
323 | GPS => {
|
---|
324 | SubDirectory => {
|
---|
325 | TagTable => 'Image::ExifTool::MIE::GPS',
|
---|
326 | DirName => 'MIE-GPS',
|
---|
327 | },
|
---|
328 | },
|
---|
329 | PostalCode => { },
|
---|
330 | State => { Notes => 'state or province' },
|
---|
331 | UTM => {
|
---|
332 | SubDirectory => {
|
---|
333 | TagTable => 'Image::ExifTool::MIE::UTM',
|
---|
334 | DirName => 'MIE-UTM',
|
---|
335 | },
|
---|
336 | },
|
---|
337 | );
|
---|
338 |
|
---|
339 | # MIE GPS information
|
---|
340 | %Image::ExifTool::MIE::GPS = (
|
---|
341 | %tableDefaults,
|
---|
342 | GROUPS => { 1 => 'MIE-GPS', 2 => 'Location' },
|
---|
343 | WRITE_GROUP => 'MIE-GPS',
|
---|
344 | Altitude => {
|
---|
345 | Name => 'GPSAltitude',
|
---|
346 | Writable => 'rational64s',
|
---|
347 | Units => [ qw(m ft) ],
|
---|
348 | Notes => q{'m' above sea level unless 'ft' specified},
|
---|
349 | },
|
---|
350 | Bearing => {
|
---|
351 | Name => 'GPSDestBearing',
|
---|
352 | Writable => 'rational64s',
|
---|
353 | Units => [ qw(deg deg{mag}) ],
|
---|
354 | Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
|
---|
355 | },
|
---|
356 | Datum => { Name => 'GPSMapDatum', Notes => 'WGS-84 assumed if not specified' },
|
---|
357 | Differential => {
|
---|
358 | Name => 'GPSDifferential',
|
---|
359 | Writable => 'int8u',
|
---|
360 | PrintConv => {
|
---|
361 | 0 => 'No Correction',
|
---|
362 | 1 => 'Differential Corrected',
|
---|
363 | },
|
---|
364 | },
|
---|
365 | Distance => {
|
---|
366 | Name => 'GPSDestDistance',
|
---|
367 | Writable => 'rational64s',
|
---|
368 | Units => [ qw(km mi nmi) ],
|
---|
369 | Notes => q{'km' unless 'mi' or 'nmi' specified},
|
---|
370 | },
|
---|
371 | Heading => {
|
---|
372 | Name => 'GPSTrack',
|
---|
373 | Writable => 'rational64s',
|
---|
374 | Units => [ qw(deg deg{mag}) ],
|
---|
375 | Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
|
---|
376 | },
|
---|
377 | Latitude => {
|
---|
378 | Name => 'GPSLatitude',
|
---|
379 | Writable => 'rational64s',
|
---|
380 | Count => -1,
|
---|
381 | Notes => q{
|
---|
382 | 1 to 3 numbers: degrees, minutes then seconds. South latitudes are stored
|
---|
383 | as all negative numbers, but may be entered as positive numbers with a
|
---|
384 | trailing 'S' for convenience. For example, these are all equivalent: "-40
|
---|
385 | -30", "-40.5", "40 30 0.00 S"
|
---|
386 | },
|
---|
387 | ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
---|
388 | ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)',
|
---|
389 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
---|
390 | PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
---|
391 | },
|
---|
392 | Longitude => {
|
---|
393 | Name => 'GPSLongitude',
|
---|
394 | Writable => 'rational64s',
|
---|
395 | Count => -1,
|
---|
396 | Notes => q{
|
---|
397 | 1 to 3 numbers: degrees, minutes then seconds. West longitudes are
|
---|
398 | negative, but may be entered as positive numbers with a trailing 'W'
|
---|
399 | },
|
---|
400 | ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
---|
401 | ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)',
|
---|
402 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
---|
403 | PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
---|
404 | },
|
---|
405 | MeasureMode => {
|
---|
406 | Name => 'GPSMeasureMode',
|
---|
407 | Writable => 'int8u',
|
---|
408 | PrintConv => { 2 => '2-D', 3 => '3-D' },
|
---|
409 | },
|
---|
410 | Satellites => 'GPSSatellites',
|
---|
411 | Speed => {
|
---|
412 | Name => 'GPSSpeed',
|
---|
413 | Writable => 'rational64s',
|
---|
414 | Units => [ qw(km/h mi/h m/s kn) ],
|
---|
415 | Notes => q{'km/h' unless 'mi/h', 'm/s' or 'kn' specified},
|
---|
416 | },
|
---|
417 | DateTime => { Name => 'GPSDateTime', Groups => { 2 => 'Time' }, %dateInfo },
|
---|
418 | );
|
---|
419 |
|
---|
420 | # MIE UTM information
|
---|
421 | %Image::ExifTool::MIE::UTM = (
|
---|
422 | %tableDefaults,
|
---|
423 | GROUPS => { 1 => 'MIE-UTM', 2 => 'Location' },
|
---|
424 | WRITE_GROUP => 'MIE-UTM',
|
---|
425 | Datum => { Name => 'UTMMapDatum', Notes => 'WGS-84 assumed if not specified' },
|
---|
426 | Easting => { Name => 'UTMEasting' },
|
---|
427 | Northing => { Name => 'UTMNorthing' },
|
---|
428 | Zone => { Name => 'UTMZone', Writable => 'int8s' },
|
---|
429 | );
|
---|
430 |
|
---|
431 | # MIE image information
|
---|
432 | %Image::ExifTool::MIE::Image = (
|
---|
433 | %tableDefaults,
|
---|
434 | GROUPS => { 1 => 'MIE-Image', 2 => 'Image' },
|
---|
435 | WRITE_GROUP => 'MIE-Image',
|
---|
436 | '0Type' => { Name => 'FullSizeImageType', Notes => 'JPEG if not specified' },
|
---|
437 | '1Name' => { Name => 'FullSizeImageName' },
|
---|
438 | BitDepth => { Name => 'BitDepth', Writable => 'int16u' },
|
---|
439 | ColorSpace => { Notes => 'standard ColorSpace values are "sRGB" and "Adobe RGB"' },
|
---|
440 | Components => {
|
---|
441 | Name => 'ComponentsConfiguration',
|
---|
442 | Notes => 'string composed of R, G, B, Y, Cb and Cr',
|
---|
443 | },
|
---|
444 | Compression => { Name => 'CompressionRatio', Writable => 'rational32u' },
|
---|
445 | ImageSize => {
|
---|
446 | Writable => 'int16u',
|
---|
447 | Count => -1,
|
---|
448 | Notes => '2 or 3 values, for number of XY or XYZ pixels',
|
---|
449 | PrintConv => '$val=~tr/ /x/;$val',
|
---|
450 | PrintConvInv => '$val=~tr/x/ /;$val',
|
---|
451 | },
|
---|
452 | Resolution => {
|
---|
453 | Writable => 'rational64u',
|
---|
454 | Units => [ qw(/in /cm /deg /arcmin /arcsec), '' ],
|
---|
455 | Count => -1,
|
---|
456 | Notes => q{
|
---|
457 | 1 to 3 values. A single value for equal resolution in all directions, or
|
---|
458 | separate X, Y and Z values if necessary. Units are '/in' unless '/cm',
|
---|
459 | '/deg', '/arcmin', '/arcsec' or '' specified
|
---|
460 | },
|
---|
461 | PrintConv => '$val=~tr/ /x/;$val',
|
---|
462 | PrintConvInv => '$val=~tr/x/ /;$val',
|
---|
463 | },
|
---|
464 | data => {
|
---|
465 | Name => 'FullSizeImage',
|
---|
466 | %binaryConv,
|
---|
467 | RawConv => '$self->ValidateImage(\$val,$tag)',
|
---|
468 | },
|
---|
469 | );
|
---|
470 |
|
---|
471 | # MIE preview image
|
---|
472 | %Image::ExifTool::MIE::Preview = (
|
---|
473 | %tableDefaults,
|
---|
474 | GROUPS => { 1 => 'MIE-Preview', 2 => 'Image' },
|
---|
475 | WRITE_GROUP => 'MIE-Preview',
|
---|
476 | '0Type' => { Name => 'PreviewImageType', Notes => 'JPEG if not specified' },
|
---|
477 | '1Name' => { Name => 'PreviewImageName' },
|
---|
478 | ImageSize => {
|
---|
479 | Name => 'PreviewImageSize',
|
---|
480 | Writable => 'int16u',
|
---|
481 | Count => -1,
|
---|
482 | Notes => '2 or 3 values, for number of XY or XYZ pixels',
|
---|
483 | PrintConv => '$val=~tr/ /x/;$val',
|
---|
484 | PrintConvInv => '$val=~tr/x/ /;$val',
|
---|
485 | },
|
---|
486 | data => {
|
---|
487 | Name => 'PreviewImage',
|
---|
488 | %binaryConv,
|
---|
489 | RawConv => '$self->ValidateImage(\$val,$tag)',
|
---|
490 | },
|
---|
491 | );
|
---|
492 |
|
---|
493 | # MIE thumbnail image
|
---|
494 | %Image::ExifTool::MIE::Thumbnail = (
|
---|
495 | %tableDefaults,
|
---|
496 | GROUPS => { 1 => 'MIE-Thumbnail', 2 => 'Image' },
|
---|
497 | WRITE_GROUP => 'MIE-Thumbnail',
|
---|
498 | '0Type' => { Name => 'ThumbnailImageType', Notes => 'JPEG if not specified' },
|
---|
499 | '1Name' => { Name => 'ThumbnailImageName' },
|
---|
500 | ImageSize => {
|
---|
501 | Name => 'ThumbnailImageSize',
|
---|
502 | Writable => 'int16u',
|
---|
503 | Count => -1,
|
---|
504 | Notes => '2 or 3 values, for number of XY or XYZ pixels',
|
---|
505 | PrintConv => '$val=~tr/ /x/;$val',
|
---|
506 | PrintConvInv => '$val=~tr/x/ /;$val',
|
---|
507 | },
|
---|
508 | data => {
|
---|
509 | Name => 'ThumbnailImage',
|
---|
510 | %binaryConv,
|
---|
511 | RawConv => '$self->ValidateImage(\$val,$tag)',
|
---|
512 | },
|
---|
513 | );
|
---|
514 |
|
---|
515 | # MIE audio information
|
---|
516 | %Image::ExifTool::MIE::Audio = (
|
---|
517 | %tableDefaults,
|
---|
518 | GROUPS => { 1 => 'MIE-Audio', 2 => 'Audio' },
|
---|
519 | WRITE_GROUP => 'MIE-Audio',
|
---|
520 | NOTES => q{
|
---|
521 | For the Audio group (and any other group containing a 'data' element), tags
|
---|
522 | refer to the contained data if present, otherwise they refer to the main
|
---|
523 | SubfileData. The C<0Type> and C<1Name> elements should exist only if C<data>
|
---|
524 | is present.
|
---|
525 | },
|
---|
526 | '0Type' => { Name => 'RelatedAudioFileType', Notes => 'MP3 if not specified' },
|
---|
527 | '1Name' => { Name => 'RelatedAudioFileName' },
|
---|
528 | SampleBits => { Writable => 'int16u' },
|
---|
529 | Channels => { Writable => 'int8u' },
|
---|
530 | Compression => { Name => 'AudioCompression' },
|
---|
531 | Duration => { Writable => 'rational64u', PrintConv => 'ConvertDuration($val)' },
|
---|
532 | SampleRate => { Writable => 'int32u' },
|
---|
533 | data => { Name => 'RelatedAudioFile', %binaryConv },
|
---|
534 | );
|
---|
535 |
|
---|
536 | # MIE video information
|
---|
537 | %Image::ExifTool::MIE::Video = (
|
---|
538 | %tableDefaults,
|
---|
539 | GROUPS => { 1 => 'MIE-Video', 2 => 'Video' },
|
---|
540 | WRITE_GROUP => 'MIE-Video',
|
---|
541 | '0Type' => { Name => 'RelatedVideoFileType', Notes => 'MOV if not specified' },
|
---|
542 | '1Name' => { Name => 'RelatedVideoFileName' },
|
---|
543 | Codec => { },
|
---|
544 | Duration => { Writable => 'rational64u', PrintConv => 'ConvertDuration($val)' },
|
---|
545 | data => { Name => 'RelatedVideoFile', %binaryConv },
|
---|
546 | );
|
---|
547 |
|
---|
548 | # MIE camera information
|
---|
549 | %Image::ExifTool::MIE::Camera = (
|
---|
550 | %tableDefaults,
|
---|
551 | GROUPS => { 1 => 'MIE-Camera', 2 => 'Camera' },
|
---|
552 | WRITE_GROUP => 'MIE-Camera',
|
---|
553 | Brightness => { Writable => 'int8s' },
|
---|
554 | ColorTemperature=> { Writable => 'int32u' },
|
---|
555 | ColorBalance => {
|
---|
556 | Writable => 'rational64u',
|
---|
557 | Count => 3,
|
---|
558 | Notes => 'RGB scaling factors',
|
---|
559 | },
|
---|
560 | Contrast => { Writable => 'int8s' },
|
---|
561 | DigitalZoom => { Writable => 'rational64u' },
|
---|
562 | ExposureComp => { Name => 'ExposureCompensation', Writable => 'rational64s' },
|
---|
563 | ExposureMode => { },
|
---|
564 | ExposureTime => {
|
---|
565 | Writable => 'rational64u',
|
---|
566 | PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
---|
567 | PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
|
---|
568 | },
|
---|
569 | Flash => {
|
---|
570 | SubDirectory => {
|
---|
571 | TagTable => 'Image::ExifTool::MIE::Flash',
|
---|
572 | DirName => 'MIE-Flash',
|
---|
573 | },
|
---|
574 | },
|
---|
575 | FirmwareVersion => { },
|
---|
576 | FocusMode => { },
|
---|
577 | ISO => { Writable => 'int16u' },
|
---|
578 | ISOSetting => {
|
---|
579 | Writable => 'int16u',
|
---|
580 | Notes => '0 = Auto, otherwise manual ISO speed setting',
|
---|
581 | },
|
---|
582 | ImageNumber => { Writable => 'int32u' },
|
---|
583 | ImageQuality => { Notes => 'Economy, Normal, Fine, Super Fine or Raw' },
|
---|
584 | ImageStabilization => { Writable => 'int8u', %offOn },
|
---|
585 | Lens => {
|
---|
586 | SubDirectory => {
|
---|
587 | TagTable => 'Image::ExifTool::MIE::Lens',
|
---|
588 | DirName => 'MIE-Lens',
|
---|
589 | },
|
---|
590 | },
|
---|
591 | Make => { },
|
---|
592 | MeasuredEV => { Writable => 'rational64s' },
|
---|
593 | Model => { },
|
---|
594 | OwnerName => { },
|
---|
595 | Orientation => {
|
---|
596 | SubDirectory => {
|
---|
597 | TagTable => 'Image::ExifTool::MIE::Orient',
|
---|
598 | DirName => 'MIE-Orient',
|
---|
599 | },
|
---|
600 | },
|
---|
601 | Saturation => { Writable => 'int8s' },
|
---|
602 | SensorSize => {
|
---|
603 | Writable => 'rational64u',
|
---|
604 | Count => 2,
|
---|
605 | Notes => 'width and height of active sensor area in mm',
|
---|
606 | },
|
---|
607 | SerialNumber => { },
|
---|
608 | Sharpness => { Writable => 'int8s' },
|
---|
609 | ShootingMode => { },
|
---|
610 | );
|
---|
611 |
|
---|
612 | # Camera orientation information
|
---|
613 | %Image::ExifTool::MIE::Orient = (
|
---|
614 | %tableDefaults,
|
---|
615 | GROUPS => { 1 => 'MIE-Orient', 2 => 'Camera' },
|
---|
616 | WRITE_GROUP => 'MIE-Orient',
|
---|
617 | NOTES => 'These tags describe the camera orientation.',
|
---|
618 | Azimuth => {
|
---|
619 | Writable => 'rational64s',
|
---|
620 | Units => [ qw(deg deg{mag}) ],
|
---|
621 | Notes => q{'deg' CW from true north unless 'deg{mag}' specified},
|
---|
622 | },
|
---|
623 | Declination => { Writable => 'rational64s' },
|
---|
624 | Elevation => { Writable => 'rational64s' },
|
---|
625 | RightAscension => { Writable => 'rational64s' },
|
---|
626 | Rotation => {
|
---|
627 | Writable => 'rational64s',
|
---|
628 | Notes => 'CW rotation angle of camera about lens axis',
|
---|
629 | },
|
---|
630 | );
|
---|
631 |
|
---|
632 | # MIE camera lens information
|
---|
633 | %Image::ExifTool::MIE::Lens = (
|
---|
634 | %tableDefaults,
|
---|
635 | GROUPS => { 1 => 'MIE-Lens', 2 => 'Camera' },
|
---|
636 | WRITE_GROUP => 'MIE-Lens',
|
---|
637 | NOTES => q{
|
---|
638 | All recorded lens parameters (focal length, aperture, etc) include the
|
---|
639 | effects of the extender if present.
|
---|
640 | },
|
---|
641 | Extender => {
|
---|
642 | SubDirectory => {
|
---|
643 | TagTable => 'Image::ExifTool::MIE::Extender',
|
---|
644 | DirName => 'MIE-Extender',
|
---|
645 | },
|
---|
646 | },
|
---|
647 | FNumber => { Writable => 'rational64u' },
|
---|
648 | FocalLength => { Writable => 'rational64u', Notes => 'all focal lengths in mm' },
|
---|
649 | FocusDistance => {
|
---|
650 | Writable => 'rational64u',
|
---|
651 | Units => [ qw(m ft) ],
|
---|
652 | Notes => q{'m' unless 'ft' specified},
|
---|
653 | },
|
---|
654 | Make => { Name => 'LensMake' },
|
---|
655 | MaxAperture => { Writable => 'rational64u' },
|
---|
656 | MaxApertureAtMaxFocal => { Writable => 'rational64u' },
|
---|
657 | MaxFocalLength => { Writable => 'rational64u' },
|
---|
658 | MinAperture => { Writable => 'rational64u' },
|
---|
659 | MinFocalLength => { Writable => 'rational64u' },
|
---|
660 | Model => { Name => 'LensModel' },
|
---|
661 | OpticalZoom => { Writable => 'rational64u' },
|
---|
662 | SerialNumber => { Name => 'LensSerialNumber' },
|
---|
663 | );
|
---|
664 |
|
---|
665 | # MIE lens extender information
|
---|
666 | %Image::ExifTool::MIE::Extender = (
|
---|
667 | %tableDefaults,
|
---|
668 | GROUPS => { 1 => 'MIE-Extender', 2 => 'Camera' },
|
---|
669 | WRITE_GROUP => 'MIE-Extender',
|
---|
670 | Magnification => { Name => 'ExtenderMagnification', Writable => 'rational64s' },
|
---|
671 | Make => { Name => 'ExtenderMake' },
|
---|
672 | Model => { Name => 'ExtenderModel' },
|
---|
673 | SerialNumber => { Name => 'ExtenderSerialNumber' },
|
---|
674 | );
|
---|
675 |
|
---|
676 | # MIE camera flash information
|
---|
677 | %Image::ExifTool::MIE::Flash = (
|
---|
678 | %tableDefaults,
|
---|
679 | GROUPS => { 1 => 'MIE-Flash', 2 => 'Camera' },
|
---|
680 | WRITE_GROUP => 'MIE-Flash',
|
---|
681 | ExposureComp => { Name => 'FlashExposureComp', Writable => 'rational64s' },
|
---|
682 | Fired => { Name => 'FlashFired', Writable => 'int8u', PrintConv => \%noYes },
|
---|
683 | GuideNumber => { Name => 'FlashGuideNumber' },
|
---|
684 | Make => { Name => 'FlashMake' },
|
---|
685 | Mode => { Name => 'FlashMode' },
|
---|
686 | Model => { Name => 'FlashModel' },
|
---|
687 | SerialNumber => { Name => 'FlashSerialNumber' },
|
---|
688 | Type => { Name => 'FlashType', Notes => '"Internal" or "External"' },
|
---|
689 | );
|
---|
690 |
|
---|
691 | # MIE maker notes information
|
---|
692 | %Image::ExifTool::MIE::MakerNotes = (
|
---|
693 | %tableDefaults,
|
---|
694 | GROUPS => { 1 => 'MIE-MakerNotes' },
|
---|
695 | WRITE_GROUP => 'MIE-MakerNotes',
|
---|
696 | NOTES => q{
|
---|
697 | MIE maker notes are contained within separate groups for each manufacturer
|
---|
698 | to avoid name conflicts.
|
---|
699 | },
|
---|
700 | Canon => {
|
---|
701 | SubDirectory => {
|
---|
702 | TagTable => 'Image::ExifTool::MIE::Canon',
|
---|
703 | DirName => 'MIE-Canon',
|
---|
704 | },
|
---|
705 | },
|
---|
706 | Casio => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
707 | FujiFilm => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
708 | Kodak => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
709 | KonicaMinolta=>{ SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
710 | Nikon => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
711 | Olympus => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
712 | Panasonic => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
713 | Pentax => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
714 | Ricoh => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
715 | Sigma => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
716 | Sony => { SubDirectory => { TagTable => 'Image::ExifTool::MIE::Unknown' } },
|
---|
717 | );
|
---|
718 |
|
---|
719 | # MIE Canon-specific information
|
---|
720 | %Image::ExifTool::MIE::Canon = (
|
---|
721 | %tableDefaults,
|
---|
722 | GROUPS => { 1 => 'MIE-Canon' },
|
---|
723 | WRITE_GROUP => 'MIE-Canon',
|
---|
724 | VRD => {
|
---|
725 | Name => 'CanonVRD',
|
---|
726 | SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Main' },
|
---|
727 | },
|
---|
728 | );
|
---|
729 |
|
---|
730 | %Image::ExifTool::MIE::Unknown = (
|
---|
731 | PROCESS_PROC => \&ProcessMIE,
|
---|
732 | GROUPS => { 1 => 'MIE-Unknown' },
|
---|
733 | );
|
---|
734 |
|
---|
735 | #------------------------------------------------------------------------------
|
---|
736 | # Add user-defined MIE groups to %mieMap
|
---|
737 | # Inputs: none; Returns: nothing, but sets $doneMieMap flag
|
---|
738 | sub UpdateMieMap()
|
---|
739 | {
|
---|
740 | $doneMieMap = 1; # set flag so we only do this once
|
---|
741 | return unless %Image::ExifTool::UserDefined;
|
---|
742 | my ($tableName, @tables, %doneTable, $tagID);
|
---|
743 | # get list of top-level MIE tables with user-defined tags
|
---|
744 | foreach $tableName (keys %Image::ExifTool::UserDefined) {
|
---|
745 | next unless $tableName =~ /^Image::ExifTool::MIE::/;
|
---|
746 | my $userTable = $Image::ExifTool::UserDefined{$tableName};
|
---|
747 | my $tagTablePtr = GetTagTable($tableName) or next;
|
---|
748 | # copy the WRITE_GROUP from the actual table
|
---|
749 | $$userTable{WRITE_GROUP} = $$tagTablePtr{WRITE_GROUP};
|
---|
750 | # add to list of tables to process
|
---|
751 | $doneTable{$tableName} = 1;
|
---|
752 | push @tables, [$tableName, $userTable];
|
---|
753 | }
|
---|
754 | # recursively add all user-defined groups to MIE map
|
---|
755 | while (@tables) {
|
---|
756 | my ($tableName, $tagTablePtr) = @{shift @tables};
|
---|
757 | my $parent = $$tagTablePtr{WRITE_GROUP};
|
---|
758 | $parent or warn("No WRITE_GROUP for $tableName\n"), next;
|
---|
759 | $mieMap{$parent} or warn("$parent is not in MIE map\n"), next;
|
---|
760 | foreach $tagID (TagTableKeys($tagTablePtr)) {
|
---|
761 | my $tagInfo = $$tagTablePtr{$tagID};
|
---|
762 | next unless ref $tagInfo eq 'HASH' and $$tagInfo{SubDirectory};
|
---|
763 | my $subTableName = $tagInfo->{SubDirectory}->{TagTable};
|
---|
764 | my $subTablePtr = GetTagTable($subTableName) or next;
|
---|
765 | # only care about MIE tables
|
---|
766 | next unless $$subTablePtr{PROCESS_PROC} and
|
---|
767 | $$subTablePtr{PROCESS_PROC} eq \&ProcessMIE;
|
---|
768 | my $group = $$subTablePtr{WRITE_GROUP};
|
---|
769 | $group or warn("No WRITE_GROUP for $subTableName\n"), next;
|
---|
770 | if ($mieMap{$group} and $mieMap{$group} ne $parent) {
|
---|
771 | warn("$group already has different parent ($mieMap{$group})\n"), next;
|
---|
772 | }
|
---|
773 | $mieMap{$group} = $parent; # add to map
|
---|
774 | # process tables within this one too
|
---|
775 | $doneTable{$subTableName} and next;
|
---|
776 | $doneTable{$subTableName} = 1;
|
---|
777 | push @tables, [$subTableName, $subTablePtr];
|
---|
778 | }
|
---|
779 | }
|
---|
780 | }
|
---|
781 |
|
---|
782 | #------------------------------------------------------------------------------
|
---|
783 | # Get localized version of tagInfo hash
|
---|
784 | # Inputs: 0) tagInfo hash ref, 1) locale code (ie. "en_CA")
|
---|
785 | # Returns: new tagInfo hash ref, or undef if invalid
|
---|
786 | sub GetLangInfo($$)
|
---|
787 | {
|
---|
788 | my ($tagInfo, $langCode) = @_;
|
---|
789 | # check for properly formatted language code
|
---|
790 | return undef unless $langCode =~ /^[a-z]{2}([-_])[A-Z]{2}$/;
|
---|
791 | # use '_' as a separator, but recognize '_' or '-'
|
---|
792 | $langCode =~ tr/-/_/ if $1 eq '-';
|
---|
793 | # can only set locale on string types
|
---|
794 | return undef if $$tagInfo{Writable} and $$tagInfo{Writable} ne 'string';
|
---|
795 | return Image::ExifTool::GetLangInfo($tagInfo, $langCode);
|
---|
796 | }
|
---|
797 |
|
---|
798 | #------------------------------------------------------------------------------
|
---|
799 | # return true if we have Zlib::Compress
|
---|
800 | # Inputs: 0) ExifTool object ref, 1) verb for what you want to do with the info
|
---|
801 | # Returns: 1 if Zlib available, 0 otherwise
|
---|
802 | sub HasZlib($$)
|
---|
803 | {
|
---|
804 | unless (defined $hasZlib) {
|
---|
805 | $hasZlib = eval 'require Compress::Zlib';
|
---|
806 | unless ($hasZlib) {
|
---|
807 | $hasZlib = 0;
|
---|
808 | $_[0]->Warn("Install Compress::Zlib to $_[1] compressed information");
|
---|
809 | }
|
---|
810 | }
|
---|
811 | return $hasZlib;
|
---|
812 | }
|
---|
813 |
|
---|
814 | #------------------------------------------------------------------------------
|
---|
815 | # Get format code for MIE group element with current byte order
|
---|
816 | # Inputs: 0) [optional] true to convert result to chr()
|
---|
817 | # Returns: format code
|
---|
818 | sub MIEGroupFormat(;$)
|
---|
819 | {
|
---|
820 | my $chr = shift;
|
---|
821 | my $format = GetByteOrder() eq 'MM' ? 0x10 : 0x18;
|
---|
822 | return $chr ? chr($format) : $format;
|
---|
823 | }
|
---|
824 |
|
---|
825 | #------------------------------------------------------------------------------
|
---|
826 | # ReadValue() with added support for UTF formats (utf8, utf16 and utf32)
|
---|
827 | # Inputs: 0) data reference, 1) value offset, 2) format string,
|
---|
828 | # 3) number of values (or undef to use all data)
|
---|
829 | # 4) valid data length relative to offset
|
---|
830 | # Returns: converted value, or undefined if data isn't there
|
---|
831 | # or list of values in list context
|
---|
832 | # Notes: all string formats are converted to UTF8
|
---|
833 | sub ReadMIEValue($$$$$)
|
---|
834 | {
|
---|
835 | my ($dataPt, $offset, $format, $count, $size) = @_;
|
---|
836 | my $val;
|
---|
837 | if ($format =~ /^(utf(8|16|32)|string)/) {
|
---|
838 | if ($1 eq 'utf8' or $1 eq 'string') {
|
---|
839 | # read the 8-bit string
|
---|
840 | $val = substr($$dataPt, $offset, $size);
|
---|
841 | # (as of ExifTool 7.62, leave string values unconverted)
|
---|
842 | } else {
|
---|
843 | # convert to UTF8
|
---|
844 | my $fmt;
|
---|
845 | if (GetByteOrder() eq 'MM') {
|
---|
846 | $fmt = ($1 eq 'utf16') ? 'n' : 'N';
|
---|
847 | } else {
|
---|
848 | $fmt = ($1 eq 'utf16') ? 'v' : 'V';
|
---|
849 | }
|
---|
850 | my @unpk = unpack("x$offset$fmt$size",$$dataPt);
|
---|
851 | if ($] >= 5.006001) {
|
---|
852 | $val = pack('C0U*', @unpk);
|
---|
853 | } else {
|
---|
854 | $val = Image::ExifTool::PackUTF8(@unpk);
|
---|
855 | }
|
---|
856 | }
|
---|
857 | # truncate at null unless this is a list
|
---|
858 | # (strings shouldn't have a null, but just in case)
|
---|
859 | $val =~ s/\0.*//s unless $format =~ /_list$/;
|
---|
860 | } else {
|
---|
861 | $format = 'undef' if $format eq 'free'; # read 'free' as 'undef'
|
---|
862 | return ReadValue($dataPt, $offset, $format, $count, $size);
|
---|
863 | }
|
---|
864 | return $val;
|
---|
865 | }
|
---|
866 |
|
---|
867 | #------------------------------------------------------------------------------
|
---|
868 | # validate raw values for writing
|
---|
869 | # Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref
|
---|
870 | # Returns: error string or undef (and possibly changes value) on success
|
---|
871 | sub CheckMIE($$$)
|
---|
872 | {
|
---|
873 | my ($exifTool, $tagInfo, $valPtr) = @_;
|
---|
874 | my $format = $$tagInfo{Writable} || $tagInfo->{Table}->{WRITABLE};
|
---|
875 | my $err;
|
---|
876 |
|
---|
877 | return 'No writable format' if not $format or $format eq '1';
|
---|
878 | # handle units if supported by this tag
|
---|
879 | my $ulist = $$tagInfo{Units};
|
---|
880 | if ($ulist and $$valPtr =~ /(.*)\((.*)\)$/) {
|
---|
881 | my ($val, $units) = ($1, $2);
|
---|
882 | ($units) = grep /^$units$/i, @$ulist;
|
---|
883 | defined $units or return 'Allowed units: (' . join('|', @$ulist) . ')';
|
---|
884 | $err = Image::ExifTool::CheckValue(\$val, $format, $$tagInfo{Count});
|
---|
885 | # add units back onto value
|
---|
886 | $$valPtr = "$val($units)" unless $err;
|
---|
887 | } elsif ($format !~ /^(utf|string|undef)/ and $$valPtr =~ /\)$/) {
|
---|
888 | return 'Units not supported';
|
---|
889 | } else {
|
---|
890 | if ($format eq 'string' and $exifTool->{OPTIONS}->{Charset} ne 'UTF8' and
|
---|
891 | $$valPtr =~ /[\x80-\xff]/)
|
---|
892 | {
|
---|
893 | # convert from Charset to UTF-8
|
---|
894 | $$valPtr = $exifTool->Encode($$valPtr,'UTF8');
|
---|
895 | }
|
---|
896 | $err = Image::ExifTool::CheckValue($valPtr, $format, $$tagInfo{Count});
|
---|
897 | }
|
---|
898 | return $err;
|
---|
899 | }
|
---|
900 |
|
---|
901 | #------------------------------------------------------------------------------
|
---|
902 | # Rewrite a MIE directory
|
---|
903 | # Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ptr
|
---|
904 | # Returns: undef on success, otherwise error message (empty message if nothing to write)
|
---|
905 | sub WriteMIEGroup($$$)
|
---|
906 | {
|
---|
907 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
908 | my $outfile = $$dirInfo{OutFile};
|
---|
909 | my $dirName = $$dirInfo{DirName};
|
---|
910 | my $toWrite = $$dirInfo{ToWrite} || '';
|
---|
911 | my $raf = $$dirInfo{RAF};
|
---|
912 | my $verbose = $exifTool->Options('Verbose');
|
---|
913 | my $optCompress = $exifTool->Options('Compress');
|
---|
914 | my $out = $exifTool->Options('TextOut');
|
---|
915 | my ($msg, $err, $ok, $sync, $delGroup);
|
---|
916 | my $tag = '';
|
---|
917 | my $deletedTag = '';
|
---|
918 |
|
---|
919 | # count each MIE directory found and make name for this specific instance
|
---|
920 | my ($grp1, %isWriting);
|
---|
921 | my $cnt = $exifTool->{MIE_COUNT};
|
---|
922 | my $grp = $tagTablePtr->{GROUPS}->{1};
|
---|
923 | my $n = $$cnt{'MIE-Main'} || 0;
|
---|
924 | if ($grp eq 'MIE-Main') {
|
---|
925 | $$cnt{$grp} = ++$n;
|
---|
926 | ($grp1 = $grp) =~ s/MIE-/MIE$n-/;
|
---|
927 | } else {
|
---|
928 | ($grp1 = $grp) =~ s/MIE-/MIE$n-/;
|
---|
929 | my $m = $$cnt{$grp1} = ($$cnt{$grp1} || 0) + 1;
|
---|
930 | $isWriting{"$grp$m"} = 1; # ie. 'MIE-Doc2'
|
---|
931 | $isWriting{$grp1} = 1; # ie. 'MIE1-Doc'
|
---|
932 | $grp1 .= $m;
|
---|
933 | }
|
---|
934 | # build lookup for all valid group names for this MIE group
|
---|
935 | $isWriting{$grp} = 1; # ie. 'MIE-Doc'
|
---|
936 | $isWriting{$grp1} = 1; # ie. 'MIE1-Doc2'
|
---|
937 | $isWriting{"MIE$n"} = 1; # ie. 'MIE1'
|
---|
938 |
|
---|
939 | # determine if we are deleting this group
|
---|
940 | if (%{$exifTool->{DEL_GROUP}}) {
|
---|
941 | $delGroup = 1 if $exifTool->{DEL_GROUP}->{MIE} or
|
---|
942 | $exifTool->{DEL_GROUP}->{$grp} or
|
---|
943 | $exifTool->{DEL_GROUP}->{$grp1} or
|
---|
944 | $exifTool->{DEL_GROUP}->{"MIE$n"};
|
---|
945 | }
|
---|
946 |
|
---|
947 | # prepare lookups and lists for writing
|
---|
948 | my $newTags = $exifTool->GetNewTagInfoHash($tagTablePtr);
|
---|
949 | my ($addDirs, $editDirs) = $exifTool->GetAddDirHash($tagTablePtr, $dirName);
|
---|
950 | my @editTags = sort keys %$newTags, keys %$editDirs;
|
---|
951 | $verbose and print $out $raf ? 'Writing' : 'Creating', " $grp1:\n";
|
---|
952 |
|
---|
953 | # loop through elements in MIE group
|
---|
954 | MieElement: for (;;) {
|
---|
955 | my ($format, $tagLen, $valLen, $units, $oldHdr, $buff);
|
---|
956 | my $lastTag = $tag;
|
---|
957 | if ($raf) {
|
---|
958 | # read first 4 bytes of element header
|
---|
959 | my $n = $raf->Read($oldHdr, 4);
|
---|
960 | if ($n != 4) {
|
---|
961 | last if $n or defined $sync;
|
---|
962 | undef $raf; # all done reading
|
---|
963 | $ok = 1;
|
---|
964 | }
|
---|
965 | }
|
---|
966 | if ($raf) {
|
---|
967 | ($sync, $format, $tagLen, $valLen) = unpack('aC3', $oldHdr);
|
---|
968 | $sync eq '~' or $msg = 'Invalid sync byte', last;
|
---|
969 |
|
---|
970 | # read tag name
|
---|
971 | if ($tagLen) {
|
---|
972 | $raf->Read($tag, $tagLen) == $tagLen or last;
|
---|
973 | $oldHdr .= $tag; # add tag to element header
|
---|
974 | $exifTool->Warn("MIE tag '$tag' out of sequence") if $tag lt $lastTag;
|
---|
975 | # separate units from tag name if they exist
|
---|
976 | $units = $1 if $tag =~ s/\((.*)\)$//;
|
---|
977 | } else {
|
---|
978 | $tag = '';
|
---|
979 | }
|
---|
980 |
|
---|
981 | # get multi-byte value length if necessary
|
---|
982 | if ($valLen > 252) {
|
---|
983 | # calculate number of bytes in extended DataLength
|
---|
984 | my $n = 1 << (256 - $valLen);
|
---|
985 | $raf->Read($buff, $n) == $n or last;
|
---|
986 | $oldHdr .= $buff; # add to old header
|
---|
987 | my $fmt = 'int' . ($n * 8) . 'u';
|
---|
988 | $valLen = ReadValue(\$buff, 0, $fmt, 1, $n);
|
---|
989 | if ($valLen > 0x7fffffff) {
|
---|
990 | $msg = "Can't write $tag (DataLength > 2GB not yet supported)";
|
---|
991 | last;
|
---|
992 | }
|
---|
993 | }
|
---|
994 | # don't rewrite free bytes or information in deleted groups
|
---|
995 | if ($format eq 0x80 or ($delGroup and $tagLen and ($format & 0xf0) != 0x10)) {
|
---|
996 | $raf->Seek($valLen, 1) or $msg = 'Seek error', last;
|
---|
997 | if ($verbose > 1) {
|
---|
998 | my $free = ($format eq 0x80) ? ' free' : '';
|
---|
999 | print $out " - $grp1:$tag ($valLen$free bytes)\n";
|
---|
1000 | }
|
---|
1001 | ++$exifTool->{CHANGED} if $delGroup;
|
---|
1002 | next;
|
---|
1003 | }
|
---|
1004 | } else {
|
---|
1005 | # no more elements to read
|
---|
1006 | $tagLen = $valLen = 0;
|
---|
1007 | $tag = '';
|
---|
1008 | }
|
---|
1009 | #
|
---|
1010 | # write necessary new tags and process directories
|
---|
1011 | #
|
---|
1012 | while (@editTags) {
|
---|
1013 | last if $tagLen and $editTags[0] gt $tag;
|
---|
1014 | # we are writing the new tag now
|
---|
1015 | my ($newVal, $writable, $oldVal, $newFormat, $compress);
|
---|
1016 | my $newTag = shift @editTags;
|
---|
1017 | my $newInfo = $$editDirs{$newTag};
|
---|
1018 | if ($newInfo) {
|
---|
1019 | # create the new subdirectory or rewrite existing non-MIE directory
|
---|
1020 | my $subTablePtr = GetTagTable($newInfo->{SubDirectory}->{TagTable});
|
---|
1021 | unless ($subTablePtr) {
|
---|
1022 | $exifTool->Warn("No tag table for $newTag $$newInfo{Name}");
|
---|
1023 | next;
|
---|
1024 | }
|
---|
1025 | my %subdirInfo;
|
---|
1026 | my $isMieGroup = ($$subTablePtr{WRITE_PROC} and
|
---|
1027 | $$subTablePtr{WRITE_PROC} eq \&ProcessMIE);
|
---|
1028 |
|
---|
1029 | if ($newTag eq $tag) {
|
---|
1030 | # make sure that either both or neither old and new tags are MIE groups
|
---|
1031 | if ($isMieGroup xor ($format & 0xf3) == 0x10) {
|
---|
1032 | $exifTool->Warn("Tag '$tag' not expected type");
|
---|
1033 | next; # don't write our new tag
|
---|
1034 | }
|
---|
1035 | # uncompress existing directory into $oldVal since we are editing it
|
---|
1036 | if ($format & 0x04) {
|
---|
1037 | last unless HasZlib($exifTool, 'edit');
|
---|
1038 | $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
|
---|
1039 | my $stat;
|
---|
1040 | my $inflate = Compress::Zlib::inflateInit();
|
---|
1041 | $inflate and ($oldVal, $stat) = $inflate->inflate($oldVal);
|
---|
1042 | unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
|
---|
1043 | $msg = "Error inflating $tag";
|
---|
1044 | last MieElement;
|
---|
1045 | }
|
---|
1046 | $compress = 1;
|
---|
1047 | $valLen = length $oldVal; # uncompressed value length
|
---|
1048 | }
|
---|
1049 | } else {
|
---|
1050 | # don't create this directory unless necessary
|
---|
1051 | next unless $$addDirs{$newTag};
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | if ($isMieGroup) {
|
---|
1055 | my $hdr;
|
---|
1056 | if ($newTag eq $tag) {
|
---|
1057 | # rewrite existing directory later unless it was compressed
|
---|
1058 | last unless $compress;
|
---|
1059 | # rewrite directory to '$newVal'
|
---|
1060 | $newVal = '';
|
---|
1061 | %subdirInfo = (
|
---|
1062 | OutFile => \$newVal,
|
---|
1063 | RAF => new File::RandomAccess(\$oldVal),
|
---|
1064 | );
|
---|
1065 | } elsif ($optCompress and not $$dirInfo{IsCompressed}) {
|
---|
1066 | # write to memory so we can compress the new MIE group
|
---|
1067 | $compress = 1;
|
---|
1068 | %subdirInfo = (
|
---|
1069 | OutFile => \$newVal,
|
---|
1070 | );
|
---|
1071 | } else {
|
---|
1072 | $hdr = '~' . MIEGroupFormat(1) . chr(length($newTag)) .
|
---|
1073 | "\0" . $newTag;
|
---|
1074 | %subdirInfo = (
|
---|
1075 | OutFile => $outfile,
|
---|
1076 | ToWrite => $toWrite . $hdr,
|
---|
1077 | );
|
---|
1078 | }
|
---|
1079 | $subdirInfo{DirName} = $newInfo->{SubDirectory}->{DirName} || $newTag;
|
---|
1080 | $subdirInfo{Parent} = $dirName;
|
---|
1081 | # don't compress elements of an already compressed group
|
---|
1082 | $subdirInfo{IsCompressed} = 1;
|
---|
1083 | $msg = WriteMIEGroup($exifTool, \%subdirInfo, $subTablePtr);
|
---|
1084 | last MieElement if $msg;
|
---|
1085 | # message is defined but empty if nothing was written
|
---|
1086 | if (defined $msg) {
|
---|
1087 | undef $msg; # not a problem if nothing was written
|
---|
1088 | next;
|
---|
1089 | } elsif (not $compress) {
|
---|
1090 | # group was written already
|
---|
1091 | $toWrite = '';
|
---|
1092 | next;
|
---|
1093 | }
|
---|
1094 | $writable = 'undef';
|
---|
1095 | $newFormat = MIEGroupFormat();
|
---|
1096 | } else {
|
---|
1097 | if ($newTag eq $tag) {
|
---|
1098 | unless ($compress) {
|
---|
1099 | # read and edit existing directory
|
---|
1100 | $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
|
---|
1101 | }
|
---|
1102 | %subdirInfo = (
|
---|
1103 | DataPt => \$oldVal,
|
---|
1104 | DataLen => $valLen,
|
---|
1105 | DirName => $$newInfo{Name},
|
---|
1106 | DataPos => $raf->Tell() - $valLen,
|
---|
1107 | DirStart=> 0,
|
---|
1108 | DirLen => $valLen,
|
---|
1109 | );
|
---|
1110 | # write Compact subdirectories if we will compress the data
|
---|
1111 | if (($compress or $optCompress or $$dirInfo{IsCompressed}) and
|
---|
1112 | eval 'require Compress::Zlib')
|
---|
1113 | {
|
---|
1114 | $subdirInfo{Compact} = 1;
|
---|
1115 | }
|
---|
1116 | }
|
---|
1117 | $subdirInfo{Parent} = $dirName;
|
---|
1118 | my $writeProc = $newInfo->{SubDirectory}->{WriteProc};
|
---|
1119 | # reset processed lookup to avoid errors in case of multiple EXIF blocks
|
---|
1120 | $exifTool->{PROCESSED} = { };
|
---|
1121 | $newVal = $exifTool->WriteDirectory(\%subdirInfo, $subTablePtr, $writeProc);
|
---|
1122 | if (defined $newVal) {
|
---|
1123 | if ($newVal eq '') {
|
---|
1124 | next MieElement if $newTag eq $tag; # deleting the directory
|
---|
1125 | next; # not creating the new directory
|
---|
1126 | }
|
---|
1127 | } else {
|
---|
1128 | next unless defined $oldVal;
|
---|
1129 | $newVal = $oldVal; # just copy over the old directory
|
---|
1130 | }
|
---|
1131 | $writable = 'undef';
|
---|
1132 | $newFormat = 0x00; # all other directories are 'undef' format
|
---|
1133 | }
|
---|
1134 | } else {
|
---|
1135 |
|
---|
1136 | # get the new tag information
|
---|
1137 | $newInfo = $$newTags{$newTag};
|
---|
1138 | my $nvHash = $exifTool->GetNewValueHash($newInfo);
|
---|
1139 | my @newVals;
|
---|
1140 |
|
---|
1141 | # write information only to specified group
|
---|
1142 | my $writeGroup = $$nvHash{WriteGroup};
|
---|
1143 | last unless $isWriting{$writeGroup};
|
---|
1144 |
|
---|
1145 | # if tag existed, must decide if we want to overwrite the value
|
---|
1146 | if ($newTag eq $tag) {
|
---|
1147 | my $isOverwriting;
|
---|
1148 | my $isList = $$newInfo{List};
|
---|
1149 | if ($isList) {
|
---|
1150 | $isOverwriting = -1; # force processing list elements individually
|
---|
1151 | } else {
|
---|
1152 | $isOverwriting = Image::ExifTool::IsOverwriting($nvHash);
|
---|
1153 | last unless $isOverwriting;
|
---|
1154 | }
|
---|
1155 | my ($val, $cmpVal);
|
---|
1156 | if ($isOverwriting < 0 or $verbose > 1) {
|
---|
1157 | # check to be sure we can uncompress the value if necessary
|
---|
1158 | HasZlib($exifTool, 'edit') or last if $format & 0x04;
|
---|
1159 | # read the old value
|
---|
1160 | $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
|
---|
1161 | # uncompress if necessary
|
---|
1162 | if ($format & 0x04) {
|
---|
1163 | my $stat;
|
---|
1164 | my $inflate = Compress::Zlib::inflateInit();
|
---|
1165 | # must save original compressed value in case we decide
|
---|
1166 | # not to overwrite it later
|
---|
1167 | $cmpVal = $oldVal;
|
---|
1168 | $inflate and ($oldVal, $stat) = $inflate->inflate($oldVal);
|
---|
1169 | unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
|
---|
1170 | $msg = "Error inflating $tag";
|
---|
1171 | last MieElement;
|
---|
1172 | }
|
---|
1173 | $valLen = length $oldVal; # update value length
|
---|
1174 | }
|
---|
1175 | # convert according to specified format
|
---|
1176 | my $formatStr = $mieFormat{$format & 0xfb} || 'undef';
|
---|
1177 | $val = ReadMIEValue(\$oldVal, 0, $formatStr, undef, $valLen);
|
---|
1178 | if ($isOverwriting < 0 and defined $val) {
|
---|
1179 | # handle list values individually
|
---|
1180 | if ($isList) {
|
---|
1181 | my (@vals, $v);
|
---|
1182 | if ($formatStr =~ /_list$/) {
|
---|
1183 | @vals = split "\0", $val;
|
---|
1184 | } else {
|
---|
1185 | @vals = $val;
|
---|
1186 | }
|
---|
1187 | # keep any list items that we aren't overwriting
|
---|
1188 | foreach $v (@vals) {
|
---|
1189 | next if Image::ExifTool::IsOverwriting($nvHash, $v);
|
---|
1190 | push @newVals, $v;
|
---|
1191 | }
|
---|
1192 | } else {
|
---|
1193 | # test to see if we really want to overwrite the value
|
---|
1194 | $isOverwriting = Image::ExifTool::IsOverwriting($nvHash, $val);
|
---|
1195 | }
|
---|
1196 | }
|
---|
1197 | }
|
---|
1198 | if ($isOverwriting) {
|
---|
1199 | # skip the old value if we didn't read it already
|
---|
1200 | unless (defined $oldVal) {
|
---|
1201 | $raf->Seek($valLen, 1) or $msg = 'Seek error';
|
---|
1202 | }
|
---|
1203 | if ($verbose > 1) {
|
---|
1204 | $val .= "($units)" if defined $units;
|
---|
1205 | $exifTool->VerboseValue("- $grp1:$$newInfo{Name}", $val);
|
---|
1206 | }
|
---|
1207 | $deletedTag = $tag; # remember that we deleted this tag
|
---|
1208 | ++$exifTool->{CHANGED}; # we deleted the old value
|
---|
1209 | } else {
|
---|
1210 | if (defined $oldVal) {
|
---|
1211 | # write original compressed value
|
---|
1212 | $oldVal = $cmpVal if defined $cmpVal;
|
---|
1213 | } else {
|
---|
1214 | $raf->Read($oldVal, $valLen) == $valLen or last MieElement;
|
---|
1215 | }
|
---|
1216 | # write the old value now
|
---|
1217 | Write($outfile, $toWrite, $oldHdr, $oldVal) or $err = 1;
|
---|
1218 | $toWrite = '';
|
---|
1219 | }
|
---|
1220 | unless (@newVals) {
|
---|
1221 | # unshift the new tag info to write it later
|
---|
1222 | unshift @editTags, $newTag;
|
---|
1223 | next MieElement; # get next element from file
|
---|
1224 | }
|
---|
1225 | } else {
|
---|
1226 | # write new value if creating, or if List and list existed, or
|
---|
1227 | # if tag was previously deleted
|
---|
1228 | next unless Image::ExifTool::IsCreating($nvHash) or
|
---|
1229 | ($newTag eq $lastTag and ($$newInfo{List} or $deletedTag eq $lastTag));
|
---|
1230 | }
|
---|
1231 | # get the new value to write (undef to delete)
|
---|
1232 | push @newVals, Image::ExifTool::GetNewValues($nvHash);
|
---|
1233 | next unless @newVals;
|
---|
1234 | $writable = $$newInfo{Writable} || $$tagTablePtr{WRITABLE};
|
---|
1235 | if ($writable eq 'string') {
|
---|
1236 | # join multiple values into a single string
|
---|
1237 | $newVal = join "\0", @newVals;
|
---|
1238 | # write string as UTF-8,16 or 32 if value contains valid UTF-8 codes
|
---|
1239 | require Image::ExifTool::XMP;
|
---|
1240 | my $isUTF8 = Image::ExifTool::XMP::IsUTF8(\$newVal);
|
---|
1241 | if ($isUTF8 > 0) {
|
---|
1242 | $writable = 'utf8';
|
---|
1243 | # write UTF-16 or UTF-32 if it is more compact
|
---|
1244 | my $to = $isUTF8 > 1 ? 'UCS4' : 'UCS2';
|
---|
1245 | my $tmp = Image::ExifTool::Decode(undef,$newVal,'UTF8',undef,$to);
|
---|
1246 | if (length $tmp < length $newVal) {
|
---|
1247 | $newVal = $tmp;
|
---|
1248 | $writable = ($isUTF8 > 1) ? 'utf32' : 'utf16';
|
---|
1249 | }
|
---|
1250 | }
|
---|
1251 | # write as a list if we have multiple values
|
---|
1252 | $writable .= '_list' if @newVals > 1;
|
---|
1253 | } else {
|
---|
1254 | # should only be one element in the list
|
---|
1255 | $newVal = shift @newVals;
|
---|
1256 | }
|
---|
1257 | $newFormat = $mieCode{$writable};
|
---|
1258 | unless (defined $newFormat) {
|
---|
1259 | $msg = "Bad format '$writable' for $$newInfo{Name}";
|
---|
1260 | next MieElement;
|
---|
1261 | }
|
---|
1262 | }
|
---|
1263 |
|
---|
1264 | # write the new or edited element
|
---|
1265 | while (defined $newFormat) {
|
---|
1266 | my $valPt = \$newVal;
|
---|
1267 | # remove units from value and add to tag name if supported by this tag
|
---|
1268 | if ($$newInfo{Units}) {
|
---|
1269 | my $val2;
|
---|
1270 | if ($$valPt =~ /(.*)\((.*)\)$/) {
|
---|
1271 | $val2 = $1;
|
---|
1272 | $newTag .= "($2)";
|
---|
1273 | } else {
|
---|
1274 | $val2 = $$valPt;
|
---|
1275 | # add default units
|
---|
1276 | my $ustr = '(' . $newInfo->{Units}->[0] . ')';
|
---|
1277 | $newTag .= $ustr;
|
---|
1278 | $$valPt .= $ustr;
|
---|
1279 | }
|
---|
1280 | $valPt = \$val2;
|
---|
1281 | }
|
---|
1282 | # convert value if necessary
|
---|
1283 | if ($writable !~ /^(utf|string|undef)/) {
|
---|
1284 | my $val3 = WriteValue($$valPt, $writable, $$newInfo{Count});
|
---|
1285 | defined $val3 or $exifTool->Warn("Error writing $newTag"), last;
|
---|
1286 | $valPt = \$val3;
|
---|
1287 | }
|
---|
1288 | my $len = length $$valPt;
|
---|
1289 | # compress value before writing if required
|
---|
1290 | if (($compress or $optCompress) and not $$dirInfo{IsCompressed} and
|
---|
1291 | HasZlib($exifTool, 'write'))
|
---|
1292 | {
|
---|
1293 | my $deflate = Compress::Zlib::deflateInit();
|
---|
1294 | my $val4;
|
---|
1295 | if ($deflate) {
|
---|
1296 | $val4 = $deflate->deflate($$valPt);
|
---|
1297 | $val4 .= $deflate->flush() if defined $val4;
|
---|
1298 | }
|
---|
1299 | if (defined $val4) {
|
---|
1300 | my $len4 = length $val4;
|
---|
1301 | my $saved = $len - $len4;
|
---|
1302 | # only use compressed data if it is smaller
|
---|
1303 | if ($saved > 0) {
|
---|
1304 | $verbose and print $out " [$newTag compression saved $saved bytes]\n";
|
---|
1305 | $newFormat |= 0x04; # set compressed bit
|
---|
1306 | $len = $len4; # set length
|
---|
1307 | $valPt = \$val4; # set value pointer
|
---|
1308 | } elsif ($verbose) {
|
---|
1309 | print $out " [$newTag compression saved $saved bytes -- written uncompressed]\n";
|
---|
1310 | }
|
---|
1311 | } else {
|
---|
1312 | $exifTool->Warn("Error deflating $newTag (written uncompressed)");
|
---|
1313 | }
|
---|
1314 | }
|
---|
1315 | # calculate the DataLength code
|
---|
1316 | my $extLen;
|
---|
1317 | if ($len < 253) {
|
---|
1318 | $extLen = '';
|
---|
1319 | } elsif ($len < 65536) {
|
---|
1320 | $extLen = Set16u($len);
|
---|
1321 | $len = 255;
|
---|
1322 | } elsif ($len <= 0x7fffffff) {
|
---|
1323 | $extLen = Set32u($len);
|
---|
1324 | $len = 254;
|
---|
1325 | } else {
|
---|
1326 | $exifTool->Warn("Can't write $newTag (DataLength > 2GB not yet suppported)");
|
---|
1327 | last; # don't write this tag
|
---|
1328 | }
|
---|
1329 | # write this element (with leading MIE group element if not done already)
|
---|
1330 | my $hdr = $toWrite . '~' . chr($newFormat) . chr(length $newTag);
|
---|
1331 | Write($outfile, $hdr, chr($len), $newTag, $extLen, $$valPt) or $err = 1;
|
---|
1332 | $toWrite = '';
|
---|
1333 | # we changed a tag unless just editing a subdirectory
|
---|
1334 | unless ($$editDirs{$newTag}) {
|
---|
1335 | $exifTool->VerboseValue("+ $grp1:$$newInfo{Name}", $newVal);
|
---|
1336 | ++$exifTool->{CHANGED};
|
---|
1337 | }
|
---|
1338 | last; # didn't want to loop anyway
|
---|
1339 | }
|
---|
1340 | next MieElement if defined $oldVal;
|
---|
1341 | }
|
---|
1342 | #
|
---|
1343 | # rewrite existing element or descend into uncompressed MIE group
|
---|
1344 | #
|
---|
1345 | # all done this MIE group if we reached the terminator element
|
---|
1346 | unless ($tagLen) {
|
---|
1347 | # skip over existing terminator data (if any)
|
---|
1348 | last if $valLen and not $raf->Seek($valLen, 1);
|
---|
1349 | $ok = 1;
|
---|
1350 | # write group terminator if necessary
|
---|
1351 | unless ($toWrite) {
|
---|
1352 | # write end-of-group terminator element
|
---|
1353 | my $term = "~\0\0\0";
|
---|
1354 | unless ($$dirInfo{Parent}) {
|
---|
1355 | # write extended terminator for file-level group
|
---|
1356 | my $len = ref $outfile eq 'SCALAR' ? length($$outfile) : tell $outfile;
|
---|
1357 | $len += 10; # include length of terminator itself
|
---|
1358 | if ($len and $len <= 0x7fffffff) {
|
---|
1359 | $term = "~\0\0\x06" . Set32u($len) . MIEGroupFormat(1) . "\x04";
|
---|
1360 | }
|
---|
1361 | }
|
---|
1362 | Write($outfile, $term) or $err = 1;
|
---|
1363 | }
|
---|
1364 | last;
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | # descend into existing uncompressed MIE group
|
---|
1368 | if ($format == 0x10 or $format == 0x18) {
|
---|
1369 | my ($subTablePtr, $dirName);
|
---|
1370 | my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
|
---|
1371 | if ($tagInfo and $$tagInfo{SubDirectory}) {
|
---|
1372 | $dirName = $tagInfo->{SubDirectory}->{DirName};
|
---|
1373 | my $subTable = $tagInfo->{SubDirectory}->{TagTable};
|
---|
1374 | $subTablePtr = $subTable ? GetTagTable($subTable) : $tagTablePtr;
|
---|
1375 | } else {
|
---|
1376 | $subTablePtr = GetTagTable('Image::ExifTool::MIE::Unknown');
|
---|
1377 | }
|
---|
1378 | my $hdr = '~' . chr($format) . chr(length $tag) . "\0" . $tag;
|
---|
1379 | my %subdirInfo = (
|
---|
1380 | DirName => $dirName || $tag,
|
---|
1381 | RAF => $raf,
|
---|
1382 | ToWrite => $toWrite . $hdr,
|
---|
1383 | OutFile => $outfile,
|
---|
1384 | Parent => $dirName,
|
---|
1385 | IsCompressed => $$dirInfo{IsCompressed},
|
---|
1386 | );
|
---|
1387 | my $oldOrder = GetByteOrder();
|
---|
1388 | SetByteOrder($format & 0x08 ? 'II' : 'MM');
|
---|
1389 | $msg = WriteMIEGroup($exifTool, \%subdirInfo, $subTablePtr);
|
---|
1390 | SetByteOrder($oldOrder);
|
---|
1391 | last if $msg;
|
---|
1392 | if (defined $msg) {
|
---|
1393 | undef $msg; # no problem if nothing written
|
---|
1394 | } else {
|
---|
1395 | $toWrite = '';
|
---|
1396 | }
|
---|
1397 | next;
|
---|
1398 | }
|
---|
1399 | # just copy existing element
|
---|
1400 | my $oldVal;
|
---|
1401 | $raf->Read($oldVal, $valLen) == $valLen or last;
|
---|
1402 | if ($toWrite) {
|
---|
1403 | Write($outfile, $toWrite) or $err = 1;
|
---|
1404 | $toWrite = '';
|
---|
1405 | }
|
---|
1406 | Write($outfile, $oldHdr, $oldVal) or $err = 1;
|
---|
1407 | }
|
---|
1408 | # return error message
|
---|
1409 | if ($err) {
|
---|
1410 | $msg = 'Error writing file';
|
---|
1411 | } elsif (not $ok and not $msg) {
|
---|
1412 | $msg = 'Unexpected end of file';
|
---|
1413 | } elsif (not $msg and $toWrite) {
|
---|
1414 | $msg = ''; # flag for nothing written
|
---|
1415 | $verbose and print $out "Deleted $grp1 (empty)\n";
|
---|
1416 | }
|
---|
1417 | return $msg;
|
---|
1418 | }
|
---|
1419 |
|
---|
1420 | #------------------------------------------------------------------------------
|
---|
1421 | # Process MIE directory
|
---|
1422 | # Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
|
---|
1423 | # Returns: undef on success, or error message if there was a problem
|
---|
1424 | # Notes: file pointer is positioned at the MIE end on entry
|
---|
1425 | sub ProcessMIEGroup($$$)
|
---|
1426 | {
|
---|
1427 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
1428 | my $raf = $$dirInfo{RAF};
|
---|
1429 | my $verbose = $exifTool->Options('Verbose');
|
---|
1430 | my $out = $exifTool->Options('TextOut');
|
---|
1431 | my $notUTF8 = ($exifTool->{OPTIONS}->{Charset} ne 'UTF8');
|
---|
1432 | my ($msg, $buff, $ok, $oldIndent, $mime);
|
---|
1433 | my $lastTag = '';
|
---|
1434 |
|
---|
1435 | # get group 1 names: $grp doesn't have numbers (ie. 'MIE-Doc'),
|
---|
1436 | # and $grp1 does (ie. 'MIE1-Doc1')
|
---|
1437 | my $cnt = $exifTool->{MIE_COUNT};
|
---|
1438 | my $grp1 = $tagTablePtr->{GROUPS}->{1};
|
---|
1439 | my $n = $$cnt{'MIE-Main'} || 0;
|
---|
1440 | if ($grp1 eq 'MIE-Main') {
|
---|
1441 | $$cnt{$grp1} = ++$n;
|
---|
1442 | $grp1 =~ s/MIE-/MIE$n-/ if $n > 1;
|
---|
1443 | } else {
|
---|
1444 | $grp1 =~ s/MIE-/MIE$n-/ if $n > 1;
|
---|
1445 | $$cnt{$grp1} = ($$cnt{$grp1} || 0) + 1;
|
---|
1446 | $grp1 .= $$cnt{$grp1} if $$cnt{$grp1} > 1;
|
---|
1447 | }
|
---|
1448 | # set group1 name for all tags extracted from this group
|
---|
1449 | $exifTool->{SET_GROUP1} = $grp1;
|
---|
1450 |
|
---|
1451 | if ($verbose) {
|
---|
1452 | $oldIndent = $exifTool->{INDENT};
|
---|
1453 | $exifTool->{INDENT} .= '| ';
|
---|
1454 | $exifTool->VerboseDir($grp1);
|
---|
1455 | }
|
---|
1456 | my $wasCompressed = $$dirInfo{WasCompressed};
|
---|
1457 |
|
---|
1458 | # process all MIE elements
|
---|
1459 | for (;;) {
|
---|
1460 | $raf->Read($buff, 4) == 4 or last;
|
---|
1461 | my ($sync, $format, $tagLen, $valLen) = unpack('aC3', $buff);
|
---|
1462 | $sync eq '~' or $msg = 'Invalid sync byte', last;
|
---|
1463 |
|
---|
1464 | # read tag name
|
---|
1465 | my ($tag, $units);
|
---|
1466 | if ($tagLen) {
|
---|
1467 | $raf->Read($tag, $tagLen) == $tagLen or last;
|
---|
1468 | $exifTool->Warn("MIE tag '$tag' out of sequence") if $tag lt $lastTag;
|
---|
1469 | $lastTag = $tag;
|
---|
1470 | # separate units from tag name if they exist
|
---|
1471 | $units = $1 if $tag =~ s/\((.*)\)$//;
|
---|
1472 | } else {
|
---|
1473 | $tag = '';
|
---|
1474 | }
|
---|
1475 |
|
---|
1476 | # get multi-byte value length if necessary
|
---|
1477 | if ($valLen > 252) {
|
---|
1478 | my $n = 1 << (256 - $valLen);
|
---|
1479 | $raf->Read($buff, $n) == $n or last;
|
---|
1480 | my $fmt = 'int' . ($n * 8) . 'u';
|
---|
1481 | $valLen = ReadValue(\$buff, 0, $fmt, 1, $n);
|
---|
1482 | if ($valLen > 0x7fffffff) {
|
---|
1483 | $msg = "Can't read $tag (DataLength > 2GB not yet supported)";
|
---|
1484 | last;
|
---|
1485 | }
|
---|
1486 | }
|
---|
1487 |
|
---|
1488 | # all done if we reached the group terminator
|
---|
1489 | unless ($tagLen) {
|
---|
1490 | # skip over terminator data block
|
---|
1491 | $ok = 1 unless $valLen and not $raf->Seek($valLen, 1);
|
---|
1492 | last;
|
---|
1493 | }
|
---|
1494 |
|
---|
1495 | # get tag information hash unless this is free space
|
---|
1496 | my ($tagInfo, $value);
|
---|
1497 | while ($format != 0x80) {
|
---|
1498 | $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
|
---|
1499 | last if $tagInfo;
|
---|
1500 | # extract tags with locale code
|
---|
1501 | if ($tag =~ /\W/) {
|
---|
1502 | if ($tag =~ /^(\w+)-([a-z]{2}_[A-Z]{2})$/) {
|
---|
1503 | my ($baseTag, $langCode) = ($1, $2);
|
---|
1504 | $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $baseTag);
|
---|
1505 | $tagInfo = GetLangInfo($tagInfo, $langCode) if $tagInfo;
|
---|
1506 | last if $tagInfo;
|
---|
1507 | } else {
|
---|
1508 | $exifTool->Warn('Invalid MIE tag name');
|
---|
1509 | last;
|
---|
1510 | }
|
---|
1511 | }
|
---|
1512 | # extract unknown tags if specified
|
---|
1513 | $tagInfo = {
|
---|
1514 | Name => $tag,
|
---|
1515 | Writable => 0,
|
---|
1516 | PrintConv => 'length($val) > 60 ? substr($val,0,55) . "[...]" : $val',
|
---|
1517 | };
|
---|
1518 | Image::ExifTool::AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
---|
1519 | last;
|
---|
1520 | }
|
---|
1521 |
|
---|
1522 | # read value and uncompress if necessary
|
---|
1523 | my $formatStr = $mieFormat{$format & 0xfb} || 'undef';
|
---|
1524 | if ($tagInfo or ($formatStr eq 'MIE' and $format & 0x04)) {
|
---|
1525 | $raf->Read($value, $valLen) == $valLen or last;
|
---|
1526 | if ($format & 0x04) {
|
---|
1527 | if ($verbose) {
|
---|
1528 | print $out "$$exifTool{INDENT}\[Tag '$tag' $valLen bytes compressed]\n";
|
---|
1529 | }
|
---|
1530 | next unless HasZlib($exifTool, 'decode');
|
---|
1531 | my $stat;
|
---|
1532 | my $inflate = Compress::Zlib::inflateInit();
|
---|
1533 | $inflate and ($value, $stat) = $inflate->inflate($value);
|
---|
1534 | unless ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
|
---|
1535 | $exifTool->Warn("Error inflating $tag");
|
---|
1536 | next;
|
---|
1537 | }
|
---|
1538 | $valLen = length $value;
|
---|
1539 | $wasCompressed = 1;
|
---|
1540 | }
|
---|
1541 | }
|
---|
1542 |
|
---|
1543 | # process this tag
|
---|
1544 | if ($formatStr eq 'MIE') {
|
---|
1545 | # process MIE directory
|
---|
1546 | my ($subTablePtr, $dirName);
|
---|
1547 | if ($tagInfo and $$tagInfo{SubDirectory}) {
|
---|
1548 | $dirName = $tagInfo->{SubDirectory}->{DirName};
|
---|
1549 | my $subTable = $tagInfo->{SubDirectory}->{TagTable};
|
---|
1550 | $subTablePtr = $subTable ? GetTagTable($subTable) : $tagTablePtr;
|
---|
1551 | } else {
|
---|
1552 | $subTablePtr = GetTagTable('Image::ExifTool::MIE::Unknown');
|
---|
1553 | }
|
---|
1554 | if ($verbose) {
|
---|
1555 | my $order = ', byte order ' . GetByteOrder();
|
---|
1556 | $exifTool->VerboseInfo($tag, $tagInfo, Size => $valLen, Extra => $order);
|
---|
1557 | }
|
---|
1558 | my %subdirInfo = (
|
---|
1559 | DirName => $dirName || $tag,
|
---|
1560 | RAF => $raf,
|
---|
1561 | Parent => $$dirInfo{DirName},
|
---|
1562 | WasCompressed => $wasCompressed,
|
---|
1563 | );
|
---|
1564 | # read from uncompressed data instead if necessary
|
---|
1565 | $subdirInfo{RAF} = new File::RandomAccess(\$value) if $format & 0x04;
|
---|
1566 |
|
---|
1567 | my $oldOrder = GetByteOrder();
|
---|
1568 | SetByteOrder($format & 0x08 ? 'II' : 'MM');
|
---|
1569 | $msg = ProcessMIEGroup($exifTool, \%subdirInfo, $subTablePtr);
|
---|
1570 | SetByteOrder($oldOrder);
|
---|
1571 | $exifTool->{SET_GROUP1} = $grp1; # restore this group1 name
|
---|
1572 | last if $msg;
|
---|
1573 | } else {
|
---|
1574 | # process MIE data format types
|
---|
1575 | if ($tagInfo) {
|
---|
1576 | # extract tag value
|
---|
1577 | my $val = ReadMIEValue(\$value, 0, $formatStr, undef, $valLen);
|
---|
1578 | unless (defined $val) {
|
---|
1579 | $exifTool->Warn("Error reading $tag value");
|
---|
1580 | $val = '<err>';
|
---|
1581 | }
|
---|
1582 | # save type or mime type
|
---|
1583 | $mime = $val if $tag eq '0Type' or $tag eq '2MIME';
|
---|
1584 | if ($verbose) {
|
---|
1585 | my $count;
|
---|
1586 | my $s = Image::ExifTool::FormatSize($formatStr);
|
---|
1587 | if ($s and $formatStr !~ /^(utf|string|undef)/) {
|
---|
1588 | $count = $valLen / $s;
|
---|
1589 | }
|
---|
1590 | $exifTool->VerboseInfo($lastTag, $tagInfo,
|
---|
1591 | DataPt => \$value,
|
---|
1592 | DataPos => $raf->Tell() - $valLen,
|
---|
1593 | Size => $valLen,
|
---|
1594 | Format => $formatStr,
|
---|
1595 | Value => $val,
|
---|
1596 | Count => $count,
|
---|
1597 | );
|
---|
1598 | }
|
---|
1599 | if ($$tagInfo{SubDirectory}) {
|
---|
1600 | my $subTablePtr = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
|
---|
1601 | my %subdirInfo = (
|
---|
1602 | DirName => $$tagInfo{Name},
|
---|
1603 | DataPt => \$value,
|
---|
1604 | DataLen => $valLen,
|
---|
1605 | DirStart=> 0,
|
---|
1606 | DirLen => $valLen,
|
---|
1607 | Parent => $$dirInfo{DirName},
|
---|
1608 | WasCompressed => $wasCompressed,
|
---|
1609 | );
|
---|
1610 | # set DataPos and Base for uncompressed information only
|
---|
1611 | unless ($wasCompressed) {
|
---|
1612 | $subdirInfo{DataPos} = $raf->Tell() - $valLen;
|
---|
1613 | $subdirInfo{Base} = $raf->Tell() - $valLen;
|
---|
1614 | }
|
---|
1615 | # reset PROCESSED lookup for each MIE directory
|
---|
1616 | # (there is no possibility of double-processing a MIE directory)
|
---|
1617 | $exifTool->{PROCESSED} = { };
|
---|
1618 | my $processProc = $tagInfo->{SubDirectory}->{ProcessProc};
|
---|
1619 | delete $exifTool->{SET_GROUP1};
|
---|
1620 | delete $exifTool->{NO_LIST};
|
---|
1621 | $exifTool->ProcessDirectory(\%subdirInfo, $subTablePtr, $processProc);
|
---|
1622 | $exifTool->{SET_GROUP1} = $grp1;
|
---|
1623 | $exifTool->{NO_LIST} = 1;
|
---|
1624 | } else {
|
---|
1625 | # convert to specified character set if necessary
|
---|
1626 | if ($notUTF8 and $formatStr =~ /^(utf|string)/) {
|
---|
1627 | $val = $exifTool->Decode($val, 'UTF8');
|
---|
1628 | }
|
---|
1629 | if ($formatStr =~ /_list$/) {
|
---|
1630 | # split list value into separate strings
|
---|
1631 | my @vals = split "\0", $val;
|
---|
1632 | $val = \@vals;
|
---|
1633 | }
|
---|
1634 | if (defined $units) {
|
---|
1635 | $val = "@$val" if ref $val; # convert string list to number list
|
---|
1636 | # add units to value if specified
|
---|
1637 | $val .= "($units)" if defined $units;
|
---|
1638 | }
|
---|
1639 | $exifTool->FoundTag($tagInfo, $val);
|
---|
1640 | }
|
---|
1641 | } else {
|
---|
1642 | # skip over unknown information or free bytes
|
---|
1643 | $raf->Seek($valLen, 1) or $msg = 'Seek error', last;
|
---|
1644 | $verbose and $exifTool->VerboseInfo($tag, undef, Size => $valLen);
|
---|
1645 | }
|
---|
1646 | }
|
---|
1647 | }
|
---|
1648 | # modify MIME type if necessary
|
---|
1649 | $mime and not $$dirInfo{Parent} and $exifTool->ModifyMimeType($mime);
|
---|
1650 |
|
---|
1651 | $ok or $msg or $msg = 'Unexpected end of file';
|
---|
1652 | $verbose and $exifTool->{INDENT} = $oldIndent;
|
---|
1653 | return $msg;
|
---|
1654 | }
|
---|
1655 |
|
---|
1656 | #------------------------------------------------------------------------------
|
---|
1657 | # Read/write a MIE file
|
---|
1658 | # Inputs: 0) ExifTool object reference, 1) DirInfo reference
|
---|
1659 | # Returns: 1 on success, 0 if this wasn't a valid MIE file, or -1 on write error
|
---|
1660 | # - process as a trailer if "Trailer" flag set in dirInfo
|
---|
1661 | sub ProcessMIE($$)
|
---|
1662 | {
|
---|
1663 | my ($exifTool, $dirInfo) = @_;
|
---|
1664 | return 1 unless defined $exifTool;
|
---|
1665 | my $raf = $$dirInfo{RAF};
|
---|
1666 | my $outfile = $$dirInfo{OutFile};
|
---|
1667 | my ($buff, $err, $msg, $pos, $end, $isCreating);
|
---|
1668 | my $numDocs = 0;
|
---|
1669 | #
|
---|
1670 | # process as a trailer (from end of file) if specified
|
---|
1671 | #
|
---|
1672 | if ($$dirInfo{Trailer}) {
|
---|
1673 | my $offset = $$dirInfo{Offset} || 0; # offset from end of file
|
---|
1674 | $raf->Seek(-10 - $offset, 2) or return 0;
|
---|
1675 | for (;;) {
|
---|
1676 | # read and validate last 10 bytes
|
---|
1677 | $raf->Read($buff, 10) == 10 or last;
|
---|
1678 | last unless $buff =~ /~\0\0\x06.{4}(\x10|\x18)(\x04)$/s or
|
---|
1679 | $buff =~ /(\x10|\x18)(\x08)$/s;
|
---|
1680 | SetByteOrder($1 eq "\x10" ? 'MM' : 'II');
|
---|
1681 | my $len = ($2 eq "\x04") ? Get32u(\$buff, 4) : Get64u(\$buff, 0);
|
---|
1682 | my $curPos = $raf->Tell() or last;
|
---|
1683 | last if $len < 12 or $len > $curPos;
|
---|
1684 | # validate element header if 8-byte offset was used
|
---|
1685 | if ($2 eq "\x08") {
|
---|
1686 | last if $len < 14;
|
---|
1687 | $raf->Seek($curPos - 14, 0) and $raf->Read($buff, 4) or last;
|
---|
1688 | last unless $buff eq "~\0\0\x0a";
|
---|
1689 | }
|
---|
1690 | # looks like a good group, so remember start position
|
---|
1691 | $pos = $curPos - $len;
|
---|
1692 | $end = $curPos unless $end;
|
---|
1693 | # seek to 10 bytes from end of previous group
|
---|
1694 | $raf->Seek($pos - 10, 0) or last;
|
---|
1695 | }
|
---|
1696 | # seek to start of first MIE group
|
---|
1697 | return 0 unless defined $pos and $raf->Seek($pos, 0);
|
---|
1698 | # update DataPos and DirLen for ProcessTrailers()
|
---|
1699 | $$dirInfo{DataPos} = $pos;
|
---|
1700 | $$dirInfo{DirLen} = $end - $pos;
|
---|
1701 | if ($outfile and $exifTool->{DEL_GROUP}->{MIE}) {
|
---|
1702 | # delete the trailer
|
---|
1703 | $exifTool->VPrint(0," Deleting MIE trailer\n");
|
---|
1704 | ++$exifTool->{CHANGED};
|
---|
1705 | return 1;
|
---|
1706 | } elsif ($exifTool->Options('Verbose') or $exifTool->{HTML_DUMP}) {
|
---|
1707 | $exifTool->DumpTrailer($dirInfo);
|
---|
1708 | }
|
---|
1709 | }
|
---|
1710 | #
|
---|
1711 | # loop through all documents in MIE file
|
---|
1712 | #
|
---|
1713 | for (;;) {
|
---|
1714 | # look for "0MIE" group element
|
---|
1715 | my $num = $raf->Read($buff, 8);
|
---|
1716 | if ($num == 8) {
|
---|
1717 | # verify file identifier
|
---|
1718 | if ($buff =~ /^~(\x10|\x18)\x04(.)0MIE/) {
|
---|
1719 | SetByteOrder($1 eq "\x10" ? 'MM' : 'II');
|
---|
1720 | my $len = ord($2);
|
---|
1721 | # skip extended DataLength if it exists
|
---|
1722 | if ($len > 252 and not $raf->Seek(1 << (256 - $len), 1)) {
|
---|
1723 | $msg = 'Seek error';
|
---|
1724 | last;
|
---|
1725 | }
|
---|
1726 | } else {
|
---|
1727 | return 0 unless $numDocs; # not a MIE file
|
---|
1728 | if ($buff =~ /^~/) {
|
---|
1729 | $msg = 'Non-standard file-level MIE element';
|
---|
1730 | } else {
|
---|
1731 | $msg = 'Invalid MIE file-level data';
|
---|
1732 | }
|
---|
1733 | }
|
---|
1734 | } elsif ($numDocs) {
|
---|
1735 | last unless $num; # OK, all done with file
|
---|
1736 | $msg = 'Truncated MIE element header';
|
---|
1737 | } else {
|
---|
1738 | return 0 if $num or not $outfile;
|
---|
1739 | # we have the ability to create a MIE file from scratch
|
---|
1740 | $buff = ''; # start from nothing
|
---|
1741 | # set byte order according to preferences
|
---|
1742 | $exifTool->SetPreferredByteOrder();
|
---|
1743 | $isCreating = 1;
|
---|
1744 | }
|
---|
1745 | if ($msg) {
|
---|
1746 | last if $$dirInfo{Trailer}; # allow other trailers after MIE
|
---|
1747 | if ($outfile) {
|
---|
1748 | $exifTool->Error($msg);
|
---|
1749 | } else {
|
---|
1750 | $exifTool->Warn($msg);
|
---|
1751 | }
|
---|
1752 | last;
|
---|
1753 | }
|
---|
1754 | # this is a new MIE document -- increment document count
|
---|
1755 | unless ($numDocs) {
|
---|
1756 | # this is a valid MIE file (unless a trailer on another file)
|
---|
1757 | $exifTool->SetFileType();
|
---|
1758 | $exifTool->{NO_LIST} = 1; # handle lists ourself
|
---|
1759 | $exifTool->{MIE_COUNT} = { };
|
---|
1760 | undef $hasZlib;
|
---|
1761 | }
|
---|
1762 | ++$numDocs;
|
---|
1763 |
|
---|
1764 | # process the MIE groups recursively, beginning with the main MIE group
|
---|
1765 | my $tagTablePtr = GetTagTable('Image::ExifTool::MIE::Main');
|
---|
1766 |
|
---|
1767 | my %subdirInfo = (
|
---|
1768 | DirName => 'MIE',
|
---|
1769 | RAF => $raf,
|
---|
1770 | OutFile => $outfile,
|
---|
1771 | # don't define Parent so WriteMIEGroup() writes extended terminator
|
---|
1772 | );
|
---|
1773 | if ($outfile) {
|
---|
1774 | # generate lookup for MIE format codes if not done already
|
---|
1775 | unless (%mieCode) {
|
---|
1776 | foreach (keys %mieFormat) {
|
---|
1777 | $mieCode{$mieFormat{$_}} = $_;
|
---|
1778 | }
|
---|
1779 | }
|
---|
1780 | # update %mieMap with user-defined MIE groups
|
---|
1781 | UpdateMieMap() unless $doneMieMap;
|
---|
1782 | # initialize write directories, with MIE tags taking priority
|
---|
1783 | # (note that this may re-initialize directories when writing trailer
|
---|
1784 | # to another type of image, but this is OK because we are done writing
|
---|
1785 | # the other format by the time we start writing the trailer)
|
---|
1786 | $exifTool->InitWriteDirs(\%mieMap, 'MIE');
|
---|
1787 | $subdirInfo{ToWrite} = '~' . MIEGroupFormat(1) . "\x04\xfe0MIE\0\0\0\0";
|
---|
1788 | $msg = WriteMIEGroup($exifTool, \%subdirInfo, $tagTablePtr);
|
---|
1789 | if ($msg) {
|
---|
1790 | $exifTool->Error($msg);
|
---|
1791 | $err = 1;
|
---|
1792 | last;
|
---|
1793 | } elsif (defined $msg and $isCreating) {
|
---|
1794 | last;
|
---|
1795 | }
|
---|
1796 | } else {
|
---|
1797 | $msg = ProcessMIEGroup($exifTool, \%subdirInfo, $tagTablePtr);
|
---|
1798 | if ($msg) {
|
---|
1799 | $exifTool->Warn($msg);
|
---|
1800 | last;
|
---|
1801 | }
|
---|
1802 | }
|
---|
1803 | }
|
---|
1804 | delete $exifTool->{NO_LIST};
|
---|
1805 | delete $exifTool->{MIE_COUNT};
|
---|
1806 | delete $exifTool->{SET_GROUP1};
|
---|
1807 | return $err ? -1 : 1;
|
---|
1808 | }
|
---|
1809 |
|
---|
1810 | 1; # end
|
---|
1811 |
|
---|
1812 | __END__
|
---|
1813 |
|
---|
1814 | =head1 NAME
|
---|
1815 |
|
---|
1816 | Image::ExifTool::MIE - Read/write MIE meta information
|
---|
1817 |
|
---|
1818 | =head1 SYNOPSIS
|
---|
1819 |
|
---|
1820 | This module is used by Image::ExifTool
|
---|
1821 |
|
---|
1822 | =head1 DESCRIPTION
|
---|
1823 |
|
---|
1824 | This module contains routines required by Image::ExifTool to read and write
|
---|
1825 | information in MIE files.
|
---|
1826 |
|
---|
1827 | =head1 WHAT IS MIE?
|
---|
1828 |
|
---|
1829 | MIE stands for "Meta Information Encapsulation". The MIE format is an
|
---|
1830 | extensible, dedicated meta information format which supports storage of
|
---|
1831 | binary as well as textual meta information. MIE can be used to encapsulate
|
---|
1832 | meta information from many sources and bundle it together with any type of
|
---|
1833 | file.
|
---|
1834 |
|
---|
1835 | =head2 Features
|
---|
1836 |
|
---|
1837 | Below is very subjective score card comparing the features of a number of
|
---|
1838 | common file and meta information formats, and comparing them to MIE. The
|
---|
1839 | following features are rated for each format with a score of 0 to 10:
|
---|
1840 |
|
---|
1841 | 1) Extensible (can incorporate user-defined information).
|
---|
1842 | 2) Meaningful tag ID's (hint to meaning of unknown information).
|
---|
1843 | 3) Sequential read/write ability (streamable).
|
---|
1844 | 4) Hierarchical information structure.
|
---|
1845 | 5) Easy to implement reader/writer/editor.
|
---|
1846 | 6) Order of information well defined.
|
---|
1847 | 7) Large data lengths supported: >64kB (+5) and >4GB (+5).
|
---|
1848 | 8) Localized text strings.
|
---|
1849 | 9) Multiple documents in a single file.
|
---|
1850 | 10) Compact format doesn't squander disk space or bandwidth.
|
---|
1851 | 11) Compressed meta information supported.
|
---|
1852 | 12) Relocatable data elements (ie. no fixed offsets).
|
---|
1853 | 13) Binary meta information (+7) with variable byte order (+3).
|
---|
1854 | 14) Mandatory tags not required (an unecessary complication).
|
---|
1855 | 15) Append information to end of file without editing.
|
---|
1856 |
|
---|
1857 | Feature number Total
|
---|
1858 | Format 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Score
|
---|
1859 | ------ --------------------------------------------- -----
|
---|
1860 | MIE 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 150
|
---|
1861 | PDF 10 10 0 10 0 0 10 0 10 10 10 0 7 10 10 97
|
---|
1862 | PNG 10 10 10 0 8 0 5 10 0 10 10 10 0 10 0 93
|
---|
1863 | XMP 10 10 10 10 2 0 10 10 10 0 0 10 0 10 0 92
|
---|
1864 | AIFF 0 5 10 10 10 0 5 0 0 10 0 10 7 10 0 77
|
---|
1865 | RIFF 0 5 10 10 10 0 5 0 0 10 0 10 7 10 0 77
|
---|
1866 | JPEG 10 0 10 0 10 0 0 0 0 10 0 10 7 10 0 67
|
---|
1867 | EPS 10 10 10 0 0 0 10 0 10 0 0 5 0 10 0 65
|
---|
1868 | CIFF 0 0 0 10 10 0 5 0 0 10 0 10 10 10 0 65
|
---|
1869 | TIFF 0 0 0 10 5 10 5 0 10 10 0 0 10 0 0 60
|
---|
1870 | EXIF 0 0 0 10 5 10 0 0 0 10 0 0 10 0 0 45
|
---|
1871 | IPTC 0 0 10 0 8 0 0 0 0 10 0 10 7 0 0 45
|
---|
1872 |
|
---|
1873 | By design, MIE ranks highest by a significant margin. Other formats with
|
---|
1874 | reasonable scores are PDF, PNG and XMP, but each has significant weak
|
---|
1875 | points. What may be surprising is that TIFF, EXIF and IPTC rank so low.
|
---|
1876 |
|
---|
1877 | As well as scoring high in all these features, the MIE format has the unique
|
---|
1878 | ability to encapsulate any other type of file, and provides a non-invasive
|
---|
1879 | method of adding meta information to a file. The meta information is
|
---|
1880 | logically separated from the original file data, which is extremely
|
---|
1881 | important because meta information is routinely lost when files are edited.
|
---|
1882 |
|
---|
1883 | Also, the MIE format supports multiple files by simple concatenation,
|
---|
1884 | enabling all kinds of wonderful features such as linear databases, edit
|
---|
1885 | histories or non-intrusive file updates. This ability can also be leveraged
|
---|
1886 | to allow MIE-format trailers to be added to some other file types.
|
---|
1887 |
|
---|
1888 | =head1 MIE 1.1 FORMAT SPECIFICATION (2007-01-21)
|
---|
1889 |
|
---|
1890 | =head2 File Structure
|
---|
1891 |
|
---|
1892 | A MIE file consists of a series of MIE elements. A MIE element may contain
|
---|
1893 | either data or a group of MIE elements, providing a hierarchical format for
|
---|
1894 | storing data. Each MIE element is identified by a human-readable tag name,
|
---|
1895 | and may store data from zero to 2^64-1 bytes in length.
|
---|
1896 |
|
---|
1897 | =head2 File Signature
|
---|
1898 |
|
---|
1899 | The first element in the MIE file must be an uncompressed MIE group element
|
---|
1900 | with a tag name of "0MIE". This restriction allows the first 8 bytes of a
|
---|
1901 | MIE file to be used to identify a MIE format file. The following table
|
---|
1902 | lists the two possible initial byte sequences for a MIE-format file (the
|
---|
1903 | first for big-endian, and the second for little-endian byte ordering):
|
---|
1904 |
|
---|
1905 | Byte Number: 0 1 2 3 4 5 6 7
|
---|
1906 |
|
---|
1907 | C Characters: ~ \x10 \x04 ? 0 M I E
|
---|
1908 | or ~ \x18 \x04 ? 0 M I E
|
---|
1909 |
|
---|
1910 | Hexadecimal: 7e 10 04 ? 30 4d 49 45
|
---|
1911 | or 7e 18 04 ? 30 4d 49 45
|
---|
1912 |
|
---|
1913 | Decimal: 126 16 4 ? 48 77 73 69
|
---|
1914 | or 126 24 4 ? 48 77 73 69
|
---|
1915 |
|
---|
1916 | Note that byte 1 may have one of the two possible values (0x10 or 0x18), and
|
---|
1917 | byte 3 may have any value (0x00 to 0xff).
|
---|
1918 |
|
---|
1919 | =head2 Element Structure
|
---|
1920 |
|
---|
1921 | 1 byte SyncByte = 0x7e (decimal 126, character '~')
|
---|
1922 | 1 byte FormatCode (see below)
|
---|
1923 | 1 byte TagLength (T)
|
---|
1924 | 1 byte DataLength (gives D if DataLength < 253)
|
---|
1925 | T bytes TagName (T given by TagLength)
|
---|
1926 | 2 bytes DataLength2 [exists only if DataLength == 255 (0xff)]
|
---|
1927 | 4 bytes DataLength4 [exists only if DataLength == 254 (0xfe)]
|
---|
1928 | 8 bytes DataLength8 [exists only if DataLength == 253 (0xfd)]
|
---|
1929 | D bytes DataBlock (D given by DataLength)
|
---|
1930 |
|
---|
1931 | The minimum element length is 4 bytes (for a group terminator). The maximum
|
---|
1932 | DataBlock size is 2^64-1 bytes. TagLength and DataLength are unsigned
|
---|
1933 | integers, and the byte ordering for multi-byte DataLength fields is
|
---|
1934 | specified by the containing MIE group element. The SyncByte is byte
|
---|
1935 | aligned, so no padding is added to align on an N-byte boundary.
|
---|
1936 |
|
---|
1937 | =head3 FormatCode
|
---|
1938 |
|
---|
1939 | The format code is a bitmask that defines the format of the data:
|
---|
1940 |
|
---|
1941 | 7654 3210
|
---|
1942 | ++++ ---- FormatType
|
---|
1943 | ---- +--- TypeModifier
|
---|
1944 | ---- -+-- Compressed
|
---|
1945 | ---- --++ FormatSize
|
---|
1946 |
|
---|
1947 | =over 4
|
---|
1948 |
|
---|
1949 | =item FormatType (bitmask 0xf0):
|
---|
1950 |
|
---|
1951 | 0x00 - other (or unknown) data
|
---|
1952 | 0x10 - MIE group
|
---|
1953 | 0x20 - text string
|
---|
1954 | 0x30 - list of null-separated text strings
|
---|
1955 | 0x40 - integer
|
---|
1956 | 0x50 - rational
|
---|
1957 | 0x60 - fixed point
|
---|
1958 | 0x70 - floating point
|
---|
1959 | 0x80 - free space
|
---|
1960 |
|
---|
1961 | =item TypeModifier (bitmask 0x08):
|
---|
1962 |
|
---|
1963 | Modifies the meaning of certain FormatTypes (0x00-0x60):
|
---|
1964 |
|
---|
1965 | 0x08 - other data sensitive to MIE group byte order
|
---|
1966 | 0x18 - MIE group with little-endian byte ordering
|
---|
1967 | 0x28 - UTF encoded text string
|
---|
1968 | 0x38 - UTF encoded text string list
|
---|
1969 | 0x48 - signed integer
|
---|
1970 | 0x58 - signed rational (denominator is always unsigned)
|
---|
1971 | 0x68 - signed fixed-point
|
---|
1972 |
|
---|
1973 | =item Compressed (bitmask 0x04):
|
---|
1974 |
|
---|
1975 | If this bit is set, the data block is compressed using Zlib deflate. An
|
---|
1976 | entire MIE group may be compressed, with the exception of file-level groups.
|
---|
1977 |
|
---|
1978 | =item FormatSize (bitmask 0x03):
|
---|
1979 |
|
---|
1980 | Gives the byte size of each data element:
|
---|
1981 |
|
---|
1982 | 0x00 - 8 bits (1 byte)
|
---|
1983 | 0x01 - 16 bits (2 bytes)
|
---|
1984 | 0x02 - 32 bits (4 bytes)
|
---|
1985 | 0x03 - 64 bits (8 bytes)
|
---|
1986 |
|
---|
1987 | The number of bytes in a single value for this format is given by
|
---|
1988 | 2**FormatSize (or 1 << FormatSize). The number of values is the data length
|
---|
1989 | divided by this number of bytes. It is an error if the data length is not
|
---|
1990 | an even multiple of the format size in bytes.
|
---|
1991 |
|
---|
1992 | =back
|
---|
1993 |
|
---|
1994 | The following is a list of all currently defined MIE FormatCode values for
|
---|
1995 | uncompressed data (add 0x04 to each value for compressed data):
|
---|
1996 |
|
---|
1997 | 0x00 - other data (insensitive to MIE group byte order) (1)
|
---|
1998 | 0x01 - other 16-bit data (may be byte swapped)
|
---|
1999 | 0x02 - other 32-bit data (may be byte swapped)
|
---|
2000 | 0x03 - other 64-bit data (may be byte swapped)
|
---|
2001 | 0x08 - other data (sensitive to MIE group byte order) (1)
|
---|
2002 | 0x10 - MIE group with big-endian values (1)
|
---|
2003 | 0x18 - MIE group with little-endian values (1)
|
---|
2004 | 0x20 - ASCII (ISO 8859-1) string (2,3)
|
---|
2005 | 0x28 - UTF-8 string (2,3,4)
|
---|
2006 | 0x29 - UTF-16 string (2,3,4)
|
---|
2007 | 0x2a - UTF-32 string (2,3,4)
|
---|
2008 | 0x30 - ASCII (ISO 8859-1) string list (3,5)
|
---|
2009 | 0x38 - UTF-8 string list (3,4,5)
|
---|
2010 | 0x39 - UTF-16 string list (3,4,5)
|
---|
2011 | 0x3a - UTF-32 string list (3,4,5)
|
---|
2012 | 0x40 - unsigned 8-bit integer
|
---|
2013 | 0x41 - unsigned 16-bit integer
|
---|
2014 | 0x42 - unsigned 32-bit integer
|
---|
2015 | 0x43 - unsigned 64-bit integer (6)
|
---|
2016 | 0x48 - signed 8-bit integer
|
---|
2017 | 0x49 - signed 16-bit integer
|
---|
2018 | 0x4a - signed 32-bit integer
|
---|
2019 | 0x4b - signed 64-bit integer (6)
|
---|
2020 | 0x52 - unsigned 32-bit rational (16-bit numerator then denominator) (7)
|
---|
2021 | 0x53 - unsigned 64-bit rational (32-bit numerator then denominator) (7)
|
---|
2022 | 0x5a - signed 32-bit rational (denominator is unsigned) (7)
|
---|
2023 | 0x5b - signed 64-bit rational (denominator is unsigned) (7)
|
---|
2024 | 0x61 - unsigned 16-bit fixed-point (high 8 bits is integer part) (8)
|
---|
2025 | 0x62 - unsigned 32-bit fixed-point (high 16 bits is integer part) (8)
|
---|
2026 | 0x69 - signed 16-bit fixed-point (high 8 bits is signed integer) (8)
|
---|
2027 | 0x6a - signed 32-bit fixed-point (high 16 bits is signed integer) (8)
|
---|
2028 | 0x72 - 32-bit IEEE float (not recommended for portability reasons)
|
---|
2029 | 0x73 - 64-bit IEEE double (not recommended for portability reasons) (6)
|
---|
2030 | 0x80 - free space (value data does not contain useful information)
|
---|
2031 |
|
---|
2032 | Notes:
|
---|
2033 |
|
---|
2034 | =over 4
|
---|
2035 |
|
---|
2036 | =item 1.
|
---|
2037 |
|
---|
2038 | The byte ordering specified by the MIE group TypeModifier applies to the MIE
|
---|
2039 | group element as well as all elements within the group. Data for all
|
---|
2040 | FormatCodes except 0x08 (other data, sensitive to byte order) may be
|
---|
2041 | transferred between MIE groups with different byte order by byte swapping
|
---|
2042 | the uncompressed data according to the specified data format. The following
|
---|
2043 | list illustrates the byte-swapping pattern, based on FormatSize, for all
|
---|
2044 | format types except rational (FormatType 0x50).
|
---|
2045 |
|
---|
2046 | FormatSize Change in Byte Sequence
|
---|
2047 | -------------- -----------------------------------
|
---|
2048 | 0x00 (8 bits) 0 1 2 3 4 5 6 7 --> 0 1 2 3 4 5 6 7 (no change)
|
---|
2049 | 0x01 (16 bits) 0 1 2 3 4 5 6 7 --> 1 0 3 2 5 4 7 6
|
---|
2050 | 0x02 (32 bits) 0 1 2 3 4 5 6 7 --> 3 2 1 0 7 6 5 4
|
---|
2051 | 0x03 (64 bits) 0 1 2 3 4 5 6 7 --> 7 6 5 4 3 2 1 0
|
---|
2052 |
|
---|
2053 | Rational values consist of two integers, so they are swapped as the next
|
---|
2054 | lower FormatSize. For example, a 32-bit rational (FormatSize 0x02, and
|
---|
2055 | FormatCode 0x52 or 0x5a) is swapped as two 16-bit values (ie. as if it had
|
---|
2056 | FormatSize 0x01).
|
---|
2057 |
|
---|
2058 | =item 2.
|
---|
2059 |
|
---|
2060 | The TagName of a string element may have an 6-character suffix to indicate a
|
---|
2061 | specific locale. (ie. "Title-en_US", or "Keywords-de_DE").
|
---|
2062 |
|
---|
2063 | =item 3.
|
---|
2064 |
|
---|
2065 | Text strings are not normally null terminated, however they may be padded
|
---|
2066 | with one or more null characters to the end of the data block to allow
|
---|
2067 | strings to be edited within fixed-length data blocks. Newlines in the text
|
---|
2068 | are indicated by a single LF (0x0a) character.
|
---|
2069 |
|
---|
2070 | =item 4.
|
---|
2071 |
|
---|
2072 | UTF strings must not begin with a byte order mark (BOM) since the byte order
|
---|
2073 | and byte size are specified by the MIE format. If a BOM is found, it should
|
---|
2074 | be treated as a zero-width non-breaking space.
|
---|
2075 |
|
---|
2076 | =item 5.
|
---|
2077 |
|
---|
2078 | A list of text strings separated by null characters. These lists must not
|
---|
2079 | be null padded or null terminated, since this would be interpreted as
|
---|
2080 | additional zero-length strings. For ASCII and UTF-8 strings, the null
|
---|
2081 | character is a single zero (0x00) byte. For UTF-16 or UTF-32 strings, the
|
---|
2082 | null character is 2 or 4 zero bytes respectively.
|
---|
2083 |
|
---|
2084 | =item 6.
|
---|
2085 |
|
---|
2086 | 64-bit integers and doubles are subject to the specified byte ordering for
|
---|
2087 | both 32-bit words and bytes within these words. For instance, the high
|
---|
2088 | order byte is always the first byte if big-endian, and the eighth byte if
|
---|
2089 | little-endian. This means that some swapping is always necessary for these
|
---|
2090 | values on systems where the byte order differs from the word order (ie. some
|
---|
2091 | ARM systems), regardless of the endian-ness of the stored values.
|
---|
2092 |
|
---|
2093 | =item 7.
|
---|
2094 |
|
---|
2095 | Rational values are treated as two separate integers. The numerator always
|
---|
2096 | comes first regardless of the byte ordering. In a signed rational value,
|
---|
2097 | only the numerator is signed. The denominator of all rational values is
|
---|
2098 | unsigned (ie. a signed 64-bit rational of 0x80000000/0x80000000 evaluates to
|
---|
2099 | -1, not +1).
|
---|
2100 |
|
---|
2101 | =item 8.
|
---|
2102 |
|
---|
2103 | 32-bit fixed point values are converted to floating point by treating them
|
---|
2104 | as an integer and dividing by an appropriate value. ie)
|
---|
2105 |
|
---|
2106 | 16-bit fixed value = 16-bit integer value / 256.0
|
---|
2107 | 32-bit fixed value = 32-bit integer value / 65536.0
|
---|
2108 |
|
---|
2109 | =back
|
---|
2110 |
|
---|
2111 | =head3 TagLength
|
---|
2112 |
|
---|
2113 | Gives the length of the TagName string. Any value between 0 and 255 is
|
---|
2114 | valid, but the TagLength of 0 is valid only for the MIE group terminator.
|
---|
2115 |
|
---|
2116 | =head3 DataLength
|
---|
2117 |
|
---|
2118 | DataLength is an unsigned byte that gives the number of bytes in the data
|
---|
2119 | block. A value between 0 and 252 gives the data length directly, and
|
---|
2120 | numbers from 253 to 255 are reserved for extended DataLength codes. Codes
|
---|
2121 | of 255, 254 and 253 indicate that the element contains an additional 2, 4 or
|
---|
2122 | 8 byte unsigned integer representing the data length.
|
---|
2123 |
|
---|
2124 | 0-252 - length of data block
|
---|
2125 | 255 (0xff) - use DataLength2
|
---|
2126 | 254 (0xfe) - use DataLength4
|
---|
2127 | 253 (0xfd) - use DataLength8
|
---|
2128 |
|
---|
2129 | A DataLength of zero is valid for any element except a compressed MIE group.
|
---|
2130 | A zero DataLength for an uncompressed MIE group indicates that the group
|
---|
2131 | length is unknown. For other elements, a zero length indicates there is no
|
---|
2132 | associated data. A terminator element must have a DataLength of 0, 6 or 10,
|
---|
2133 | and may not use an extended DataLength.
|
---|
2134 |
|
---|
2135 | =head3 TagName
|
---|
2136 |
|
---|
2137 | The TagName string is 0 to 255 bytes long, and is composed of the ASCII
|
---|
2138 | characters A-Z, a-z, 0-9 and underline ('_'). Also, a dash ('-') is used to
|
---|
2139 | separate the language/country code in the TagName of a localized text
|
---|
2140 | string, and a units string (possibly containing other ASCII characters) may
|
---|
2141 | be appear in brackets at the end of the TagName. The TagName string is NOT
|
---|
2142 | null terminated. A MIE element with a tag string of zero length is reserved
|
---|
2143 | for the group terminator.
|
---|
2144 |
|
---|
2145 | MIE elements are sorted alphabetically by TagName within each group.
|
---|
2146 | Multiple elements with the same TagName are allowed, even within the same
|
---|
2147 | group.
|
---|
2148 |
|
---|
2149 | TagNames should be meaningful. Case is significant. Words should be
|
---|
2150 | lowercase with an uppercase first character, and acronyms should be all
|
---|
2151 | upper case. The underline ("_") is provided to allow separation of two
|
---|
2152 | acronyms or two numbers, but it shouldn't be used unless necessary. No
|
---|
2153 | separation is necessary between an acronym and a word (ie. "ISOSetting").
|
---|
2154 |
|
---|
2155 | All TagNames should start with an uppercase letter. An exception to this
|
---|
2156 | rule allows tags to begin with a digit (0-9) if they must come before other
|
---|
2157 | tags in the sort order, or a lowercase letter (a-z) if they must come after.
|
---|
2158 | For instance, the '0Type' element begins with a digit so it comes before,
|
---|
2159 | and the 'data' element begins with a lowercase letter so that it comes after
|
---|
2160 | meta information tags in the main "0MIE" group.
|
---|
2161 |
|
---|
2162 | Tag names for localized text strings have an 6-character suffix with the
|
---|
2163 | following format: The first character is a dash ('-'), followed by a
|
---|
2164 | 2-character lower case ISO 639-1 language code, then an underline ('_'), and
|
---|
2165 | ending with a 2-character upper case ISO 3166-1 alpha 2 country code. (ie.
|
---|
2166 | "-en_US", "-en_GB", "-de_DE" or "-fr_FR". Note that "GB", and not "UK" is
|
---|
2167 | the code for Great Britain, although "UK" should be recognized for
|
---|
2168 | compatibility reasons.) The suffix is included when sorting the tags
|
---|
2169 | alphabetically, so the default locale (with no tag-name suffix) always comes
|
---|
2170 | first. If the country is unknown or not applicable, a country code of "XX"
|
---|
2171 | should be used.
|
---|
2172 |
|
---|
2173 | Tags with numerical values may allow units of measurement to be specified.
|
---|
2174 | The units string is stored in brackets at the end of the tag name, and is
|
---|
2175 | composed of zero or more ASCII characters in the range 0x21 to 0x7d,
|
---|
2176 | excluding the bracket characters 0x28 and 0x29. (ie. "Resolution(/cm)" or
|
---|
2177 | "SpecificHeat(J/kg.K)".) See L<Image::ExifTool::MIEUnits> for details. Unit
|
---|
2178 | strings are not localized, and may not be used in combination with localized
|
---|
2179 | text strings.
|
---|
2180 |
|
---|
2181 | Sets of tags which would require a common prefix should be added in a
|
---|
2182 | separate MIE group instead of adding the prefix to all tag names. For
|
---|
2183 | example, instead of these TagName's:
|
---|
2184 |
|
---|
2185 | ExternalFlashType
|
---|
2186 | ExternalFlashSerialNumber
|
---|
2187 | ExternalFlashFired
|
---|
2188 |
|
---|
2189 | one would instead designate a separate "ExternalFlash" MIE group to contain
|
---|
2190 | the following elements:
|
---|
2191 |
|
---|
2192 | Type
|
---|
2193 | SerialNumber
|
---|
2194 | Fired
|
---|
2195 |
|
---|
2196 | =head3 DataLength2/4/8
|
---|
2197 |
|
---|
2198 | These extended DataLength fields exist only if DataLength is 255, 254 or
|
---|
2199 | 253, and are respectively 2, 4 or 8 byte unsigned integers giving the data
|
---|
2200 | block length. One of these values must be used if the data block is larger
|
---|
2201 | than 252 bytes, but they may be used if desired for smaller blocks too
|
---|
2202 | (although this may add a few unnecessary bytes to the MIE element).
|
---|
2203 |
|
---|
2204 | =head3 DataBlock
|
---|
2205 |
|
---|
2206 | The data value for the MIE element. The format of the data is given by the
|
---|
2207 | FormatCode. For MIE group elements, the data includes all contained
|
---|
2208 | elements and the group terminator.
|
---|
2209 |
|
---|
2210 | =head2 MIE groups
|
---|
2211 |
|
---|
2212 | All MIE data elements must be contained within a group. A group begins with
|
---|
2213 | a MIE group element, and ends with a group terminator. Groups may be nested
|
---|
2214 | in a hierarchy to arbitrary depth.
|
---|
2215 |
|
---|
2216 | A MIE group element is identified by a format code of 0x10 (big endian byte
|
---|
2217 | ordering) or 0x18 (little endian). The group terminator is distinguished by
|
---|
2218 | a zero TagLength (it is the only element allowed to have a zero TagLength),
|
---|
2219 | and has a FormatCode of 0x00.
|
---|
2220 |
|
---|
2221 | The MIE group element is permitted to have a zero DataLength only if the
|
---|
2222 | data is uncompressed. This special value indicates that the group length is
|
---|
2223 | unknown (otherwise the minimum value for DataLength is 4, corresponding the
|
---|
2224 | the minimum group size which includes a terminator of at least 4 bytes). If
|
---|
2225 | DataLength is zero, all elements in the group must be parsed until the group
|
---|
2226 | terminator is found. If non-zero, DataLength includes the length of all
|
---|
2227 | elements contained within the group, including the group terminator. Use of
|
---|
2228 | a non-zero DataLength is encouraged because it allows readers quickly skip
|
---|
2229 | over entire MIE groups. For compressed groups DataLength must be non-zero,
|
---|
2230 | and is the length of the compressed group data (which includes the
|
---|
2231 | compressed group terminator).
|
---|
2232 |
|
---|
2233 | =head3 Group Terminator
|
---|
2234 |
|
---|
2235 | The group terminator has a FormatCode and TagLength of zero. The terminator
|
---|
2236 | DataLength must be 0, 6 or 10 bytes, and extended DataLength codes may not
|
---|
2237 | be used. With a zero DataLength, the byte sequence for a terminator is "7e
|
---|
2238 | 00 00 00" (hex). With a DataLength of 6 or 10 bytes, the terminator data
|
---|
2239 | block contains information about the length and byte ordering of the
|
---|
2240 | preceding group. This additional information is recommended for file-level
|
---|
2241 | groups, and is used in multi-document MIE files and MIE trailers to allow
|
---|
2242 | the file to be scanned backwards from the end. (This may also allow some
|
---|
2243 | documents to be recovered if part of the file is corrupted.) The structure
|
---|
2244 | of this optional terminator data block is as follows:
|
---|
2245 |
|
---|
2246 | 4 or 8 bytes GroupLength (unsigned integer)
|
---|
2247 | 1 byte ByteOrder (0x10 or 0x18, same as MIE group)
|
---|
2248 | 1 byte GroupLengthSize (0x04 or 0x08)
|
---|
2249 |
|
---|
2250 | The ByteOrder and GroupLengthSize values give the byte ordering and size of
|
---|
2251 | the GroupLength integer. The GroupLength value is the total length of the
|
---|
2252 | entire MIE group ending with this terminator, including the opening MIE
|
---|
2253 | group element and the terminator itself.
|
---|
2254 |
|
---|
2255 | =head3 File-level MIE groups
|
---|
2256 |
|
---|
2257 | File-level MIE groups may NOT be compressed.
|
---|
2258 |
|
---|
2259 | All elements in a MIE file are contained within a special group with a
|
---|
2260 | TagName of "0MIE". The purpose of the "OMIE" group is to provide a unique
|
---|
2261 | signature at the start of the file, and to encapsulate information allowing
|
---|
2262 | files to be easily combined. The "0MIE" group must be terminated like any
|
---|
2263 | other group, but it is recommended that the terminator of a file-level group
|
---|
2264 | include the optional data block (defined above) to provide information about
|
---|
2265 | the group length and byte order.
|
---|
2266 |
|
---|
2267 | It is valid to have more than one "0MIE" group at the file level, allowing
|
---|
2268 | multiple documents in a single MIE file. Furthermore, the MIE structure
|
---|
2269 | enables multi-document files to be generated by simply concatenating two or
|
---|
2270 | more MIE files.
|
---|
2271 |
|
---|
2272 | =head2 Scanning Backwards through a MIE File
|
---|
2273 |
|
---|
2274 | The steps below give an algorithm to quickly locate the last document in a
|
---|
2275 | MIE file:
|
---|
2276 |
|
---|
2277 | =over 4
|
---|
2278 |
|
---|
2279 | =item 1.
|
---|
2280 |
|
---|
2281 | Read the last 10 bytes of the file. (Note that a valid MIE file may be as
|
---|
2282 | short as 12 bytes long, but a file this length contains only an an empty MIE
|
---|
2283 | group.)
|
---|
2284 |
|
---|
2285 | =item 2.
|
---|
2286 |
|
---|
2287 | If the last byte of the file is zero, then it is not possible to scan
|
---|
2288 | backward through the file, so the file must be scanned from the beginning.
|
---|
2289 | Otherwise, proceed to the next step.
|
---|
2290 |
|
---|
2291 | =item 3.
|
---|
2292 |
|
---|
2293 | If the last byte is 4 or 8, the terminator contains information about the
|
---|
2294 | byte ordering and length of the group. Otherwise, stop here because this
|
---|
2295 | isn't a valid MIE file.
|
---|
2296 |
|
---|
2297 | =item 4.
|
---|
2298 |
|
---|
2299 | The next-to-last byte must be either 0x10 indicating big-endian byte
|
---|
2300 | ordering or 0x18 for little-endian ordering, otherwise this isn't a valid
|
---|
2301 | MIE file.
|
---|
2302 |
|
---|
2303 | =item 5.
|
---|
2304 |
|
---|
2305 | The value of the preceding 4 or 8 bytes gives the length of the complete
|
---|
2306 | file-level MIE group (GroupLength). This length includes both the leading
|
---|
2307 | MIE group element and the terminator element itself. The value is an
|
---|
2308 | unsigned integer with a byte length given in step 3), and a byte order from
|
---|
2309 | step 4). From the current file position (at the end of the data read in
|
---|
2310 | step 1), seek backward by this number of bytes to find the start of the MIE
|
---|
2311 | group element for this document.
|
---|
2312 |
|
---|
2313 | =back
|
---|
2314 |
|
---|
2315 | This algorithm may be repeated again beginning at this point in the file to
|
---|
2316 | locate the next-to-last document, etc.
|
---|
2317 |
|
---|
2318 | The table below lists all 5 valid patterns for the last 14 bytes of a
|
---|
2319 | file-level MIE group, with all numbers in hex. The comments indicate the
|
---|
2320 | length and byte ordering of GroupLength (xx) if available:
|
---|
2321 |
|
---|
2322 | ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 7e 00 00 00 - (no GroupLength)
|
---|
2323 | ?? ?? ?? ?? 7e 00 00 06 xx xx xx xx 10 04 - 4 bytes, big endian
|
---|
2324 | ?? ?? ?? ?? 7e 00 00 06 xx xx xx xx 18 04 - 4 bytes, little endian
|
---|
2325 | 7e 00 00 0a xx xx xx xx xx xx xx xx 10 08 - 8 bytes, big endian
|
---|
2326 | 7e 00 00 0a xx xx xx xx xx xx xx xx 18 08 - 8 bytes, little endian
|
---|
2327 |
|
---|
2328 | =head2 Trailer Signature
|
---|
2329 |
|
---|
2330 | The MIE format may be used for trailer information appended to other types
|
---|
2331 | of files. When this is done, a signature must appear at the end of the main
|
---|
2332 | MIE group to uniquely identify the MIE format trailer. To achieve this, a
|
---|
2333 | "zmie" trailer signature is written as the last element in the main "0MIE"
|
---|
2334 | group. This element has a FormatCode of 0, a TagLength of 4, a DataLength
|
---|
2335 | of 0, and a TagName of "zmie". With this signature, the hex byte sequence
|
---|
2336 | "7e 00 04 00 7a 6d 69 65" appears immediately before the final group
|
---|
2337 | terminator, and the last 22 bytes of the trailer correspond to one of the
|
---|
2338 | following 4 patterns (where the trailer length is given by "xx", as above):
|
---|
2339 |
|
---|
2340 | ?? ?? ?? ?? 7e 00 04 00 7a 6d 69 65 7e 00 00 06 xx xx xx xx 10 04
|
---|
2341 | ?? ?? ?? ?? 7e 00 04 00 7a 6d 69 65 7e 00 00 06 xx xx xx xx 18 04
|
---|
2342 | 7e 00 04 00 7a 6d 69 65 7e 00 00 0a xx xx xx xx xx xx xx xx 10 08
|
---|
2343 | 7e 00 04 00 7a 6d 69 65 7e 00 00 0a xx xx xx xx xx xx xx xx 18 08
|
---|
2344 |
|
---|
2345 | Note that the zero-DataLength terminator may not be used here because the
|
---|
2346 | trailer length must be known for seeking backwards from the end of the file.
|
---|
2347 |
|
---|
2348 | Multiple trailers may be appended to the same file using this technique.
|
---|
2349 |
|
---|
2350 | =head2 MIE Data Values
|
---|
2351 |
|
---|
2352 | MIE data values for a given tag are usually not restricted to a specific
|
---|
2353 | FormatCode. Any value may be represented in any appropriate format,
|
---|
2354 | including numbers represented in string (ASCII or UTF) form.
|
---|
2355 |
|
---|
2356 | It is preferred that closely related values with the same format are written
|
---|
2357 | to a single tag instead of using multiple tags. This improves localization
|
---|
2358 | of like values and decreases MIE element overhead. For instance, instead of
|
---|
2359 | separate ImageWidth and ImageHeight tags, a single ImageSize tag is defined.
|
---|
2360 |
|
---|
2361 | Tags which may take on a discrete set of values should have meaningful
|
---|
2362 | values if possible. This improves the extensibility of the format and
|
---|
2363 | allows a more reasonable interpretation of unrecognized values.
|
---|
2364 |
|
---|
2365 | =head3 Numerical Representation
|
---|
2366 |
|
---|
2367 | Integer and floating point numbers may be represented in binary or string
|
---|
2368 | form. In string form, integers are a series of digits with an optional
|
---|
2369 | leading sign (ie. "[+|-]DDDDDD"), and multiple values are separated by a
|
---|
2370 | single space character (ie. "23 128 -32"). Floating point numbers are
|
---|
2371 | similar but may also contain a decimal point and/or a signed exponent with a
|
---|
2372 | leading 'e' character (ie. "[+|-]DD[.DDDDDD][e(+|-)EEE]"). The string "inf"
|
---|
2373 | is used to represent infinity. One advantage of numerical strings is that
|
---|
2374 | they can have an arbitrarily high precision because the possible number of
|
---|
2375 | significant digits is virtually unlimited.
|
---|
2376 |
|
---|
2377 | Note that numerical values may have associated units of measurement which
|
---|
2378 | are specified in the L</TagName> string.
|
---|
2379 |
|
---|
2380 | =head3 Date/Time Format
|
---|
2381 |
|
---|
2382 | All MIE dates are strings in the form "YYYY:mm:dd HH:MM:SS.ss+HH:MM". The
|
---|
2383 | fractional seconds (".ss") are optional, and if included may contain any
|
---|
2384 | number of significant digits (unlike all other fields which are a fixed
|
---|
2385 | number of digits and must be padded with leading zeros if necessary). The
|
---|
2386 | timezone ("+HH:MM" or "-HH:MM") is recommended but not required. If not
|
---|
2387 | given, the local system timezone is assumed.
|
---|
2388 |
|
---|
2389 | =head2 MIME Type
|
---|
2390 |
|
---|
2391 | The basic MIME type for a MIE file is "application/x-mie", however the
|
---|
2392 | specific MIME type depends on the type of subfile, and is obtained by adding
|
---|
2393 | "x-mie-" to the MIME type of the subfile. For example, with a subfile of
|
---|
2394 | type "image/jpeg", the MIE file MIME type is "image/x-mie-jpeg". But note
|
---|
2395 | that the "x-" is not duplicated if the subfile MIME type already starts with
|
---|
2396 | "x-". So a subfile with MIME type "image/x-raw" is contained within a MIE
|
---|
2397 | file of type "image/x-mie-raw", not "image/x-mie-x-raw". In the case of
|
---|
2398 | multiple documents in a MIE file, the MIME type is taken from the first
|
---|
2399 | document. Regardless of the subfile type, all MIE-format files should have
|
---|
2400 | a filename extension of ".MIE".
|
---|
2401 |
|
---|
2402 | =head2 Levels of Support
|
---|
2403 |
|
---|
2404 | Basic MIE reader/writer applications may choose not to provide support for
|
---|
2405 | some advanced features of the MIE format. Features which may not be
|
---|
2406 | supported by all software are:
|
---|
2407 |
|
---|
2408 | =over 4
|
---|
2409 |
|
---|
2410 | =item Compression
|
---|
2411 |
|
---|
2412 | Software not supporting compression must ignore compressed elements and
|
---|
2413 | groups, but should be able to process the remaining information.
|
---|
2414 |
|
---|
2415 | =item Large data lengths
|
---|
2416 |
|
---|
2417 | Some software may limit the maximum size of a MIE group or element.
|
---|
2418 | Historically, a limit of 2GB may be imposed by some systems. However,
|
---|
2419 | 8-byte data lengths should be supported by all applications provided the
|
---|
2420 | value doesn't exceed the system limit. (ie. For systems with a 2GB limit,
|
---|
2421 | 8-byte data lengths should be supported if the upper 17 bits are all zero.)
|
---|
2422 | If a data length above the system limit is encountered, it may be necessary
|
---|
2423 | for the application to stop processing if it can not seek to the next
|
---|
2424 | element in the file.
|
---|
2425 |
|
---|
2426 | =back
|
---|
2427 |
|
---|
2428 | =head1 EXAMPLES
|
---|
2429 |
|
---|
2430 | This section gives examples for working with MIE information using ExifTool.
|
---|
2431 |
|
---|
2432 | =head2 Encapsulating Information with Data in a MIE File
|
---|
2433 |
|
---|
2434 | The following command encapsulates any file recognized by ExifTool inside a
|
---|
2435 | MIE file, and initializes MIE tags from information within the file:
|
---|
2436 |
|
---|
2437 | exiftool -o new.mie -tagsfromfile FILE '-mie:all<all' \
|
---|
2438 | '-subfilename<filename' '-subfiletype<filetype' \
|
---|
2439 | '-subfilemimetype<mimetype' '-subfiledata<=FILE'
|
---|
2440 |
|
---|
2441 | where C<FILE> is the name of the file.
|
---|
2442 |
|
---|
2443 | For unrecognized files, this command may be used:
|
---|
2444 |
|
---|
2445 | exiftool -o new.mie -subfilename=FILE -subfiletype=TYPE \
|
---|
2446 | -subfilemimetype=MIME '-subfiledata<=FILE'
|
---|
2447 |
|
---|
2448 | where C<TYPE> and C<MIME> represent the source file type and MIME type
|
---|
2449 | respectively.
|
---|
2450 |
|
---|
2451 | =head2 Adding a MIE Trailer to a File
|
---|
2452 |
|
---|
2453 | The MIE format may also be used to store information in a trailer appended
|
---|
2454 | to another type of file. Beware that trailers may not be compatible with
|
---|
2455 | all file formats, but JPEG and TIFF are two formats where additional trailer
|
---|
2456 | information doesn't create any problems for normal parsing of the file.
|
---|
2457 | Also note that this technique has the disadvantage that trailer information
|
---|
2458 | is commonly lost if the file is subsequently edited by other software.
|
---|
2459 |
|
---|
2460 | Creating a MIE trailer with ExifTool is a two-step process since ExifTool
|
---|
2461 | can't currently be used to add a MIE trailer directly. The example below
|
---|
2462 | illustrates the steps for adding a MIE trailer with a small preview image
|
---|
2463 | (C<small.jpg>) to a destination JPEG image (C<dst.jpg>).
|
---|
2464 |
|
---|
2465 | Step 1) Create a MIE file with a TrailerSignature containing the desired
|
---|
2466 | information:
|
---|
2467 |
|
---|
2468 | exiftool -o new.mie -trailersignature=1 -tagsfromfile small.jpg \
|
---|
2469 | '-previewimagetype<filetype' '-previewimagesize<imagesize' \
|
---|
2470 | '-previewimagename<filename' '-previewimage<=small.jpg'
|
---|
2471 |
|
---|
2472 | Step 2) Append the MIE information to another file. In Unix, this can be
|
---|
2473 | done with the 'cat' command:
|
---|
2474 |
|
---|
2475 | cat new.mie >> dst.jpg
|
---|
2476 |
|
---|
2477 | Once added, ExifTool may be used to edit or delete a MIE trailer in a JPEG
|
---|
2478 | or TIFF image.
|
---|
2479 |
|
---|
2480 | =head2 Multiple MIE Documents in a Single File
|
---|
2481 |
|
---|
2482 | The MIE specification allows multiple MIE documents (or trailers) to exist
|
---|
2483 | in a single file. A file like this may be created by simply concatenating
|
---|
2484 | MIE documents. ExifTool may be used to access information in a specific
|
---|
2485 | document by adding a copy number to the MIE group name. For example:
|
---|
2486 |
|
---|
2487 | # write the Author tag in the second MIE document
|
---|
2488 | exiftool -mie2:author=phil test.mie
|
---|
2489 |
|
---|
2490 | # delete the first MIE document from a file
|
---|
2491 | exiftool -mie1:all= test.mie
|
---|
2492 |
|
---|
2493 | =head2 Units of Measurement
|
---|
2494 |
|
---|
2495 | Some MIE tags allow values to be specified in different units of
|
---|
2496 | measurement. In the MIE file format these units are combined with the tag
|
---|
2497 | name, but when using ExifTool they are specified in brackets after the
|
---|
2498 | value:
|
---|
2499 |
|
---|
2500 | exiftool -mie:gpsaltitude='7500(ft)' test.mie
|
---|
2501 |
|
---|
2502 | If no units are provided, the default units are written.
|
---|
2503 |
|
---|
2504 | =head2 Localized Text
|
---|
2505 |
|
---|
2506 | Localized text values are accessed by adding a language/country code to the
|
---|
2507 | tag name. For example:
|
---|
2508 |
|
---|
2509 | exiftool -comment-en_us='this is a comment' test.mie
|
---|
2510 |
|
---|
2511 | =head1 REVISIONS
|
---|
2512 |
|
---|
2513 | 2010-04-05 - Fixed ÒFormat SizeÓ Note 7 to give the correct number of bits
|
---|
2514 | in the example rational value
|
---|
2515 | 2007-01-21 - Specified LF character (0x0a) for text newline sequence
|
---|
2516 | 2007-01-19 - Specified ISO 8859-1 character set for extended ASCII codes
|
---|
2517 | 2007-01-01 - Improved wording of Step 5 for scanning backwards in MIE file
|
---|
2518 | 2006-12-30 - Added EXAMPLES section and note about UTF BOM
|
---|
2519 | 2006-12-20 - MIE 1.1: Changed meaning of TypeModifier bit (0x08) for
|
---|
2520 | unknown data (FormatType 0x00), and documented byte swapping
|
---|
2521 | 2006-12-14 - MIE 1.0: Added Data Values and Numerical Representations
|
---|
2522 | sections, and added ability to specify units in tag names
|
---|
2523 | 2006-11-09 - Added Levels of Support section
|
---|
2524 | 2006-11-03 - Added Trailer Signature
|
---|
2525 | 2005-11-18 - Original specification created
|
---|
2526 |
|
---|
2527 | =head1 AUTHOR
|
---|
2528 |
|
---|
2529 | Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
2530 |
|
---|
2531 | This library is free software; you can redistribute it and/or modify it
|
---|
2532 | under the same terms as Perl itself. The MIE format itself is also
|
---|
2533 | copyright Phil Harvey, and is covered by the same free-use license.
|
---|
2534 |
|
---|
2535 | =head1 REFERENCES
|
---|
2536 |
|
---|
2537 | =over 4
|
---|
2538 |
|
---|
2539 | =item L<http://owl.phy.queensu.ca/~phil/exiftool/MIE1.1-20070121.pdf>
|
---|
2540 |
|
---|
2541 | =back
|
---|
2542 |
|
---|
2543 | =head1 SEE ALSO
|
---|
2544 |
|
---|
2545 | L<Image::ExifTool::TagNames/MIE Tags>, L<Image::ExifTool::MIEUnits>,
|
---|
2546 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
2547 |
|
---|
2548 | =cut
|
---|
2549 |
|
---|