1 | #------------------------------------------------------------------------------
|
---|
2 | # File: ICC_Profile.pm
|
---|
3 | #
|
---|
4 | # Description: Read ICC Profile meta information
|
---|
5 | #
|
---|
6 | # Revisions: 11/16/2004 - P. Harvey Created
|
---|
7 | #
|
---|
8 | # References: 1) http://www.color.org/icc_specs2.html (ICC.1:2003-09)
|
---|
9 | # 2) http://www.color.org/icc_specs2.html (ICC.1:2001-04)
|
---|
10 | # 3) http://developer.apple.com/documentation/GraphicsImaging/Reference/ColorSync_Manager/ColorSync_Manager.pdf
|
---|
11 | # 4) http://www.color.org/privatetag2007-01.pdf
|
---|
12 | # 5) http://www.color.org/icc_specs2.xalter (approved revisions, 2010-07-16)
|
---|
13 | #
|
---|
14 | # Notes: The ICC profile information is different: the format of each
|
---|
15 | # tag is embedded in the information instead of in the directory
|
---|
16 | # structure. This makes things a bit more complex because I need
|
---|
17 | # an extra level of logic to decode the variable-format tags.
|
---|
18 | #------------------------------------------------------------------------------
|
---|
19 |
|
---|
20 | package Image::ExifTool::ICC_Profile;
|
---|
21 |
|
---|
22 | use strict;
|
---|
23 | use vars qw($VERSION);
|
---|
24 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
25 |
|
---|
26 | $VERSION = '1.22';
|
---|
27 |
|
---|
28 | sub ProcessICC($$);
|
---|
29 | sub ProcessICC_Profile($$$);
|
---|
30 | sub WriteICC_Profile($$;$);
|
---|
31 | sub ProcessMetadata($$$);
|
---|
32 | sub ValidateICC($);
|
---|
33 |
|
---|
34 | # illuminant type definitions
|
---|
35 | my %illuminantType = (
|
---|
36 | 1 => 'D50',
|
---|
37 | 2 => 'D65',
|
---|
38 | 3 => 'D93',
|
---|
39 | 4 => 'F2',
|
---|
40 | 5 => 'D55',
|
---|
41 | 6 => 'A',
|
---|
42 | 7 => 'Equi-Power (E)',
|
---|
43 | 8 => 'F8',
|
---|
44 | );
|
---|
45 | my %profileClass = (
|
---|
46 | scnr => 'Input Device Profile',
|
---|
47 | mntr => 'Display Device Profile',
|
---|
48 | prtr => 'Output Device Profile',
|
---|
49 | 'link'=> 'DeviceLink Profile',
|
---|
50 | spac => 'ColorSpace Conversion Profile',
|
---|
51 | abst => 'Abstract Profile',
|
---|
52 | nmcl => 'NamedColor Profile',
|
---|
53 | nkpf => 'Nikon Input Device Profile (NON-STANDARD!)', # (written by Nikon utilities)
|
---|
54 | );
|
---|
55 |
|
---|
56 | # ICC_Profile tag table
|
---|
57 | %Image::ExifTool::ICC_Profile::Main = (
|
---|
58 | GROUPS => { 2 => 'Image' },
|
---|
59 | PROCESS_PROC => \&ProcessICC_Profile,
|
---|
60 | WRITE_PROC => \&WriteICC_Profile,
|
---|
61 | NOTES => q{
|
---|
62 | ICC profile information is used in many different file types including JPEG,
|
---|
63 | TIFF, PDF, PostScript, Photoshop, PNG, MIFF, PICT, QuickTime, XCF and some
|
---|
64 | RAW formats. While the tags listed below are not individually writable, the
|
---|
65 | entire profile itself can be accessed via the extra 'ICC_Profile' tag, but
|
---|
66 | this tag is neither extracted nor written unless specified explicitly. See
|
---|
67 | L<http://www.color.org/icc_specs2.xalter> for the official ICC
|
---|
68 | specification.
|
---|
69 | },
|
---|
70 | A2B0 => 'AToB0',
|
---|
71 | A2B1 => 'AToB1',
|
---|
72 | A2B2 => 'AToB2',
|
---|
73 | bXYZ => 'BlueMatrixColumn', # (called BlueColorant in ref 2)
|
---|
74 | bTRC => {
|
---|
75 | Name => 'BlueTRC',
|
---|
76 | Description => 'Blue Tone Reproduction Curve',
|
---|
77 | },
|
---|
78 | B2A0 => 'BToA0',
|
---|
79 | B2A1 => 'BToA1',
|
---|
80 | B2A2 => 'BToA2',
|
---|
81 | calt => {
|
---|
82 | Name => 'CalibrationDateTime',
|
---|
83 | Groups => { 2 => 'Time' },
|
---|
84 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
85 | },
|
---|
86 | targ => {
|
---|
87 | Name => 'CharTarget',
|
---|
88 | ValueConv => 'length $val > 128 ? \$val : $val',
|
---|
89 | },
|
---|
90 | chad => 'ChromaticAdaptation',
|
---|
91 | chrm => {
|
---|
92 | Name => 'Chromaticity',
|
---|
93 | Groups => { 1 => 'ICC_Profile#' }, #(just for the group list)
|
---|
94 | SubDirectory => {
|
---|
95 | TagTable => 'Image::ExifTool::ICC_Profile::Chromaticity',
|
---|
96 | Validate => '$type eq "chrm"',
|
---|
97 | },
|
---|
98 | },
|
---|
99 | clro => 'ColorantOrder',
|
---|
100 | clrt => {
|
---|
101 | Name => 'ColorantTable',
|
---|
102 | SubDirectory => {
|
---|
103 | TagTable => 'Image::ExifTool::ICC_Profile::ColorantTable',
|
---|
104 | Validate => '$type eq "clrt"',
|
---|
105 | },
|
---|
106 | },
|
---|
107 | clot => { # new in version 4.2
|
---|
108 | Name => 'ColorantTableOut',
|
---|
109 | Binary => 1,
|
---|
110 | },
|
---|
111 | cprt => {
|
---|
112 | Name => 'ProfileCopyright',
|
---|
113 | ValueConv => '$val=~s/\0.*//; $val', # may be null terminated
|
---|
114 | },
|
---|
115 | crdi => 'CRDInfo', #2
|
---|
116 | dmnd => {
|
---|
117 | Name => 'DeviceMfgDesc',
|
---|
118 | Groups => { 2 => 'Camera' },
|
---|
119 | },
|
---|
120 | dmdd => {
|
---|
121 | Name => 'DeviceModelDesc',
|
---|
122 | Groups => { 2 => 'Camera' },
|
---|
123 | },
|
---|
124 | devs => {
|
---|
125 | Name => 'DeviceSettings', #2
|
---|
126 | Groups => { 2 => 'Camera' },
|
---|
127 | },
|
---|
128 | gamt => 'Gamut',
|
---|
129 | kTRC => {
|
---|
130 | Name => 'GrayTRC',
|
---|
131 | Description => 'Gray Tone Reproduction Curve',
|
---|
132 | },
|
---|
133 | gXYZ => 'GreenMatrixColumn', # (called GreenColorant in ref 2)
|
---|
134 | gTRC => {
|
---|
135 | Name => 'GreenTRC',
|
---|
136 | Description => 'Green Tone Reproduction Curve',
|
---|
137 | },
|
---|
138 | lumi => 'Luminance',
|
---|
139 | meas => {
|
---|
140 | Name => 'Measurement',
|
---|
141 | SubDirectory => {
|
---|
142 | TagTable => 'Image::ExifTool::ICC_Profile::Measurement',
|
---|
143 | Validate => '$type eq "meas"',
|
---|
144 | },
|
---|
145 | },
|
---|
146 | bkpt => 'MediaBlackPoint',
|
---|
147 | wtpt => 'MediaWhitePoint',
|
---|
148 | ncol => 'NamedColor', #2
|
---|
149 | ncl2 => 'NamedColor2',
|
---|
150 | resp => 'OutputResponse',
|
---|
151 | pre0 => 'Preview0',
|
---|
152 | pre1 => 'Preview1',
|
---|
153 | pre2 => 'Preview2',
|
---|
154 | desc => 'ProfileDescription',
|
---|
155 | pseq => 'ProfileSequenceDesc',
|
---|
156 | psd0 => 'PostScript2CRD0', #2
|
---|
157 | psd1 => 'PostScript2CRD1', #2
|
---|
158 | psd2 => 'PostScript2CRD2', #2
|
---|
159 | ps2s => 'PostScript2CSA', #2
|
---|
160 | ps2i => 'PS2RenderingIntent', #2
|
---|
161 | rXYZ => 'RedMatrixColumn', # (called RedColorant in ref 2)
|
---|
162 | rTRC => {
|
---|
163 | Name => 'RedTRC',
|
---|
164 | Description => 'Red Tone Reproduction Curve',
|
---|
165 | },
|
---|
166 | scrd => 'ScreeningDesc',
|
---|
167 | scrn => 'Screening',
|
---|
168 | 'bfd '=> {
|
---|
169 | Name => 'UCRBG',
|
---|
170 | Description => 'Under Color Removal and Black Gen.',
|
---|
171 | },
|
---|
172 | tech => {
|
---|
173 | Name => 'Technology',
|
---|
174 | PrintConv => {
|
---|
175 | fscn => 'Film Scanner',
|
---|
176 | dcam => 'Digital Camera',
|
---|
177 | rscn => 'Reflective Scanner',
|
---|
178 | ijet => 'Ink Jet Printer',
|
---|
179 | twax => 'Thermal Wax Printer',
|
---|
180 | epho => 'Electrophotographic Printer',
|
---|
181 | esta => 'Electrostatic Printer',
|
---|
182 | dsub => 'Dye Sublimation Printer',
|
---|
183 | rpho => 'Photographic Paper Printer',
|
---|
184 | fprn => 'Film Writer',
|
---|
185 | vidm => 'Video Monitor',
|
---|
186 | vidc => 'Video Camera',
|
---|
187 | pjtv => 'Projection Television',
|
---|
188 | 'CRT '=> 'Cathode Ray Tube Display',
|
---|
189 | 'PMD '=> 'Passive Matrix Display',
|
---|
190 | 'AMD '=> 'Active Matrix Display',
|
---|
191 | KPCD => 'Photo CD',
|
---|
192 | imgs => 'Photo Image Setter',
|
---|
193 | grav => 'Gravure',
|
---|
194 | offs => 'Offset Lithography',
|
---|
195 | silk => 'Silkscreen',
|
---|
196 | flex => 'Flexography',
|
---|
197 | mpfs => 'Motion Picture Film Scanner', #5
|
---|
198 | mpfr => 'Motion Picture Film Recorder', #5
|
---|
199 | dmpc => 'Digital Motion Picture Camera', #5
|
---|
200 | dcpj => 'Digital Cinema Projector', #5
|
---|
201 | },
|
---|
202 | },
|
---|
203 | vued => 'ViewingCondDesc',
|
---|
204 | view => {
|
---|
205 | Name => 'ViewingConditions',
|
---|
206 | SubDirectory => {
|
---|
207 | TagTable => 'Image::ExifTool::ICC_Profile::ViewingConditions',
|
---|
208 | Validate => '$type eq "view"',
|
---|
209 | },
|
---|
210 | },
|
---|
211 | ciis => 'ColorimetricIntentImageState', #5
|
---|
212 | scoe => 'SceneColorimetryEstimates', #5
|
---|
213 | sape => 'SceneAppearanceEstimates', #5
|
---|
214 | fpce => 'FocalPlaneColorimetryEstimates', #5
|
---|
215 | rhoc => 'ReflectionHardcopyOrigColorimetry', #5
|
---|
216 | rpoc => 'ReflectionPrintOutputColorimetry', #5
|
---|
217 | psid => { #5
|
---|
218 | Name => 'ProfileSequenceIdentifier',
|
---|
219 | Binary => 1,
|
---|
220 | },
|
---|
221 | B2D0 => { Name => 'BToD0', Binary => 1 }, #5
|
---|
222 | B2D1 => { Name => 'BToD1', Binary => 1 }, #5
|
---|
223 | B2D2 => { Name => 'BToD2', Binary => 1 }, #5
|
---|
224 | B2D3 => { Name => 'BToD3', Binary => 1 }, #5
|
---|
225 | D2B0 => { Name => 'DToB0', Binary => 1 }, #5
|
---|
226 | D2B1 => { Name => 'DToB1', Binary => 1 }, #5
|
---|
227 | D2B2 => { Name => 'DToB2', Binary => 1 }, #5
|
---|
228 | D2B3 => { Name => 'DToB3', Binary => 1 }, #5
|
---|
229 | rig0 => { #5
|
---|
230 | Name => 'PerceptualRenderingIntentGamut',
|
---|
231 | PrintConv => {
|
---|
232 | prmg => 'Perceptual Reference Medium Gamut',
|
---|
233 | },
|
---|
234 | },
|
---|
235 | rig2 => { #5
|
---|
236 | Name => 'SaturationRenderingIntentGamut',
|
---|
237 | PrintConv => {
|
---|
238 | prmg => 'Perceptual Reference Medium Gamut',
|
---|
239 | },
|
---|
240 | },
|
---|
241 | meta => { #5 (EVENTUALLY DECODE THIS ONCE WE HAVE A SAMPLE!!)
|
---|
242 | Name => 'Metadata',
|
---|
243 | SubDirectory => {
|
---|
244 | TagTable => 'Image::ExifTool::ICC_Profile::Metadata',
|
---|
245 | Validate => '$type eq "meta"',
|
---|
246 | },
|
---|
247 | },
|
---|
248 |
|
---|
249 | # ColorSync custom tags (ref 3)
|
---|
250 | psvm => 'PS2CRDVMSize',
|
---|
251 | vcgt => 'VideoCardGamma',
|
---|
252 | mmod => 'MakeAndModel',
|
---|
253 | dscm => 'ProfileDescriptionML',
|
---|
254 | ndin => 'NativeDisplayInfo',
|
---|
255 |
|
---|
256 | # Microsoft custom tags (ref http://msdn2.microsoft.com/en-us/library/ms536870.aspx)
|
---|
257 | MS00 => 'WCSProfiles',
|
---|
258 |
|
---|
259 | # the following entry represents the ICC profile header, and doesn't
|
---|
260 | # exist as a tag in the directory. It is only in this table to provide
|
---|
261 | # a link so ExifTool can locate the header tags
|
---|
262 | Header => {
|
---|
263 | Name => 'ProfileHeader',
|
---|
264 | SubDirectory => {
|
---|
265 | TagTable => 'Image::ExifTool::ICC_Profile::Header',
|
---|
266 | },
|
---|
267 | },
|
---|
268 | );
|
---|
269 |
|
---|
270 | # ICC profile header definition
|
---|
271 | %Image::ExifTool::ICC_Profile::Header = (
|
---|
272 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
273 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-header', 2 => 'Image' },
|
---|
274 | 4 => {
|
---|
275 | Name => 'ProfileCMMType',
|
---|
276 | Format => 'string[4]',
|
---|
277 | },
|
---|
278 | 8 => {
|
---|
279 | Name => 'ProfileVersion',
|
---|
280 | Format => 'int16s',
|
---|
281 | PrintConv => '($val >> 8).".".(($val & 0xf0)>>4).".".($val & 0x0f)',
|
---|
282 | },
|
---|
283 | 12 => {
|
---|
284 | Name => 'ProfileClass',
|
---|
285 | Format => 'string[4]',
|
---|
286 | PrintConv => \%profileClass,
|
---|
287 | },
|
---|
288 | 16 => {
|
---|
289 | Name => 'ColorSpaceData',
|
---|
290 | Format => 'string[4]',
|
---|
291 | },
|
---|
292 | 20 => {
|
---|
293 | Name => 'ProfileConnectionSpace',
|
---|
294 | Format => 'string[4]',
|
---|
295 | },
|
---|
296 | 24 => {
|
---|
297 | Name => 'ProfileDateTime',
|
---|
298 | Groups => { 2 => 'Time' },
|
---|
299 | Format => 'int16u[6]',
|
---|
300 | ValueConv => 'sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",split(" ",$val));',
|
---|
301 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
302 | },
|
---|
303 | 36 => {
|
---|
304 | Name => 'ProfileFileSignature',
|
---|
305 | Format => 'string[4]',
|
---|
306 | },
|
---|
307 | 40 => {
|
---|
308 | Name => 'PrimaryPlatform',
|
---|
309 | Format => 'string[4]',
|
---|
310 | PrintConv => {
|
---|
311 | 'APPL' => 'Apple Computer Inc.',
|
---|
312 | 'MSFT' => 'Microsoft Corporation',
|
---|
313 | 'SGI ' => 'Silicon Graphics Inc.',
|
---|
314 | 'SUNW' => 'Sun Microsystems Inc.',
|
---|
315 | 'TGNT' => 'Taligent Inc.',
|
---|
316 | },
|
---|
317 | },
|
---|
318 | 44 => {
|
---|
319 | Name => 'CMMFlags',
|
---|
320 | Format => 'int32u',
|
---|
321 | PrintConv => q[
|
---|
322 | ($val & 0x01 ? "Embedded, " : "Not Embedded, ") .
|
---|
323 | ($val & 0x02 ? "Not Independent" : "Independent")
|
---|
324 | ],
|
---|
325 | },
|
---|
326 | 48 => {
|
---|
327 | Name => 'DeviceManufacturer',
|
---|
328 | Format => 'string[4]',
|
---|
329 | # KODA = Kodak
|
---|
330 | },
|
---|
331 | 52 => {
|
---|
332 | Name => 'DeviceModel',
|
---|
333 | Format => 'string[4]',
|
---|
334 | # ROMM = Refrence Output Medium Metric
|
---|
335 | },
|
---|
336 | 56 => {
|
---|
337 | Name => 'DeviceAttributes',
|
---|
338 | Format => 'int32u[2]',
|
---|
339 | PrintConv => q[
|
---|
340 | my @v = split ' ', $val;
|
---|
341 | ($v[1] & 0x01 ? "Transparency, " : "Reflective, ") .
|
---|
342 | ($v[1] & 0x02 ? "Matte, " : "Glossy, ") .
|
---|
343 | ($v[1] & 0x04 ? "Negative, " : "Positive, ") .
|
---|
344 | ($v[1] & 0x08 ? "B&W" : "Color");
|
---|
345 | ],
|
---|
346 | },
|
---|
347 | 64 => {
|
---|
348 | Name => 'RenderingIntent',
|
---|
349 | Format => 'int32u',
|
---|
350 | PrintConv => {
|
---|
351 | 0 => 'Perceptual',
|
---|
352 | 1 => 'Media-Relative Colorimetric',
|
---|
353 | 2 => 'Saturation',
|
---|
354 | 3 => 'ICC-Absolute Colorimetric',
|
---|
355 | },
|
---|
356 | },
|
---|
357 | 68 => {
|
---|
358 | Name => 'ConnectionSpaceIlluminant',
|
---|
359 | Format => 'fixed32s[3]', # xyz
|
---|
360 | },
|
---|
361 | 80 => {
|
---|
362 | Name => 'ProfileCreator',
|
---|
363 | Format => 'string[4]',
|
---|
364 | # KODA = Kodak
|
---|
365 | },
|
---|
366 | 84 => {
|
---|
367 | Name => 'ProfileID',
|
---|
368 | Format => 'int8u[16]',
|
---|
369 | PrintConv => 'Image::ExifTool::ICC_Profile::HexID($val)',
|
---|
370 | },
|
---|
371 | );
|
---|
372 |
|
---|
373 | # viewingConditionsType (view) definition
|
---|
374 | %Image::ExifTool::ICC_Profile::ViewingConditions = (
|
---|
375 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
376 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-view', 2 => 'Image' },
|
---|
377 | 8 => {
|
---|
378 | Name => 'ViewingCondIlluminant',
|
---|
379 | Format => 'fixed32s[3]', # xyz
|
---|
380 | },
|
---|
381 | 20 => {
|
---|
382 | Name => 'ViewingCondSurround',
|
---|
383 | Format => 'fixed32s[3]', # xyz
|
---|
384 | },
|
---|
385 | 32 => {
|
---|
386 | Name => 'ViewingCondIlluminantType',
|
---|
387 | Format => 'int32u',
|
---|
388 | PrintConv => \%illuminantType,
|
---|
389 | },
|
---|
390 | );
|
---|
391 |
|
---|
392 | # measurementType (meas) definition
|
---|
393 | %Image::ExifTool::ICC_Profile::Measurement = (
|
---|
394 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
395 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-meas', 2 => 'Image' },
|
---|
396 | 8 => {
|
---|
397 | Name => 'MeasurementObserver',
|
---|
398 | Format => 'int32u',
|
---|
399 | PrintConv => {
|
---|
400 | 1 => 'CIE 1931',
|
---|
401 | 2 => 'CIE 1964',
|
---|
402 | },
|
---|
403 | },
|
---|
404 | 12 => {
|
---|
405 | Name => 'MeasurementBacking',
|
---|
406 | Format => 'fixed32s[3]', # xyz
|
---|
407 | },
|
---|
408 | 24 => {
|
---|
409 | Name => 'MeasurementGeometry',
|
---|
410 | Format => 'int32u',
|
---|
411 | PrintConv => {
|
---|
412 | 1 => '0/45 or 45/0',
|
---|
413 | 2 => '0/d or d/0',
|
---|
414 | },
|
---|
415 | },
|
---|
416 | 28 => {
|
---|
417 | Name => 'MeasurementFlare',
|
---|
418 | Format => 'fixed32u',
|
---|
419 | PrintConv => '$val*100 . "%"', # change into a percent
|
---|
420 | },
|
---|
421 | 32 => {
|
---|
422 | Name => 'MeasurementIlluminant',
|
---|
423 | Format => 'int32u',
|
---|
424 | PrintConv => \%illuminantType,
|
---|
425 | },
|
---|
426 | );
|
---|
427 |
|
---|
428 | # chromaticity (chrm) definition
|
---|
429 | %Image::ExifTool::ICC_Profile::Chromaticity = (
|
---|
430 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
431 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-chrm', 2 => 'Image' },
|
---|
432 | 8 => {
|
---|
433 | Name => 'ChromaticityChannels',
|
---|
434 | Format => 'int16u',
|
---|
435 | },
|
---|
436 | 10 => {
|
---|
437 | Name => 'ChromaticityColorant',
|
---|
438 | Format => 'int16u',
|
---|
439 | PrintConv => {
|
---|
440 | 1 => 'ITU-R BT.709',
|
---|
441 | 2 => 'SMPTE RP145-1994',
|
---|
442 | 3 => 'EBU Tech.3213-E',
|
---|
443 | 4 => 'P22',
|
---|
444 | },
|
---|
445 | },
|
---|
446 | # include definitions for 4 channels -- if there are
|
---|
447 | # fewer then the ProcessBinaryData logic won't print them.
|
---|
448 | # If there are more, oh well.
|
---|
449 | 12 => {
|
---|
450 | Name => 'ChromaticityChannel1',
|
---|
451 | Format => 'fixed32u[2]',
|
---|
452 | },
|
---|
453 | 20 => {
|
---|
454 | Name => 'ChromaticityChannel2',
|
---|
455 | Format => 'fixed32u[2]',
|
---|
456 | },
|
---|
457 | 28 => {
|
---|
458 | Name => 'ChromaticityChannel3',
|
---|
459 | Format => 'fixed32u[2]',
|
---|
460 | },
|
---|
461 | 36 => {
|
---|
462 | Name => 'ChromaticityChannel4',
|
---|
463 | Format => 'fixed32u[2]',
|
---|
464 | },
|
---|
465 | );
|
---|
466 |
|
---|
467 | # colorantTable (clrt) definition
|
---|
468 | %Image::ExifTool::ICC_Profile::ColorantTable = (
|
---|
469 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
470 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-clrt', 2 => 'Image' },
|
---|
471 | 8 => {
|
---|
472 | Name => 'ColorantCount',
|
---|
473 | Format => 'int32u',
|
---|
474 | },
|
---|
475 | # include definitions for 3 colorants -- if there are
|
---|
476 | # fewer then the ProcessBinaryData logic won't print them.
|
---|
477 | # If there are more, oh well.
|
---|
478 | 12 => {
|
---|
479 | Name => 'Colorant1Name',
|
---|
480 | Format => 'string[32]',
|
---|
481 | },
|
---|
482 | 44 => {
|
---|
483 | Name => 'Colorant1Coordinates',
|
---|
484 | Format => 'int16u[3]',
|
---|
485 | },
|
---|
486 | 50 => {
|
---|
487 | Name => 'Colorant2Name',
|
---|
488 | Format => 'string[32]',
|
---|
489 | },
|
---|
490 | 82 => {
|
---|
491 | Name => 'Colorant2Coordinates',
|
---|
492 | Format => 'int16u[3]',
|
---|
493 | },
|
---|
494 | 88 => {
|
---|
495 | Name => 'Colorant3Name',
|
---|
496 | Format => 'string[32]',
|
---|
497 | },
|
---|
498 | 120 => {
|
---|
499 | Name => 'Colorant3Coordinates',
|
---|
500 | Format => 'int16u[3]',
|
---|
501 | },
|
---|
502 | );
|
---|
503 |
|
---|
504 | # metadata (meta) tags
|
---|
505 | %Image::ExifTool::ICC_Profile::Metadata = (
|
---|
506 | PROCESS_PROC => \&ProcessMetadata,
|
---|
507 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-meta', 2 => 'Image' },
|
---|
508 | VARS => { NO_ID => 1 },
|
---|
509 | NOTES => q{
|
---|
510 | Only these few tags have been pre-defined, but ExifTool will extract any
|
---|
511 | Metadata tags that exist.
|
---|
512 | },
|
---|
513 | ManufacturerName => { },
|
---|
514 | MediaColor => { },
|
---|
515 | MediaWeight => { },
|
---|
516 | );
|
---|
517 |
|
---|
518 | #------------------------------------------------------------------------------
|
---|
519 | # print ICC Profile ID in hex
|
---|
520 | # Inputs: 1) string of numbers
|
---|
521 | # Returns: string of hex digits
|
---|
522 | sub HexID($)
|
---|
523 | {
|
---|
524 | my $val = shift;
|
---|
525 | my @vals = split(' ', $val);
|
---|
526 | # return a simple zero if no MD5 done
|
---|
527 | return 0 unless grep(!/^0/, @vals);
|
---|
528 | $val = '';
|
---|
529 | foreach (@vals) { $val .= sprintf("%.2x",$_); }
|
---|
530 | return $val;
|
---|
531 | }
|
---|
532 |
|
---|
533 | #------------------------------------------------------------------------------
|
---|
534 | # get formatted value from ICC tag (which has the type embedded)
|
---|
535 | # Inputs: 0) data reference, 1) offset to tag data, 2) tag data size
|
---|
536 | # Returns: Formatted value or undefined if format not supported
|
---|
537 | # Notes: The following types are handled by BinaryTables:
|
---|
538 | # chromaticityType, colorantTableType, measurementType, viewingConditionsType
|
---|
539 | # The following types are not currently handled (most are large tables):
|
---|
540 | # curveType, lut16Type, lut8Type, lutAtoBType, lutBtoAType, namedColor2Type,
|
---|
541 | # parametricCurveType, profileSeqDescType, responseCurveSet16Type
|
---|
542 | # The multiLocalizedUnicodeType must be handled by the calling routine.
|
---|
543 | sub FormatICCTag($$$)
|
---|
544 | {
|
---|
545 | my ($dataPt, $offset, $size) = @_;
|
---|
546 |
|
---|
547 | my $type;
|
---|
548 | if ($size >= 8) {
|
---|
549 | # get data type from start of tag data
|
---|
550 | $type = substr($$dataPt, $offset, 4);
|
---|
551 | } else {
|
---|
552 | $type = 'err';
|
---|
553 | }
|
---|
554 | # colorantOrderType
|
---|
555 | if ($type eq 'clro' and $size >= 12) {
|
---|
556 | my $num = Get32u($dataPt, $offset+8);
|
---|
557 | if ($size >= $num + 12) {
|
---|
558 | my $pos = $offset + 12;
|
---|
559 | return join(' ',unpack("x$pos c$num", $$dataPt));
|
---|
560 | }
|
---|
561 | }
|
---|
562 | # dataType
|
---|
563 | if ($type eq 'data' and $size >= 12) {
|
---|
564 | my $form = Get32u($dataPt, $offset+8);
|
---|
565 | # format 0 is ASCII data
|
---|
566 | $form == 0 and return substr($$dataPt, $offset+12, $size-12);
|
---|
567 | # binary data and other data types treat as binary (ie. don't format)
|
---|
568 | }
|
---|
569 | # dateTimeType
|
---|
570 | if ($type eq 'dtim' and $size >= 20) {
|
---|
571 | return sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",
|
---|
572 | Get16u($dataPt, $offset+8), Get16u($dataPt, $offset+10),
|
---|
573 | Get16u($dataPt, $offset+12), Get16u($dataPt, $offset+14),
|
---|
574 | Get16u($dataPt, $offset+16), Get16u($dataPt, $offset+18));
|
---|
575 | }
|
---|
576 | # s15Fixed16ArrayType
|
---|
577 | if ($type eq 'sf32') {
|
---|
578 | return ReadValue($dataPt,$offset+8,'fixed32s',($size-8)/4,$size-8);
|
---|
579 | }
|
---|
580 | # signatureType
|
---|
581 | if ($type eq 'sig ' and $size >= 12) {
|
---|
582 | return substr($$dataPt, $offset+8, 4);
|
---|
583 | }
|
---|
584 | # textType
|
---|
585 | $type eq 'text' and return substr($$dataPt, $offset+8, $size-8);
|
---|
586 | # textDescriptionType (ref 2, replaced by multiLocalizedUnicodeType)
|
---|
587 | if ($type eq 'desc' and $size >= 12) {
|
---|
588 | my $len = Get32u($dataPt, $offset+8);
|
---|
589 | if ($size >= $len + 12) {
|
---|
590 | my $str = substr($$dataPt, $offset+12, $len);
|
---|
591 | $str =~ s/\0.*//s; # truncate at null terminator
|
---|
592 | return $str;
|
---|
593 | }
|
---|
594 | }
|
---|
595 | # u16Fixed16ArrayType
|
---|
596 | if ($type eq 'uf32') {
|
---|
597 | return ReadValue($dataPt,$offset+8,'fixed32u',($size-8)/4,$size-8);
|
---|
598 | }
|
---|
599 | # uInt32ArrayType
|
---|
600 | if ($type eq 'ui32') {
|
---|
601 | return ReadValue($dataPt,$offset+8,'int32u',($size-8)/4,$size-8);
|
---|
602 | }
|
---|
603 | # uInt64ArrayType
|
---|
604 | if ($type eq 'ui64') {
|
---|
605 | return ReadValue($dataPt,$offset+8,'int64u',($size-8)/8,$size-8);
|
---|
606 | }
|
---|
607 | # uInt8ArrayType
|
---|
608 | if ($type eq 'ui08') {
|
---|
609 | return ReadValue($dataPt,$offset+8,'int8u',$size-8,$size-8);
|
---|
610 | }
|
---|
611 | # XYZType
|
---|
612 | if ($type eq 'XYZ ') {
|
---|
613 | my $str = '';
|
---|
614 | my $pos;
|
---|
615 | for ($pos=8; $pos+12<=$size; $pos+=12) {
|
---|
616 | $str and $str .= ', ';
|
---|
617 | $str .= ReadValue($dataPt,$offset+$pos,'fixed32s',3,$size-$pos);
|
---|
618 | }
|
---|
619 | return $str;
|
---|
620 | }
|
---|
621 | return undef; # data type is not supported
|
---|
622 | }
|
---|
623 |
|
---|
624 | #------------------------------------------------------------------------------
|
---|
625 | # Process ICC metadata record (ref 5) (UNTESTED!)
|
---|
626 | # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
---|
627 | # Returns: 1 on success
|
---|
628 | sub ProcessMetadata($$$)
|
---|
629 | {
|
---|
630 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
631 | my $dataPt = $$dirInfo{DataPt};
|
---|
632 | my $dirStart = $$dirInfo{DirStart};
|
---|
633 | my $dirLen = $$dirInfo{DirLen};
|
---|
634 | my $dirEnd = $dirStart + $dirLen;
|
---|
635 |
|
---|
636 | if ($dirLen < 16 or substr($$dataPt, $dirStart, 4) ne 'dict') {
|
---|
637 | $exifTool->Warn('Invalid ICC meta dictionary');
|
---|
638 | return 0;
|
---|
639 | }
|
---|
640 | my $num = Get32u($dataPt, $dirStart + 8);
|
---|
641 | $exifTool->VerboseDir('Metadata', $num);
|
---|
642 | my $size = Get32u($dataPt, $dirStart + 12);
|
---|
643 | $size < 16 and $exifTool->Warn('Invalid ICC meta record size'), return 0;
|
---|
644 | # NOTE: In the example the minimum offset is 20,
|
---|
645 | # but this doesn't jive with the table (both in ref 5)
|
---|
646 | my $minPtr = 16 + $size * $num;
|
---|
647 | my $index;
|
---|
648 | for ($index=0; $index<$num; ++$index) {
|
---|
649 | my $entry = $dirStart + 16 + $size * $index;
|
---|
650 | if ($entry + $size > $dirEnd) {
|
---|
651 | $exifTool->Warn('Truncated ICC meta dictionary');
|
---|
652 | last;
|
---|
653 | }
|
---|
654 | my $namePtr = Get32u($dataPt, $entry);
|
---|
655 | my $nameLen = Get32u($dataPt, $entry + 4);
|
---|
656 | my $valuePtr = Get32u($dataPt, $entry + 8);
|
---|
657 | my $valueLen = Get32u($dataPt, $entry + 16);
|
---|
658 | next unless $namePtr and $valuePtr; # ignore if offsets are zero
|
---|
659 | if ($namePtr < $minPtr or $namePtr + $nameLen > $dirLen or
|
---|
660 | $valuePtr < $minPtr or $valuePtr + $valueLen > $dirLen)
|
---|
661 | {
|
---|
662 | $exifTool->Warn('Corrupted ICC meta dictionary');
|
---|
663 | last;
|
---|
664 | }
|
---|
665 | my $tag = substr($dataPt, $dirStart + $namePtr, $nameLen);
|
---|
666 | my $val = substr($dataPt, $dirStart + $valuePtr, $valueLen);
|
---|
667 | $tag = $exifTool->Decode($tag, 'UTF16', 'MM', 'UTF8');
|
---|
668 | $val = $exifTool->Decode($val, 'UTF16', 'MM');
|
---|
669 | # generate tagInfo if it doesn't exist
|
---|
670 | unless ($$tagTablePtr{$tag}) {
|
---|
671 | my $name = ucfirst $tag;
|
---|
672 | $name =~ s/\s+(.)/\u$1/g;
|
---|
673 | $name =~ tr/-_a-zA-Z0-9//dc;
|
---|
674 | next unless length $name;
|
---|
675 | Image::ExifTool::AddTagToTable($tagTablePtr, $tag, { Name => $name });
|
---|
676 | }
|
---|
677 | $exifTool->HandleTag($tagTablePtr, $tag, $val);
|
---|
678 | }
|
---|
679 | return 1;
|
---|
680 | }
|
---|
681 |
|
---|
682 | #------------------------------------------------------------------------------
|
---|
683 | # Write ICC profile file
|
---|
684 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
685 | # Returns: 1 on success, 0 if this wasn't a valid ICC file,
|
---|
686 | # or -1 if a write error occurred
|
---|
687 | sub WriteICC($$)
|
---|
688 | {
|
---|
689 | my ($exifTool, $dirInfo) = @_;
|
---|
690 | # first make sure this is a valid ICC file (or no file at all)
|
---|
691 | my $raf = $$dirInfo{RAF};
|
---|
692 | my $buff;
|
---|
693 | return 0 if $raf->Read($buff, 24) and ValidateICC(\$buff);
|
---|
694 | # now write the new ICC
|
---|
695 | $buff = WriteICC_Profile($exifTool, $dirInfo);
|
---|
696 | if (defined $buff and length $buff) {
|
---|
697 | Write($$dirInfo{OutFile}, $buff) or return -1;
|
---|
698 | } else {
|
---|
699 | $exifTool->Error('No ICC information to write');
|
---|
700 | }
|
---|
701 | return 1;
|
---|
702 | }
|
---|
703 |
|
---|
704 | #------------------------------------------------------------------------------
|
---|
705 | # Write ICC data as a block
|
---|
706 | # Inputs: 0) ExifTool object reference, 1) source dirInfo reference,
|
---|
707 | # 2) tag table reference
|
---|
708 | # Returns: ICC data block (may be empty if no ICC data)
|
---|
709 | # Notes: Increments ExifTool CHANGED flag if changed
|
---|
710 | sub WriteICC_Profile($$;$)
|
---|
711 | {
|
---|
712 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
713 | $exifTool or return 1; # allow dummy access
|
---|
714 | my $dirName = $$dirInfo{DirName} || 'ICC_Profile';
|
---|
715 | # (don't write AsShotICCProfile or CurrentICCProfile here)
|
---|
716 | return undef unless $dirName eq 'ICC_Profile';
|
---|
717 | my $nvHash = $exifTool->GetNewValueHash($Image::ExifTool::Extra{$dirName});
|
---|
718 | return undef unless Image::ExifTool::IsOverwriting($nvHash);
|
---|
719 | my $val = Image::ExifTool::GetNewValues($nvHash);
|
---|
720 | $val = '' unless defined $val;
|
---|
721 | ++$exifTool->{CHANGED};
|
---|
722 | return $val;
|
---|
723 | }
|
---|
724 |
|
---|
725 | #------------------------------------------------------------------------------
|
---|
726 | # Validate ICC data
|
---|
727 | # Inputs: 0) ICC data reference
|
---|
728 | # Returns: error string or undef on success
|
---|
729 | sub ValidateICC($)
|
---|
730 | {
|
---|
731 | my $valPtr = shift;
|
---|
732 | my $err;
|
---|
733 | length($$valPtr) < 24 and return 'Invalid ICC profile';
|
---|
734 | $profileClass{substr($$valPtr, 12, 4)} or $err = 'profile class';
|
---|
735 | my $col = substr($$valPtr, 16, 4); # ColorSpaceData
|
---|
736 | my $con = substr($$valPtr, 20, 4); # ConnectionSpace
|
---|
737 | my $match = '(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR)';
|
---|
738 | $col =~ /$match/ or $err = 'color space';
|
---|
739 | $con =~ /$match/ or $err = 'connection space';
|
---|
740 | return $err ? "Invalid ICC profile (bad $err)" : undef;
|
---|
741 | }
|
---|
742 |
|
---|
743 | #------------------------------------------------------------------------------
|
---|
744 | # Process ICC profile file
|
---|
745 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
746 | # Returns: 1 if this was an ICC file
|
---|
747 | sub ProcessICC($$)
|
---|
748 | {
|
---|
749 | my ($exifTool, $dirInfo) = @_;
|
---|
750 | my $raf = $$dirInfo{RAF};
|
---|
751 | my $buff;
|
---|
752 | $raf->Read($buff, 24) == 24 or return 0;
|
---|
753 | # check to see if this is a valid ICC profile file
|
---|
754 | return 0 if ValidateICC(\$buff);
|
---|
755 | $exifTool->SetFileType();
|
---|
756 | # read the profile
|
---|
757 | my $size = unpack('N', $buff);
|
---|
758 | if ($size < 128 or $size & 0x80000000) {
|
---|
759 | $exifTool->Error("Bad ICC Profile length ($size)");
|
---|
760 | return 1;
|
---|
761 | }
|
---|
762 | $raf->Seek(0, 0);
|
---|
763 | unless ($raf->Read($buff, $size)) {
|
---|
764 | $exifTool->Error('Truncated ICC profile');
|
---|
765 | return 1;
|
---|
766 | }
|
---|
767 | my %dirInfo = (
|
---|
768 | DataPt => \$buff,
|
---|
769 | DataLen => $size,
|
---|
770 | DirStart => 0,
|
---|
771 | DirLen => $size,
|
---|
772 | );
|
---|
773 | my $tagTablePtr = GetTagTable('Image::ExifTool::ICC_Profile::Main');
|
---|
774 | return ProcessICC_Profile($exifTool, \%dirInfo, $tagTablePtr);
|
---|
775 | }
|
---|
776 |
|
---|
777 | #------------------------------------------------------------------------------
|
---|
778 | # Process ICC_Profile APP13 record
|
---|
779 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
780 | # 2) Tag table reference (undefined to read ICC file)
|
---|
781 | # Returns: 1 on success
|
---|
782 | sub ProcessICC_Profile($$$)
|
---|
783 | {
|
---|
784 | my ($exifTool, $dirInfo, $tagTablePtr) = @_;
|
---|
785 | my $dataPt = $$dirInfo{DataPt};
|
---|
786 | my $dirStart = $$dirInfo{DirStart};
|
---|
787 | my $dirLen = $$dirInfo{DirLen};
|
---|
788 | my $verbose = $exifTool->Options('Verbose');
|
---|
789 |
|
---|
790 | return 0 if $dirLen < 4;
|
---|
791 |
|
---|
792 | # extract binary ICC_Profile data block if binary mode or requested
|
---|
793 | if ($exifTool->{OPTIONS}->{Binary} or $exifTool->{REQ_TAG_LOOKUP}->{icc_profile} and
|
---|
794 | # (don't extract from AsShotICCProfile or CurrentICCProfile)
|
---|
795 | (not $$dirInfo{Name} or $$dirInfo{Name} eq 'ICC_Profile'))
|
---|
796 | {
|
---|
797 | $exifTool->FoundTag('ICC_Profile', substr($$dataPt, $dirStart, $dirLen));
|
---|
798 | }
|
---|
799 |
|
---|
800 | SetByteOrder('MM'); # ICC_Profile is always big-endian
|
---|
801 |
|
---|
802 | # check length of table
|
---|
803 | my $len = Get32u($dataPt, $dirStart);
|
---|
804 | if ($len != $dirLen or $len < 128) {
|
---|
805 | $exifTool->Warn("Bad length ICC_Profile (length $len)");
|
---|
806 | return 0 if $len < 128 or $dirLen < $len;
|
---|
807 | }
|
---|
808 | my $pos = $dirStart + 128; # position at start of table
|
---|
809 | my $numEntries = Get32u($dataPt, $pos);
|
---|
810 | if ($numEntries < 1 or $numEntries >= 0x100
|
---|
811 | or $numEntries * 12 + 132 > $dirLen)
|
---|
812 | {
|
---|
813 | $exifTool->Warn("Bad ICC_Profile table ($numEntries entries)");
|
---|
814 | return 0;
|
---|
815 | }
|
---|
816 |
|
---|
817 | if ($verbose) {
|
---|
818 | $exifTool->VerboseDir('ICC_Profile', $numEntries, $dirLen);
|
---|
819 | my $fakeInfo = { Name=>'ProfileHeader', SubDirectory => { } };
|
---|
820 | $exifTool->VerboseInfo(undef, $fakeInfo);
|
---|
821 | }
|
---|
822 | # increment ICC dir count
|
---|
823 | my $dirCount = $exifTool->{DIR_COUNT}->{ICC} = ($exifTool->{DIR_COUNT}->{ICC} || 0) + 1;
|
---|
824 | $exifTool->{SET_GROUP1} = '+' . $dirCount if $dirCount > 1;
|
---|
825 | # process the header block
|
---|
826 | my %subdirInfo = (
|
---|
827 | Name => 'ProfileHeader',
|
---|
828 | DataPt => $dataPt,
|
---|
829 | DataLen => $$dirInfo{DataLen},
|
---|
830 | DirStart => $dirStart,
|
---|
831 | DirLen => 128,
|
---|
832 | Parent => $$dirInfo{DirName},
|
---|
833 | );
|
---|
834 | my $newTagTable = GetTagTable('Image::ExifTool::ICC_Profile::Header');
|
---|
835 | $exifTool->ProcessDirectory(\%subdirInfo, $newTagTable);
|
---|
836 |
|
---|
837 | $pos += 4; # skip item count
|
---|
838 | my $index;
|
---|
839 | for ($index=0; $index<$numEntries; ++$index) {
|
---|
840 | my $tagID = substr($$dataPt, $pos, 4);
|
---|
841 | my $offset = Get32u($dataPt, $pos + 4);
|
---|
842 | my $size = Get32u($dataPt, $pos + 8);
|
---|
843 | $pos += 12;
|
---|
844 | my $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tagID);
|
---|
845 | # unknown tags aren't generated automatically by GetTagInfo()
|
---|
846 | # if the tagID's aren't numeric, so we must do this manually:
|
---|
847 | if (not $tagInfo and $exifTool->{OPTIONS}->{Unknown}) {
|
---|
848 | $tagInfo = { Unknown => 1 };
|
---|
849 | Image::ExifTool::AddTagToTable($tagTablePtr, $tagID, $tagInfo);
|
---|
850 | }
|
---|
851 | next unless defined $tagInfo;
|
---|
852 |
|
---|
853 | if ($offset + $size > $dirLen) {
|
---|
854 | $exifTool->Warn("Bad ICC_Profile table (truncated)");
|
---|
855 | last;
|
---|
856 | }
|
---|
857 | my $valuePtr = $dirStart + $offset;
|
---|
858 |
|
---|
859 | my $subdir = $$tagInfo{SubDirectory};
|
---|
860 | # format the value unless this is a subdirectory
|
---|
861 | my ($value, $fmt);
|
---|
862 | if ($size > 4) {
|
---|
863 | $fmt = substr($$dataPt, $valuePtr, 4);
|
---|
864 | # handle multiLocalizedUnicodeType
|
---|
865 | if ($fmt eq 'mluc' and not $subdir) {
|
---|
866 | next if $size < 28;
|
---|
867 | my $count = Get32u($dataPt, $valuePtr + 8);
|
---|
868 | my $recLen = Get32u($dataPt, $valuePtr + 12);
|
---|
869 | next if $recLen < 12;
|
---|
870 | my $i;
|
---|
871 | for ($i=0; $i<$count; ++$i) {
|
---|
872 | my $recPos = $valuePtr + 16 + $i * $recLen;
|
---|
873 | last if $recPos + $recLen > $valuePtr + $size;
|
---|
874 | my $lang = substr($$dataPt, $recPos, 4);
|
---|
875 | my $langInfo;
|
---|
876 | # validate language code and change to standard case (just in case)
|
---|
877 | if ($lang =~ s/^([a-z]{2})([A-Z]{2})$/\L$1-\U$2/i and $lang ne 'en-US') {
|
---|
878 | $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang);
|
---|
879 | }
|
---|
880 | my $strLen = Get32u($dataPt, $recPos + 4);
|
---|
881 | my $strPos = Get32u($dataPt, $recPos + 8);
|
---|
882 | last if $strPos + $strLen > $size;
|
---|
883 | my $str = substr($$dataPt, $valuePtr + $strPos, $strLen);
|
---|
884 | $str = $exifTool->Decode($str, 'UTF16');
|
---|
885 | $exifTool->HandleTag($tagTablePtr, $tagID, $str,
|
---|
886 | TagInfo => $langInfo || $tagInfo,
|
---|
887 | Table => $tagTablePtr,
|
---|
888 | Index => $index,
|
---|
889 | Value => $str,
|
---|
890 | DataPt => $dataPt,
|
---|
891 | Size => $strLen,
|
---|
892 | Start => $valuePtr + $strPos,
|
---|
893 | Format => "type '$fmt'",
|
---|
894 | );
|
---|
895 | }
|
---|
896 | $exifTool->Warn("Corrupted $$tagInfo{Name} data") if $i < $count;
|
---|
897 | next;
|
---|
898 | }
|
---|
899 | } else {
|
---|
900 | $fmt = 'err ';
|
---|
901 | }
|
---|
902 | $value = FormatICCTag($dataPt, $valuePtr, $size) unless $subdir;
|
---|
903 | $verbose and $exifTool->VerboseInfo($tagID, $tagInfo,
|
---|
904 | Table => $tagTablePtr,
|
---|
905 | Index => $index,
|
---|
906 | Value => $value,
|
---|
907 | DataPt => $dataPt,
|
---|
908 | Size => $size,
|
---|
909 | Start => $valuePtr,
|
---|
910 | Format => "type '$fmt'",
|
---|
911 | );
|
---|
912 | if ($subdir) {
|
---|
913 | my $name = $$tagInfo{Name};
|
---|
914 | undef $newTagTable;
|
---|
915 | if ($$subdir{TagTable}) {
|
---|
916 | $newTagTable = GetTagTable($$subdir{TagTable});
|
---|
917 | unless ($newTagTable) {
|
---|
918 | warn "Unknown tag table $$subdir{TagTable}\n";
|
---|
919 | next;
|
---|
920 | }
|
---|
921 | } else {
|
---|
922 | warn "Must specify TagTable for SubDirectory $name\n";
|
---|
923 | next;
|
---|
924 | }
|
---|
925 | %subdirInfo = (
|
---|
926 | Name => $name,
|
---|
927 | DataPt => $dataPt,
|
---|
928 | DataPos => $$dirInfo{DataPos},
|
---|
929 | DataLen => $$dirInfo{DataLen},
|
---|
930 | DirStart => $valuePtr,
|
---|
931 | DirLen => $size,
|
---|
932 | Parent => $$dirInfo{DirName},
|
---|
933 | );
|
---|
934 | my $type = substr($$dataPt, $valuePtr, 4);
|
---|
935 | #### eval Validate ($type)
|
---|
936 | if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
|
---|
937 | $exifTool->Warn("Invalid $name data");
|
---|
938 | } else {
|
---|
939 | $exifTool->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
|
---|
940 | }
|
---|
941 | } elsif (defined $value) {
|
---|
942 | $exifTool->FoundTag($tagInfo, $value);
|
---|
943 | } else {
|
---|
944 | $value = substr($$dataPt, $valuePtr, $size);
|
---|
945 | # treat unsupported formats as binary data
|
---|
946 | $$tagInfo{ValueConv} = '\$val' unless defined $$tagInfo{ValueConv};
|
---|
947 | $exifTool->FoundTag($tagInfo, $value);
|
---|
948 | }
|
---|
949 | }
|
---|
950 | delete $exifTool->{SET_GROUP1};
|
---|
951 | return 1;
|
---|
952 | }
|
---|
953 |
|
---|
954 |
|
---|
955 | 1; # end
|
---|
956 |
|
---|
957 |
|
---|
958 | __END__
|
---|
959 |
|
---|
960 | =head1 NAME
|
---|
961 |
|
---|
962 | Image::ExifTool::ICC_Profile - Read ICC Profile meta information
|
---|
963 |
|
---|
964 | =head1 SYNOPSIS
|
---|
965 |
|
---|
966 | This module is loaded automatically by Image::ExifTool when required.
|
---|
967 |
|
---|
968 | =head1 DESCRIPTION
|
---|
969 |
|
---|
970 | This module contains the definitions to read information from ICC profiles.
|
---|
971 | ICC (International Color Consortium) profiles are used to translate color
|
---|
972 | data created on one device into another device's native color space.
|
---|
973 |
|
---|
974 | =head1 AUTHOR
|
---|
975 |
|
---|
976 | Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
|
---|
977 |
|
---|
978 | This library is free software; you can redistribute it and/or modify it
|
---|
979 | under the same terms as Perl itself.
|
---|
980 |
|
---|
981 | =head1 REFERENCES
|
---|
982 |
|
---|
983 | =over 4
|
---|
984 |
|
---|
985 | =item L<http://www.color.org/icc_specs2.html>
|
---|
986 |
|
---|
987 | =item L<http://developer.apple.com/documentation/GraphicsImaging/Reference/ColorSync_Manager/ColorSync_Manager.pdf>
|
---|
988 |
|
---|
989 | =back
|
---|
990 |
|
---|
991 | =head1 SEE ALSO
|
---|
992 |
|
---|
993 | L<Image::ExifTool::TagNames/ICC_Profile Tags>,
|
---|
994 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
995 |
|
---|
996 | =cut
|
---|