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 | # 6) Eef Vreeland private communication
|
---|
14 | #
|
---|
15 | # Notes: The ICC profile information is different: the format of each
|
---|
16 | # tag is embedded in the information instead of in the directory
|
---|
17 | # structure. This makes things a bit more complex because I need
|
---|
18 | # an extra level of logic to decode the variable-format tags.
|
---|
19 | #------------------------------------------------------------------------------
|
---|
20 |
|
---|
21 | package Image::ExifTool::ICC_Profile;
|
---|
22 |
|
---|
23 | use strict;
|
---|
24 | use vars qw($VERSION);
|
---|
25 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
26 |
|
---|
27 | $VERSION = '1.36';
|
---|
28 |
|
---|
29 | sub ProcessICC($$);
|
---|
30 | sub ProcessICC_Profile($$$);
|
---|
31 | sub WriteICC_Profile($$;$);
|
---|
32 | sub ProcessMetadata($$$);
|
---|
33 | sub ValidateICC($);
|
---|
34 |
|
---|
35 | # illuminant type definitions
|
---|
36 | my %illuminantType = (
|
---|
37 | 1 => 'D50',
|
---|
38 | 2 => 'D65',
|
---|
39 | 3 => 'D93',
|
---|
40 | 4 => 'F2',
|
---|
41 | 5 => 'D55',
|
---|
42 | 6 => 'A',
|
---|
43 | 7 => 'Equi-Power (E)',
|
---|
44 | 8 => 'F8',
|
---|
45 | );
|
---|
46 | my %profileClass = (
|
---|
47 | scnr => 'Input Device Profile',
|
---|
48 | mntr => 'Display Device Profile',
|
---|
49 | prtr => 'Output Device Profile',
|
---|
50 | 'link'=> 'DeviceLink Profile',
|
---|
51 | spac => 'ColorSpace Conversion Profile',
|
---|
52 | abst => 'Abstract Profile',
|
---|
53 | nmcl => 'NamedColor Profile',
|
---|
54 | nkpf => 'Nikon Input Device Profile (NON-STANDARD!)', # (written by Nikon utilities)
|
---|
55 | );
|
---|
56 | my %manuSig = ( #6
|
---|
57 | 'NONE' => 'none',
|
---|
58 | 'none' => 'none', #PH
|
---|
59 | '' => '', #PH
|
---|
60 | '4d2p' => 'Erdt Systems GmbH & Co KG',
|
---|
61 | 'AAMA' => 'Aamazing Technologies, Inc.',
|
---|
62 | 'ACER' => 'Acer Peripherals',
|
---|
63 | 'ACLT' => 'Acolyte Color Research',
|
---|
64 | 'ACTI' => 'Actix Systems, Inc.',
|
---|
65 | 'ADAR' => 'Adara Technology, Inc.',
|
---|
66 | 'ADBE' => 'Adobe Systems Inc.',
|
---|
67 | 'ADI ' => 'ADI Systems, Inc.',
|
---|
68 | 'AGFA' => 'Agfa Graphics N.V.',
|
---|
69 | 'ALMD' => 'Alps Electric USA, Inc.',
|
---|
70 | 'ALPS' => 'Alps Electric USA, Inc.',
|
---|
71 | 'ALWN' => 'Alwan Color Expertise',
|
---|
72 | 'AMTI' => 'Amiable Technologies, Inc.',
|
---|
73 | 'AOC ' => 'AOC International (U.S.A), Ltd.',
|
---|
74 | 'APAG' => 'Apago',
|
---|
75 | 'APPL' => 'Apple Computer Inc.',
|
---|
76 | 'appl' => 'Apple Computer Inc.',
|
---|
77 | 'AST ' => 'AST',
|
---|
78 | 'AT&T' => 'AT&T Computer Systems',
|
---|
79 | 'BAEL' => 'BARBIERI electronic',
|
---|
80 | 'berg' => 'bergdesign incorporated',
|
---|
81 | 'bICC' => 'basICColor GmbH',
|
---|
82 | 'BRCO' => 'Barco NV',
|
---|
83 | 'BRKP' => 'Breakpoint Pty Limited',
|
---|
84 | 'BROT' => 'Brother Industries, LTD',
|
---|
85 | 'BULL' => 'Bull',
|
---|
86 | 'BUS ' => 'Bus Computer Systems',
|
---|
87 | 'C-IT' => 'C-Itoh',
|
---|
88 | 'CAMR' => 'Intel Corporation',
|
---|
89 | 'CANO' => 'Canon, Inc. (Canon Development Americas, Inc.)',
|
---|
90 | 'CARR' => 'Carroll Touch',
|
---|
91 | 'CASI' => 'Casio Computer Co., Ltd.',
|
---|
92 | 'CBUS' => 'Colorbus PL',
|
---|
93 | 'CEL ' => 'Crossfield',
|
---|
94 | 'CELx' => 'Crossfield',
|
---|
95 | 'ceyd' => 'Integrated Color Solutions, Inc.',
|
---|
96 | 'CGS ' => 'CGS Publishing Technologies International GmbH',
|
---|
97 | 'CHM ' => 'Rochester Robotics',
|
---|
98 | 'CIGL' => 'Colour Imaging Group, London',
|
---|
99 | 'CITI' => 'Citizen',
|
---|
100 | 'CL00' => 'Candela, Ltd.',
|
---|
101 | 'CLIQ' => 'Color IQ',
|
---|
102 | 'clsp' => 'MacDermid ColorSpan, Inc.',
|
---|
103 | 'CMCO' => 'Chromaco, Inc.',
|
---|
104 | 'CMiX' => 'CHROMiX',
|
---|
105 | 'COLO' => 'Colorgraphic Communications Corporation',
|
---|
106 | 'COMP' => 'COMPAQ Computer Corporation',
|
---|
107 | 'COMp' => 'Compeq USA/Focus Technology',
|
---|
108 | 'CONR' => 'Conrac Display Products',
|
---|
109 | 'CORD' => 'Cordata Technologies, Inc.',
|
---|
110 | 'CPQ ' => 'Compaq Computer Corporation',
|
---|
111 | 'CPRO' => 'ColorPro',
|
---|
112 | 'CRN ' => 'Cornerstone',
|
---|
113 | 'CTX ' => 'CTX International, Inc.',
|
---|
114 | 'CVIS' => 'ColorVision',
|
---|
115 | 'CWC ' => 'Fujitsu Laboratories, Ltd.',
|
---|
116 | 'DARI' => 'Darius Technology, Ltd.',
|
---|
117 | 'DATA' => 'Dataproducts',
|
---|
118 | 'DCP ' => 'Dry Creek Photo',
|
---|
119 | 'DCRC' => 'Digital Contents Resource Center, Chung-Ang University',
|
---|
120 | 'DELL' => 'Dell Computer Corporation',
|
---|
121 | 'DIC ' => 'Dainippon Ink and Chemicals',
|
---|
122 | 'DICO' => 'Diconix',
|
---|
123 | 'DIGI' => 'Digital',
|
---|
124 | 'DL&C' => 'Digital Light & Color',
|
---|
125 | 'DPLG' => 'Doppelganger, LLC',
|
---|
126 | 'DS ' => 'Dainippon Screen',
|
---|
127 | 'ds ' => 'Dainippon Screen',
|
---|
128 | 'DSOL' => 'DOOSOL',
|
---|
129 | 'DUPN' => 'DuPont',
|
---|
130 | 'dupn' => 'DuPont',
|
---|
131 | 'Eizo' => 'EIZO NANAO CORPORATION',
|
---|
132 | 'EPSO' => 'Epson',
|
---|
133 | 'ESKO' => 'Esko-Graphics',
|
---|
134 | 'ETRI' => 'Electronics and Telecommunications Research Institute',
|
---|
135 | 'EVER' => 'Everex Systems, Inc.',
|
---|
136 | 'EXAC' => 'ExactCODE GmbH',
|
---|
137 | 'FALC' => 'Falco Data Products, Inc.',
|
---|
138 | 'FF ' => 'Fuji Photo Film Co.,LTD',
|
---|
139 | 'FFEI' => 'FujiFilm Electronic Imaging, Ltd.',
|
---|
140 | 'ffei' => 'FujiFilm Electronic Imaging, Ltd.',
|
---|
141 | 'flux' => 'FluxData Corporation',
|
---|
142 | 'FNRD' => 'fnord software',
|
---|
143 | 'FORA' => 'Fora, Inc.',
|
---|
144 | 'FORE' => 'Forefront Technology Corporation',
|
---|
145 | 'FP ' => 'Fujitsu',
|
---|
146 | 'FPA ' => 'WayTech Development, Inc.',
|
---|
147 | 'FUJI' => 'Fujitsu',
|
---|
148 | 'FX ' => 'Fuji Xerox Co., Ltd.',
|
---|
149 | 'GCC ' => 'GCC Technologies, Inc.',
|
---|
150 | 'GGSL' => 'Global Graphics Software Limited',
|
---|
151 | 'GMB ' => 'Gretagmacbeth',
|
---|
152 | 'GMG ' => 'GMG GmbH & Co. KG',
|
---|
153 | 'GOLD' => 'GoldStar Technology, Inc.',
|
---|
154 | 'GOOG' => 'Google', #PH
|
---|
155 | 'GPRT' => 'Giantprint Pty Ltd',
|
---|
156 | 'GTMB' => 'Gretagmacbeth',
|
---|
157 | 'GVC ' => 'WayTech Development, Inc.',
|
---|
158 | 'GW2K' => 'Sony Corporation',
|
---|
159 | 'HCI ' => 'HCI',
|
---|
160 | 'HDM ' => 'Heidelberger Druckmaschinen AG',
|
---|
161 | 'HERM' => 'Hermes',
|
---|
162 | 'HITA' => 'Hitachi America, Ltd.',
|
---|
163 | 'HiTi' => 'HiTi Digital, Inc.',
|
---|
164 | 'HP ' => 'Hewlett-Packard',
|
---|
165 | 'HTC ' => 'Hitachi, Ltd.',
|
---|
166 | 'IBM ' => 'IBM Corporation',
|
---|
167 | 'IDNT' => 'Scitex Corporation, Ltd.',
|
---|
168 | 'Idnt' => 'Scitex Corporation, Ltd.',
|
---|
169 | 'IEC ' => 'Hewlett-Packard',
|
---|
170 | 'IIYA' => 'Iiyama North America, Inc.',
|
---|
171 | 'IKEG' => 'Ikegami Electronics, Inc.',
|
---|
172 | 'IMAG' => 'Image Systems Corporation',
|
---|
173 | 'IMI ' => 'Ingram Micro, Inc.',
|
---|
174 | 'Inca' => 'Inca Digital Printers Ltd.',
|
---|
175 | 'INTC' => 'Intel Corporation',
|
---|
176 | 'INTL' => 'N/A (INTL)',
|
---|
177 | 'INTR' => 'Intra Electronics USA, Inc.',
|
---|
178 | 'IOCO' => 'Iocomm International Technology Corporation',
|
---|
179 | 'IPS ' => 'InfoPrint Solutions Company',
|
---|
180 | 'IRIS' => 'Scitex Corporation, Ltd.',
|
---|
181 | 'Iris' => 'Scitex Corporation, Ltd.',
|
---|
182 | 'iris' => 'Scitex Corporation, Ltd.',
|
---|
183 | 'ISL ' => 'Ichikawa Soft Laboratory',
|
---|
184 | 'ITNL' => 'N/A (ITNL)',
|
---|
185 | 'IVM ' => 'IVM',
|
---|
186 | 'IWAT' => 'Iwatsu Electric Co., Ltd.',
|
---|
187 | 'JPEG' => 'Joint Photographic Experts Group', #PH
|
---|
188 | 'JSFT' => 'Jetsoft Development',
|
---|
189 | 'JVC ' => 'JVC Information Products Co.',
|
---|
190 | 'KART' => 'Scitex Corporation, Ltd.',
|
---|
191 | 'Kart' => 'Scitex Corporation, Ltd.',
|
---|
192 | 'kart' => 'Scitex Corporation, Ltd.',
|
---|
193 | 'KFC ' => 'KFC Computek Components Corporation',
|
---|
194 | 'KLH ' => 'KLH Computers',
|
---|
195 | 'KMHD' => 'Konica Minolta Holdings, Inc.',
|
---|
196 | 'KNCA' => 'Konica Corporation',
|
---|
197 | 'KODA' => 'Kodak',
|
---|
198 | 'KYOC' => 'Kyocera',
|
---|
199 | 'LCAG' => 'Leica Camera AG',
|
---|
200 | 'LCCD' => 'Leeds Colour',
|
---|
201 | 'lcms' => 'Little CMS', #NealKrawetz
|
---|
202 | 'LDAK' => 'Left Dakota',
|
---|
203 | 'LEAD' => 'Leading Technology, Inc.',
|
---|
204 | 'Leaf' => 'Leaf', #PH
|
---|
205 | 'LEXM' => 'Lexmark International, Inc.',
|
---|
206 | 'LINK' => 'Link Computer, Inc.',
|
---|
207 | 'LINO' => 'Linotronic',
|
---|
208 | 'Lino' => 'Linotronic', #PH (NC)
|
---|
209 | 'lino' => 'Linotronic', #PH (NC)
|
---|
210 | 'LITE' => 'Lite-On, Inc.',
|
---|
211 | 'MAGC' => 'Mag Computronic (USA) Inc.',
|
---|
212 | 'MAGI' => 'MAG Innovision, Inc.',
|
---|
213 | 'MANN' => 'Mannesmann',
|
---|
214 | 'MICN' => 'Micron Technology, Inc.',
|
---|
215 | 'MICR' => 'Microtek',
|
---|
216 | 'MICV' => 'Microvitec, Inc.',
|
---|
217 | 'MINO' => 'Minolta',
|
---|
218 | 'MITS' => 'Mitsubishi Electronics America, Inc.',
|
---|
219 | 'MITs' => 'Mitsuba Corporation',
|
---|
220 | 'Mits' => 'Mitsubishi Electric Corporation Kyoto Works',
|
---|
221 | 'MNLT' => 'Minolta',
|
---|
222 | 'MODG' => 'Modgraph, Inc.',
|
---|
223 | 'MONI' => 'Monitronix, Inc.',
|
---|
224 | 'MONS' => 'Monaco Systems Inc.',
|
---|
225 | 'MORS' => 'Morse Technology, Inc.',
|
---|
226 | 'MOTI' => 'Motive Systems',
|
---|
227 | 'MSFT' => 'Microsoft Corporation',
|
---|
228 | 'MUTO' => 'MUTOH INDUSTRIES LTD.',
|
---|
229 | 'NANA' => 'NANAO USA Corporation',
|
---|
230 | 'NEC ' => 'NEC Corporation',
|
---|
231 | 'NEXP' => 'NexPress Solutions LLC',
|
---|
232 | 'NISS' => 'Nissei Sangyo America, Ltd.',
|
---|
233 | 'NKON' => 'Nikon Corporation',
|
---|
234 | 'ob4d' => 'Erdt Systems GmbH & Co KG',
|
---|
235 | 'obic' => 'Medigraph GmbH',
|
---|
236 | 'OCE ' => 'Oce Technologies B.V.',
|
---|
237 | 'OCEC' => 'OceColor',
|
---|
238 | 'OKI ' => 'Oki',
|
---|
239 | 'OKID' => 'Okidata',
|
---|
240 | 'OKIP' => 'Okidata',
|
---|
241 | 'OLIV' => 'Olivetti',
|
---|
242 | 'OLYM' => 'OLYMPUS OPTICAL CO., LTD',
|
---|
243 | 'ONYX' => 'Onyx Graphics',
|
---|
244 | 'OPTI' => 'Optiquest',
|
---|
245 | 'PACK' => 'Packard Bell',
|
---|
246 | 'PANA' => 'Matsushita Electric Industrial Co., Ltd.',
|
---|
247 | 'PANT' => 'Pantone, Inc.',
|
---|
248 | 'PBN ' => 'Packard Bell',
|
---|
249 | 'PFU ' => 'PFU Limited',
|
---|
250 | 'PHIL' => 'Philips Consumer Electronics Co.',
|
---|
251 | 'PNTX' => 'HOYA Corporation PENTAX Imaging Systems Division',
|
---|
252 | 'POne' => 'Phase One A/S',
|
---|
253 | 'PREM' => 'Premier Computer Innovations',
|
---|
254 | 'PRIN' => 'Princeton Graphic Systems',
|
---|
255 | 'PRIP' => 'Princeton Publishing Labs',
|
---|
256 | 'QLUX' => 'Hong Kong',
|
---|
257 | 'QMS ' => 'QMS, Inc.',
|
---|
258 | 'QPCD' => 'QPcard AB',
|
---|
259 | 'QUAD' => 'QuadLaser',
|
---|
260 | 'quby' => 'Qubyx Sarl',
|
---|
261 | 'QUME' => 'Qume Corporation',
|
---|
262 | 'RADI' => 'Radius, Inc.',
|
---|
263 | 'RDDx' => 'Integrated Color Solutions, Inc.',
|
---|
264 | 'RDG ' => 'Roland DG Corporation',
|
---|
265 | 'REDM' => 'REDMS Group, Inc.',
|
---|
266 | 'RELI' => 'Relisys',
|
---|
267 | 'RGMS' => 'Rolf Gierling Multitools',
|
---|
268 | 'RICO' => 'Ricoh Corporation',
|
---|
269 | 'RNLD' => 'Edmund Ronald',
|
---|
270 | 'ROYA' => 'Royal',
|
---|
271 | 'RPC ' => 'Ricoh Printing Systems,Ltd.',
|
---|
272 | 'RTL ' => 'Royal Information Electronics Co., Ltd.',
|
---|
273 | 'SAMP' => 'Sampo Corporation of America',
|
---|
274 | 'SAMS' => 'Samsung, Inc.',
|
---|
275 | 'SANT' => 'Jaime Santana Pomares',
|
---|
276 | 'SCIT' => 'Scitex Corporation, Ltd.',
|
---|
277 | 'Scit' => 'Scitex Corporation, Ltd.',
|
---|
278 | 'scit' => 'Scitex Corporation, Ltd.',
|
---|
279 | 'SCRN' => 'Dainippon Screen',
|
---|
280 | 'scrn' => 'Dainippon Screen',
|
---|
281 | 'SDP ' => 'Scitex Corporation, Ltd.',
|
---|
282 | 'Sdp ' => 'Scitex Corporation, Ltd.',
|
---|
283 | 'sdp ' => 'Scitex Corporation, Ltd.',
|
---|
284 | 'SEC ' => 'SAMSUNG ELECTRONICS CO.,LTD',
|
---|
285 | 'SEIK' => 'Seiko Instruments U.S.A., Inc.',
|
---|
286 | 'SEIk' => 'Seikosha',
|
---|
287 | 'SGUY' => 'ScanGuy.com',
|
---|
288 | 'SHAR' => 'Sharp Laboratories',
|
---|
289 | 'SICC' => 'International Color Consortium',
|
---|
290 | 'siwi' => 'SIWI GRAFIKA CORPORATION',
|
---|
291 | 'SONY' => 'SONY Corporation',
|
---|
292 | 'Sony' => 'Sony Corporation',
|
---|
293 | 'SPCL' => 'SpectraCal',
|
---|
294 | 'STAR' => 'Star',
|
---|
295 | 'STC ' => 'Sampo Technology Corporation',
|
---|
296 | 'TALO' => 'Talon Technology Corporation',
|
---|
297 | 'TAND' => 'Tandy',
|
---|
298 | 'TATU' => 'Tatung Co. of America, Inc.',
|
---|
299 | 'TAXA' => 'TAXAN America, Inc.',
|
---|
300 | 'TDS ' => 'Tokyo Denshi Sekei K.K.',
|
---|
301 | 'TECO' => 'TECO Information Systems, Inc.',
|
---|
302 | 'TEGR' => 'Tegra',
|
---|
303 | 'TEKT' => 'Tektronix, Inc.',
|
---|
304 | 'TI ' => 'Texas Instruments',
|
---|
305 | 'TMKR' => 'TypeMaker Ltd.',
|
---|
306 | 'TOSB' => 'TOSHIBA corp.',
|
---|
307 | 'TOSH' => 'Toshiba, Inc.',
|
---|
308 | 'TOTK' => 'TOTOKU ELECTRIC Co., LTD',
|
---|
309 | 'TRIU' => 'Triumph',
|
---|
310 | 'TSBT' => 'TOSHIBA TEC CORPORATION',
|
---|
311 | 'TTX ' => 'TTX Computer Products, Inc.',
|
---|
312 | 'TVM ' => 'TVM Professional Monitor Corporation',
|
---|
313 | 'TW ' => 'TW Casper Corporation',
|
---|
314 | 'ULSX' => 'Ulead Systems',
|
---|
315 | 'UNIS' => 'Unisys',
|
---|
316 | 'UTZF' => 'Utz Fehlau & Sohn',
|
---|
317 | 'VARI' => 'Varityper',
|
---|
318 | 'VIEW' => 'Viewsonic',
|
---|
319 | 'VISL' => 'Visual communication',
|
---|
320 | 'VIVO' => 'Vivo Mobile Communication Co., Ltd',
|
---|
321 | 'WANG' => 'Wang',
|
---|
322 | 'WLBR' => 'Wilbur Imaging',
|
---|
323 | 'WTG2' => 'Ware To Go',
|
---|
324 | 'WYSE' => 'WYSE Technology',
|
---|
325 | 'XERX' => 'Xerox Corporation',
|
---|
326 | 'XRIT' => 'X-Rite',
|
---|
327 | 'yxym' => 'YxyMaster GmbH',
|
---|
328 | 'Z123' => "Lavanya's test Company",
|
---|
329 | 'Zebr' => 'Zebra Technologies Inc',
|
---|
330 | 'ZRAN' => 'Zoran Corporation',
|
---|
331 | # also seen: " ",ACMS,KCMS,UCCM,etc2,SCTX
|
---|
332 | );
|
---|
333 |
|
---|
334 | # ICC_Profile tag table
|
---|
335 | %Image::ExifTool::ICC_Profile::Main = (
|
---|
336 | GROUPS => { 2 => 'Image' },
|
---|
337 | PROCESS_PROC => \&ProcessICC_Profile,
|
---|
338 | WRITE_PROC => \&WriteICC_Profile,
|
---|
339 | NOTES => q{
|
---|
340 | ICC profile information is used in many different file types including JPEG,
|
---|
341 | TIFF, PDF, PostScript, Photoshop, PNG, MIFF, PICT, QuickTime, XCF and some
|
---|
342 | RAW formats. While the tags listed below are not individually writable, the
|
---|
343 | entire profile itself can be accessed via the extra 'ICC_Profile' tag, but
|
---|
344 | this tag is neither extracted nor written unless specified explicitly. See
|
---|
345 | L<http://www.color.org/icc_specs2.xalter> for the official ICC
|
---|
346 | specification.
|
---|
347 | },
|
---|
348 | A2B0 => 'AToB0',
|
---|
349 | A2B1 => 'AToB1',
|
---|
350 | A2B2 => 'AToB2',
|
---|
351 | bXYZ => 'BlueMatrixColumn', # (called BlueColorant in ref 2)
|
---|
352 | bTRC => {
|
---|
353 | Name => 'BlueTRC',
|
---|
354 | Description => 'Blue Tone Reproduction Curve',
|
---|
355 | },
|
---|
356 | B2A0 => 'BToA0',
|
---|
357 | B2A1 => 'BToA1',
|
---|
358 | B2A2 => 'BToA2',
|
---|
359 | calt => {
|
---|
360 | Name => 'CalibrationDateTime',
|
---|
361 | Groups => { 2 => 'Time' },
|
---|
362 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
363 | },
|
---|
364 | targ => {
|
---|
365 | Name => 'CharTarget',
|
---|
366 | ValueConv => '$val=~s/\0.*//; length $val > 128 ? \$val : $val',
|
---|
367 | },
|
---|
368 | chad => 'ChromaticAdaptation',
|
---|
369 | chrm => {
|
---|
370 | Name => 'Chromaticity',
|
---|
371 | Groups => { 1 => 'ICC_Profile#' }, #(just for the group list)
|
---|
372 | SubDirectory => {
|
---|
373 | TagTable => 'Image::ExifTool::ICC_Profile::Chromaticity',
|
---|
374 | Validate => '$type eq "chrm"',
|
---|
375 | },
|
---|
376 | },
|
---|
377 | clro => 'ColorantOrder',
|
---|
378 | clrt => {
|
---|
379 | Name => 'ColorantTable',
|
---|
380 | SubDirectory => {
|
---|
381 | TagTable => 'Image::ExifTool::ICC_Profile::ColorantTable',
|
---|
382 | Validate => '$type eq "clrt"',
|
---|
383 | },
|
---|
384 | },
|
---|
385 | clot => { # new in version 4.2
|
---|
386 | Name => 'ColorantTableOut',
|
---|
387 | Binary => 1,
|
---|
388 | },
|
---|
389 | cprt => {
|
---|
390 | Name => 'ProfileCopyright',
|
---|
391 | ValueConv => '$val=~s/\0.*//; $val', # may be null terminated
|
---|
392 | },
|
---|
393 | crdi => 'CRDInfo', #2
|
---|
394 | dmnd => {
|
---|
395 | Name => 'DeviceMfgDesc',
|
---|
396 | Groups => { 2 => 'Camera' },
|
---|
397 | },
|
---|
398 | dmdd => {
|
---|
399 | Name => 'DeviceModelDesc',
|
---|
400 | Groups => { 2 => 'Camera' },
|
---|
401 | },
|
---|
402 | devs => {
|
---|
403 | Name => 'DeviceSettings', #2
|
---|
404 | Groups => { 2 => 'Camera' },
|
---|
405 | },
|
---|
406 | gamt => 'Gamut',
|
---|
407 | kTRC => {
|
---|
408 | Name => 'GrayTRC',
|
---|
409 | Description => 'Gray Tone Reproduction Curve',
|
---|
410 | },
|
---|
411 | gXYZ => 'GreenMatrixColumn', # (called GreenColorant in ref 2)
|
---|
412 | gTRC => {
|
---|
413 | Name => 'GreenTRC',
|
---|
414 | Description => 'Green Tone Reproduction Curve',
|
---|
415 | },
|
---|
416 | lumi => 'Luminance',
|
---|
417 | meas => {
|
---|
418 | Name => 'Measurement',
|
---|
419 | SubDirectory => {
|
---|
420 | TagTable => 'Image::ExifTool::ICC_Profile::Measurement',
|
---|
421 | Validate => '$type eq "meas"',
|
---|
422 | },
|
---|
423 | },
|
---|
424 | bkpt => 'MediaBlackPoint',
|
---|
425 | wtpt => 'MediaWhitePoint',
|
---|
426 | ncol => 'NamedColor', #2
|
---|
427 | ncl2 => 'NamedColor2',
|
---|
428 | resp => 'OutputResponse',
|
---|
429 | pre0 => 'Preview0',
|
---|
430 | pre1 => 'Preview1',
|
---|
431 | pre2 => 'Preview2',
|
---|
432 | desc => 'ProfileDescription',
|
---|
433 | pseq => 'ProfileSequenceDesc',
|
---|
434 | psd0 => 'PostScript2CRD0', #2
|
---|
435 | psd1 => 'PostScript2CRD1', #2
|
---|
436 | psd2 => 'PostScript2CRD2', #2
|
---|
437 | ps2s => 'PostScript2CSA', #2
|
---|
438 | ps2i => 'PS2RenderingIntent', #2
|
---|
439 | rXYZ => 'RedMatrixColumn', # (called RedColorant in ref 2)
|
---|
440 | rTRC => {
|
---|
441 | Name => 'RedTRC',
|
---|
442 | Description => 'Red Tone Reproduction Curve',
|
---|
443 | },
|
---|
444 | scrd => 'ScreeningDesc',
|
---|
445 | scrn => 'Screening',
|
---|
446 | 'bfd '=> {
|
---|
447 | Name => 'UCRBG',
|
---|
448 | Description => 'Under Color Removal and Black Gen.',
|
---|
449 | },
|
---|
450 | tech => {
|
---|
451 | Name => 'Technology',
|
---|
452 | PrintConv => {
|
---|
453 | fscn => 'Film Scanner',
|
---|
454 | dcam => 'Digital Camera',
|
---|
455 | rscn => 'Reflective Scanner',
|
---|
456 | ijet => 'Ink Jet Printer',
|
---|
457 | twax => 'Thermal Wax Printer',
|
---|
458 | epho => 'Electrophotographic Printer',
|
---|
459 | esta => 'Electrostatic Printer',
|
---|
460 | dsub => 'Dye Sublimation Printer',
|
---|
461 | rpho => 'Photographic Paper Printer',
|
---|
462 | fprn => 'Film Writer',
|
---|
463 | vidm => 'Video Monitor',
|
---|
464 | vidc => 'Video Camera',
|
---|
465 | pjtv => 'Projection Television',
|
---|
466 | 'CRT '=> 'Cathode Ray Tube Display',
|
---|
467 | 'PMD '=> 'Passive Matrix Display',
|
---|
468 | 'AMD '=> 'Active Matrix Display',
|
---|
469 | KPCD => 'Photo CD',
|
---|
470 | imgs => 'Photo Image Setter',
|
---|
471 | grav => 'Gravure',
|
---|
472 | offs => 'Offset Lithography',
|
---|
473 | silk => 'Silkscreen',
|
---|
474 | flex => 'Flexography',
|
---|
475 | mpfs => 'Motion Picture Film Scanner', #5
|
---|
476 | mpfr => 'Motion Picture Film Recorder', #5
|
---|
477 | dmpc => 'Digital Motion Picture Camera', #5
|
---|
478 | dcpj => 'Digital Cinema Projector', #5
|
---|
479 | },
|
---|
480 | },
|
---|
481 | vued => 'ViewingCondDesc',
|
---|
482 | view => {
|
---|
483 | Name => 'ViewingConditions',
|
---|
484 | SubDirectory => {
|
---|
485 | TagTable => 'Image::ExifTool::ICC_Profile::ViewingConditions',
|
---|
486 | Validate => '$type eq "view"',
|
---|
487 | },
|
---|
488 | },
|
---|
489 | ciis => 'ColorimetricIntentImageState', #5
|
---|
490 | scoe => 'SceneColorimetryEstimates', #5
|
---|
491 | sape => 'SceneAppearanceEstimates', #5
|
---|
492 | fpce => 'FocalPlaneColorimetryEstimates', #5
|
---|
493 | rhoc => 'ReflectionHardcopyOrigColorimetry', #5
|
---|
494 | rpoc => 'ReflectionPrintOutputColorimetry', #5
|
---|
495 | psid => { #5
|
---|
496 | Name => 'ProfileSequenceIdentifier',
|
---|
497 | Binary => 1,
|
---|
498 | },
|
---|
499 | B2D0 => { Name => 'BToD0', Binary => 1 }, #5
|
---|
500 | B2D1 => { Name => 'BToD1', Binary => 1 }, #5
|
---|
501 | B2D2 => { Name => 'BToD2', Binary => 1 }, #5
|
---|
502 | B2D3 => { Name => 'BToD3', Binary => 1 }, #5
|
---|
503 | D2B0 => { Name => 'DToB0', Binary => 1 }, #5
|
---|
504 | D2B1 => { Name => 'DToB1', Binary => 1 }, #5
|
---|
505 | D2B2 => { Name => 'DToB2', Binary => 1 }, #5
|
---|
506 | D2B3 => { Name => 'DToB3', Binary => 1 }, #5
|
---|
507 | rig0 => { #5
|
---|
508 | Name => 'PerceptualRenderingIntentGamut',
|
---|
509 | PrintConv => {
|
---|
510 | prmg => 'Perceptual Reference Medium Gamut',
|
---|
511 | },
|
---|
512 | },
|
---|
513 | rig2 => { #5
|
---|
514 | Name => 'SaturationRenderingIntentGamut',
|
---|
515 | PrintConv => {
|
---|
516 | prmg => 'Perceptual Reference Medium Gamut',
|
---|
517 | },
|
---|
518 | },
|
---|
519 | meta => { #5 (EVENTUALLY DECODE THIS ONCE WE HAVE A SAMPLE!!)
|
---|
520 | Name => 'Metadata',
|
---|
521 | SubDirectory => {
|
---|
522 | TagTable => 'Image::ExifTool::ICC_Profile::Metadata',
|
---|
523 | Validate => '$type eq "meta"',
|
---|
524 | },
|
---|
525 | },
|
---|
526 |
|
---|
527 | # ColorSync custom tags (ref 3)
|
---|
528 | psvm => 'PS2CRDVMSize',
|
---|
529 | vcgt => 'VideoCardGamma',
|
---|
530 | mmod => 'MakeAndModel',
|
---|
531 | dscm => 'ProfileDescriptionML',
|
---|
532 | ndin => 'NativeDisplayInfo',
|
---|
533 |
|
---|
534 | # Microsoft custom tags (ref http://msdn2.microsoft.com/en-us/library/ms536870.aspx)
|
---|
535 | MS00 => 'WCSProfiles',
|
---|
536 |
|
---|
537 | psd3 => { #6
|
---|
538 | Name => 'PostScript2CRD3',
|
---|
539 | Binary => 1, # (NC)
|
---|
540 | },
|
---|
541 |
|
---|
542 | # the following entry represents the ICC profile header, and doesn't
|
---|
543 | # exist as a tag in the directory. It is only in this table to provide
|
---|
544 | # a link so ExifTool can locate the header tags
|
---|
545 | Header => {
|
---|
546 | Name => 'ProfileHeader',
|
---|
547 | SubDirectory => {
|
---|
548 | TagTable => 'Image::ExifTool::ICC_Profile::Header',
|
---|
549 | },
|
---|
550 | },
|
---|
551 | );
|
---|
552 |
|
---|
553 | # ICC profile header definition
|
---|
554 | %Image::ExifTool::ICC_Profile::Header = (
|
---|
555 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
556 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-header', 2 => 'Image' },
|
---|
557 | 4 => {
|
---|
558 | Name => 'ProfileCMMType',
|
---|
559 | Format => 'string[4]',
|
---|
560 | SeparateTable => 'ManuSig',
|
---|
561 | PrintConv => \%manuSig,
|
---|
562 | },
|
---|
563 | 8 => {
|
---|
564 | Name => 'ProfileVersion',
|
---|
565 | Format => 'int16s',
|
---|
566 | PrintConv => '($val >> 8).".".(($val & 0xf0)>>4).".".($val & 0x0f)',
|
---|
567 | },
|
---|
568 | 12 => {
|
---|
569 | Name => 'ProfileClass',
|
---|
570 | Format => 'string[4]',
|
---|
571 | PrintConv => \%profileClass,
|
---|
572 | },
|
---|
573 | 16 => {
|
---|
574 | Name => 'ColorSpaceData',
|
---|
575 | Format => 'string[4]',
|
---|
576 | },
|
---|
577 | 20 => {
|
---|
578 | Name => 'ProfileConnectionSpace',
|
---|
579 | Format => 'string[4]',
|
---|
580 | },
|
---|
581 | 24 => {
|
---|
582 | Name => 'ProfileDateTime',
|
---|
583 | Groups => { 2 => 'Time' },
|
---|
584 | Format => 'int16u[6]',
|
---|
585 | ValueConv => 'sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",split(" ",$val));',
|
---|
586 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
587 | },
|
---|
588 | 36 => {
|
---|
589 | Name => 'ProfileFileSignature',
|
---|
590 | Format => 'string[4]',
|
---|
591 | },
|
---|
592 | 40 => {
|
---|
593 | Name => 'PrimaryPlatform',
|
---|
594 | Format => 'string[4]',
|
---|
595 | PrintConv => {
|
---|
596 | 'APPL' => 'Apple Computer Inc.',
|
---|
597 | 'MSFT' => 'Microsoft Corporation',
|
---|
598 | 'SGI ' => 'Silicon Graphics Inc.',
|
---|
599 | 'SUNW' => 'Sun Microsystems Inc.',
|
---|
600 | 'TGNT' => 'Taligent Inc.',
|
---|
601 | },
|
---|
602 | },
|
---|
603 | 44 => {
|
---|
604 | Name => 'CMMFlags',
|
---|
605 | Format => 'int32u',
|
---|
606 | PrintConv => q[
|
---|
607 | ($val & 0x01 ? "Embedded, " : "Not Embedded, ") .
|
---|
608 | ($val & 0x02 ? "Not Independent" : "Independent")
|
---|
609 | ],
|
---|
610 | },
|
---|
611 | 48 => {
|
---|
612 | Name => 'DeviceManufacturer',
|
---|
613 | Format => 'string[4]',
|
---|
614 | SeparateTable => 'ManuSig',
|
---|
615 | PrintConv => \%manuSig,
|
---|
616 | },
|
---|
617 | 52 => {
|
---|
618 | Name => 'DeviceModel',
|
---|
619 | Format => 'string[4]',
|
---|
620 | # ROMM = Reference Output Medium Metric
|
---|
621 | },
|
---|
622 | 56 => {
|
---|
623 | Name => 'DeviceAttributes',
|
---|
624 | Format => 'int32u[2]',
|
---|
625 | PrintConv => q[
|
---|
626 | my @v = split ' ', $val;
|
---|
627 | ($v[1] & 0x01 ? "Transparency, " : "Reflective, ") .
|
---|
628 | ($v[1] & 0x02 ? "Matte, " : "Glossy, ") .
|
---|
629 | ($v[1] & 0x04 ? "Negative, " : "Positive, ") .
|
---|
630 | ($v[1] & 0x08 ? "B&W" : "Color");
|
---|
631 | ],
|
---|
632 | },
|
---|
633 | 64 => {
|
---|
634 | Name => 'RenderingIntent',
|
---|
635 | Format => 'int32u',
|
---|
636 | PrintConv => {
|
---|
637 | 0 => 'Perceptual',
|
---|
638 | 1 => 'Media-Relative Colorimetric',
|
---|
639 | 2 => 'Saturation',
|
---|
640 | 3 => 'ICC-Absolute Colorimetric',
|
---|
641 | },
|
---|
642 | },
|
---|
643 | 68 => {
|
---|
644 | Name => 'ConnectionSpaceIlluminant',
|
---|
645 | Format => 'fixed32s[3]', # xyz
|
---|
646 | },
|
---|
647 | 80 => {
|
---|
648 | Name => 'ProfileCreator',
|
---|
649 | Format => 'string[4]',
|
---|
650 | SeparateTable => 'ManuSig',
|
---|
651 | PrintConv => \%manuSig,
|
---|
652 | },
|
---|
653 | 84 => {
|
---|
654 | Name => 'ProfileID',
|
---|
655 | Format => 'int8u[16]',
|
---|
656 | PrintConv => 'Image::ExifTool::ICC_Profile::HexID($val)',
|
---|
657 | },
|
---|
658 | );
|
---|
659 |
|
---|
660 | # viewingConditionsType (view) definition
|
---|
661 | %Image::ExifTool::ICC_Profile::ViewingConditions = (
|
---|
662 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
663 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-view', 2 => 'Image' },
|
---|
664 | 8 => {
|
---|
665 | Name => 'ViewingCondIlluminant',
|
---|
666 | Format => 'fixed32s[3]', # xyz
|
---|
667 | },
|
---|
668 | 20 => {
|
---|
669 | Name => 'ViewingCondSurround',
|
---|
670 | Format => 'fixed32s[3]', # xyz
|
---|
671 | },
|
---|
672 | 32 => {
|
---|
673 | Name => 'ViewingCondIlluminantType',
|
---|
674 | Format => 'int32u',
|
---|
675 | PrintConv => \%illuminantType,
|
---|
676 | },
|
---|
677 | );
|
---|
678 |
|
---|
679 | # measurementType (meas) definition
|
---|
680 | %Image::ExifTool::ICC_Profile::Measurement = (
|
---|
681 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
682 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-meas', 2 => 'Image' },
|
---|
683 | 8 => {
|
---|
684 | Name => 'MeasurementObserver',
|
---|
685 | Format => 'int32u',
|
---|
686 | PrintConv => {
|
---|
687 | 1 => 'CIE 1931',
|
---|
688 | 2 => 'CIE 1964',
|
---|
689 | },
|
---|
690 | },
|
---|
691 | 12 => {
|
---|
692 | Name => 'MeasurementBacking',
|
---|
693 | Format => 'fixed32s[3]', # xyz
|
---|
694 | },
|
---|
695 | 24 => {
|
---|
696 | Name => 'MeasurementGeometry',
|
---|
697 | Format => 'int32u',
|
---|
698 | PrintConv => {
|
---|
699 | 0 => 'Unknown',
|
---|
700 | 1 => '0/45 or 45/0',
|
---|
701 | 2 => '0/d or d/0',
|
---|
702 | },
|
---|
703 | },
|
---|
704 | 28 => {
|
---|
705 | Name => 'MeasurementFlare',
|
---|
706 | Format => 'fixed32u',
|
---|
707 | PrintConv => '$val*100 . "%"', # change into a percent
|
---|
708 | },
|
---|
709 | 32 => {
|
---|
710 | Name => 'MeasurementIlluminant',
|
---|
711 | Format => 'int32u',
|
---|
712 | PrintConv => \%illuminantType,
|
---|
713 | },
|
---|
714 | );
|
---|
715 |
|
---|
716 | # chromaticity (chrm) definition
|
---|
717 | %Image::ExifTool::ICC_Profile::Chromaticity = (
|
---|
718 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
719 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-chrm', 2 => 'Image' },
|
---|
720 | 8 => {
|
---|
721 | Name => 'ChromaticityChannels',
|
---|
722 | Format => 'int16u',
|
---|
723 | },
|
---|
724 | 10 => {
|
---|
725 | Name => 'ChromaticityColorant',
|
---|
726 | Format => 'int16u',
|
---|
727 | PrintConv => {
|
---|
728 | 1 => 'ITU-R BT.709',
|
---|
729 | 2 => 'SMPTE RP145-1994',
|
---|
730 | 3 => 'EBU Tech.3213-E',
|
---|
731 | 4 => 'P22',
|
---|
732 | },
|
---|
733 | },
|
---|
734 | # include definitions for 4 channels -- if there are
|
---|
735 | # fewer then the ProcessBinaryData logic won't print them.
|
---|
736 | # If there are more, oh well.
|
---|
737 | 12 => {
|
---|
738 | Name => 'ChromaticityChannel1',
|
---|
739 | Format => 'fixed32u[2]',
|
---|
740 | },
|
---|
741 | 20 => {
|
---|
742 | Name => 'ChromaticityChannel2',
|
---|
743 | Format => 'fixed32u[2]',
|
---|
744 | },
|
---|
745 | 28 => {
|
---|
746 | Name => 'ChromaticityChannel3',
|
---|
747 | Format => 'fixed32u[2]',
|
---|
748 | },
|
---|
749 | 36 => {
|
---|
750 | Name => 'ChromaticityChannel4',
|
---|
751 | Format => 'fixed32u[2]',
|
---|
752 | },
|
---|
753 | );
|
---|
754 |
|
---|
755 | # colorantTable (clrt) definition
|
---|
756 | %Image::ExifTool::ICC_Profile::ColorantTable = (
|
---|
757 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
758 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-clrt', 2 => 'Image' },
|
---|
759 | 8 => {
|
---|
760 | Name => 'ColorantCount',
|
---|
761 | Format => 'int32u',
|
---|
762 | },
|
---|
763 | # include definitions for 3 colorants -- if there are
|
---|
764 | # fewer then the ProcessBinaryData logic won't print them.
|
---|
765 | # If there are more, oh well.
|
---|
766 | 12 => {
|
---|
767 | Name => 'Colorant1Name',
|
---|
768 | Format => 'string[32]',
|
---|
769 | },
|
---|
770 | 44 => {
|
---|
771 | Name => 'Colorant1Coordinates',
|
---|
772 | Format => 'int16u[3]',
|
---|
773 | },
|
---|
774 | 50 => {
|
---|
775 | Name => 'Colorant2Name',
|
---|
776 | Format => 'string[32]',
|
---|
777 | },
|
---|
778 | 82 => {
|
---|
779 | Name => 'Colorant2Coordinates',
|
---|
780 | Format => 'int16u[3]',
|
---|
781 | },
|
---|
782 | 88 => {
|
---|
783 | Name => 'Colorant3Name',
|
---|
784 | Format => 'string[32]',
|
---|
785 | },
|
---|
786 | 120 => {
|
---|
787 | Name => 'Colorant3Coordinates',
|
---|
788 | Format => 'int16u[3]',
|
---|
789 | },
|
---|
790 | );
|
---|
791 |
|
---|
792 | # metadata (meta) tags
|
---|
793 | %Image::ExifTool::ICC_Profile::Metadata = (
|
---|
794 | PROCESS_PROC => \&ProcessMetadata,
|
---|
795 | GROUPS => { 0 => 'ICC_Profile', 1 => 'ICC-meta', 2 => 'Image' },
|
---|
796 | VARS => { NO_ID => 1 },
|
---|
797 | NOTES => q{
|
---|
798 | Only these few tags have been pre-defined, but ExifTool will extract any
|
---|
799 | Metadata tags that exist.
|
---|
800 | },
|
---|
801 | ManufacturerName => { },
|
---|
802 | MediaColor => { },
|
---|
803 | MediaWeight => { },
|
---|
804 | );
|
---|
805 |
|
---|
806 | #------------------------------------------------------------------------------
|
---|
807 | # Print ICC Profile ID in hex
|
---|
808 | # Inputs: 1) string of numbers
|
---|
809 | # Returns: string of hex digits
|
---|
810 | sub HexID($)
|
---|
811 | {
|
---|
812 | my $val = shift;
|
---|
813 | my @vals = split(' ', $val);
|
---|
814 | # return a simple zero if no MD5 done
|
---|
815 | return 0 unless grep(!/^0/, @vals);
|
---|
816 | $val = '';
|
---|
817 | foreach (@vals) { $val .= sprintf("%.2x",$_); }
|
---|
818 | return $val;
|
---|
819 | }
|
---|
820 |
|
---|
821 | #------------------------------------------------------------------------------
|
---|
822 | # Get formatted value from ICC tag (which has the type embedded)
|
---|
823 | # Inputs: 0) data reference, 1) offset to tag data, 2) tag data size
|
---|
824 | # Returns: Formatted value or undefined if format not supported
|
---|
825 | # Notes: The following types are handled by BinaryTables:
|
---|
826 | # chromaticityType, colorantTableType, measurementType, viewingConditionsType
|
---|
827 | # The following types are currently not handled (most are large tables):
|
---|
828 | # curveType, lut16Type, lut8Type, lutAtoBType, lutBtoAType, namedColor2Type,
|
---|
829 | # parametricCurveType, profileSeqDescType, responseCurveSet16Type
|
---|
830 | # The multiLocalizedUnicodeType must be handled by the calling routine.
|
---|
831 | sub FormatICCTag($$$)
|
---|
832 | {
|
---|
833 | my ($dataPt, $offset, $size) = @_;
|
---|
834 |
|
---|
835 | my $type;
|
---|
836 | if ($size >= 8) {
|
---|
837 | # get data type from start of tag data
|
---|
838 | $type = substr($$dataPt, $offset, 4);
|
---|
839 | } else {
|
---|
840 | $type = 'err';
|
---|
841 | }
|
---|
842 | # colorantOrderType
|
---|
843 | if ($type eq 'clro' and $size >= 12) {
|
---|
844 | my $num = Get32u($dataPt, $offset+8);
|
---|
845 | if ($size >= $num + 12) {
|
---|
846 | my $pos = $offset + 12;
|
---|
847 | return join(' ',unpack("x$pos c$num", $$dataPt));
|
---|
848 | }
|
---|
849 | }
|
---|
850 | # dataType
|
---|
851 | if ($type eq 'data' and $size >= 12) {
|
---|
852 | my $form = Get32u($dataPt, $offset+8);
|
---|
853 | # format 0 is ASCII data
|
---|
854 | $form == 0 and return substr($$dataPt, $offset+12, $size-12);
|
---|
855 | # binary data and other data types treat as binary (ie. don't format)
|
---|
856 | }
|
---|
857 | # dateTimeType
|
---|
858 | if ($type eq 'dtim' and $size >= 20) {
|
---|
859 | return sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2d",
|
---|
860 | Get16u($dataPt, $offset+8), Get16u($dataPt, $offset+10),
|
---|
861 | Get16u($dataPt, $offset+12), Get16u($dataPt, $offset+14),
|
---|
862 | Get16u($dataPt, $offset+16), Get16u($dataPt, $offset+18));
|
---|
863 | }
|
---|
864 | # s15Fixed16ArrayType
|
---|
865 | if ($type eq 'sf32') {
|
---|
866 | return ReadValue($dataPt,$offset+8,'fixed32s',($size-8)/4,$size-8);
|
---|
867 | }
|
---|
868 | # signatureType
|
---|
869 | if ($type eq 'sig ' and $size >= 12) {
|
---|
870 | return substr($$dataPt, $offset+8, 4);
|
---|
871 | }
|
---|
872 | # textType
|
---|
873 | $type eq 'text' and return substr($$dataPt, $offset+8, $size-8);
|
---|
874 | # textDescriptionType (ref 2, replaced by multiLocalizedUnicodeType)
|
---|
875 | if ($type eq 'desc' and $size >= 12) {
|
---|
876 | my $len = Get32u($dataPt, $offset+8);
|
---|
877 | if ($size >= $len + 12) {
|
---|
878 | my $str = substr($$dataPt, $offset+12, $len);
|
---|
879 | $str =~ s/\0.*//s; # truncate at null terminator
|
---|
880 | return $str;
|
---|
881 | }
|
---|
882 | }
|
---|
883 | # u16Fixed16ArrayType
|
---|
884 | if ($type eq 'uf32') {
|
---|
885 | return ReadValue($dataPt,$offset+8,'fixed32u',($size-8)/4,$size-8);
|
---|
886 | }
|
---|
887 | # uInt32ArrayType
|
---|
888 | if ($type eq 'ui32') {
|
---|
889 | return ReadValue($dataPt,$offset+8,'int32u',($size-8)/4,$size-8);
|
---|
890 | }
|
---|
891 | # uInt64ArrayType
|
---|
892 | if ($type eq 'ui64') {
|
---|
893 | return ReadValue($dataPt,$offset+8,'int64u',($size-8)/8,$size-8);
|
---|
894 | }
|
---|
895 | # uInt8ArrayType
|
---|
896 | if ($type eq 'ui08') {
|
---|
897 | return ReadValue($dataPt,$offset+8,'int8u',$size-8,$size-8);
|
---|
898 | }
|
---|
899 | # XYZType
|
---|
900 | if ($type eq 'XYZ ') {
|
---|
901 | my $str = '';
|
---|
902 | my $pos;
|
---|
903 | for ($pos=8; $pos+12<=$size; $pos+=12) {
|
---|
904 | $str and $str .= ', ';
|
---|
905 | $str .= ReadValue($dataPt,$offset+$pos,'fixed32s',3,$size-$pos);
|
---|
906 | }
|
---|
907 | return $str;
|
---|
908 | }
|
---|
909 | return undef; # data type is not supported
|
---|
910 | }
|
---|
911 |
|
---|
912 | #------------------------------------------------------------------------------
|
---|
913 | # Process ICC metadata record (ref 5) (UNTESTED!)
|
---|
914 | # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
---|
915 | # Returns: 1 on success
|
---|
916 | sub ProcessMetadata($$$)
|
---|
917 | {
|
---|
918 | my ($et, $dirInfo, $tagTablePtr) = @_;
|
---|
919 | my $dataPt = $$dirInfo{DataPt};
|
---|
920 | my $dirStart = $$dirInfo{DirStart};
|
---|
921 | my $dirLen = $$dirInfo{DirLen};
|
---|
922 | my $dirEnd = $dirStart + $dirLen;
|
---|
923 |
|
---|
924 | if ($dirLen < 16 or substr($$dataPt, $dirStart, 4) ne 'dict') {
|
---|
925 | $et->Warn('Invalid ICC meta dictionary');
|
---|
926 | return 0;
|
---|
927 | }
|
---|
928 | my $num = Get32u($dataPt, $dirStart + 8);
|
---|
929 | $et->VerboseDir('Metadata', $num);
|
---|
930 | my $size = Get32u($dataPt, $dirStart + 12);
|
---|
931 | $size < 16 and $et->Warn('Invalid ICC meta record size'), return 0;
|
---|
932 | # NOTE: In the example the minimum offset is 20,
|
---|
933 | # but this doesn't jive with the table (both in ref 5)
|
---|
934 | my $minPtr = 16 + $size * $num;
|
---|
935 | my $index;
|
---|
936 | for ($index=0; $index<$num; ++$index) {
|
---|
937 | my $entry = $dirStart + 16 + $size * $index;
|
---|
938 | if ($entry + $size > $dirEnd) {
|
---|
939 | $et->Warn('Truncated ICC meta dictionary');
|
---|
940 | last;
|
---|
941 | }
|
---|
942 | my $namePtr = Get32u($dataPt, $entry);
|
---|
943 | my $nameLen = Get32u($dataPt, $entry + 4);
|
---|
944 | my $valuePtr = Get32u($dataPt, $entry + 8);
|
---|
945 | my $valueLen = Get32u($dataPt, $entry + 16);
|
---|
946 | next unless $namePtr and $valuePtr; # ignore if offsets are zero
|
---|
947 | if ($namePtr < $minPtr or $namePtr + $nameLen > $dirLen or
|
---|
948 | $valuePtr < $minPtr or $valuePtr + $valueLen > $dirLen)
|
---|
949 | {
|
---|
950 | $et->Warn('Corrupted ICC meta dictionary');
|
---|
951 | last;
|
---|
952 | }
|
---|
953 | my $tag = substr($dataPt, $dirStart + $namePtr, $nameLen);
|
---|
954 | my $val = substr($dataPt, $dirStart + $valuePtr, $valueLen);
|
---|
955 | $tag = $et->Decode($tag, 'UTF16', 'MM', 'UTF8');
|
---|
956 | $val = $et->Decode($val, 'UTF16', 'MM');
|
---|
957 | # generate tagInfo if it doesn't exist
|
---|
958 | unless ($$tagTablePtr{$tag}) {
|
---|
959 | my $name = ucfirst $tag;
|
---|
960 | $name =~ s/\s+(.)/\u$1/g;
|
---|
961 | $name =~ tr/-_a-zA-Z0-9//dc;
|
---|
962 | next unless length $name;
|
---|
963 | AddTagToTable($tagTablePtr, $tag, { Name => $name });
|
---|
964 | }
|
---|
965 | $et->HandleTag($tagTablePtr, $tag, $val);
|
---|
966 | }
|
---|
967 | return 1;
|
---|
968 | }
|
---|
969 |
|
---|
970 | #------------------------------------------------------------------------------
|
---|
971 | # Write ICC profile file
|
---|
972 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
973 | # Returns: 1 on success, 0 if this wasn't a valid ICC file,
|
---|
974 | # or -1 if a write error occurred
|
---|
975 | sub WriteICC($$)
|
---|
976 | {
|
---|
977 | my ($et, $dirInfo) = @_;
|
---|
978 | # first make sure this is a valid ICC file (or no file at all)
|
---|
979 | my $raf = $$dirInfo{RAF};
|
---|
980 | my $buff;
|
---|
981 | return 0 if $raf->Read($buff, 24) and ValidateICC(\$buff);
|
---|
982 | # now write the new ICC
|
---|
983 | $buff = WriteICC_Profile($et, $dirInfo);
|
---|
984 | if (defined $buff and length $buff) {
|
---|
985 | Write($$dirInfo{OutFile}, $buff) or return -1;
|
---|
986 | } else {
|
---|
987 | $et->Error('No ICC information to write');
|
---|
988 | }
|
---|
989 | return 1;
|
---|
990 | }
|
---|
991 |
|
---|
992 | #------------------------------------------------------------------------------
|
---|
993 | # Write ICC data as a block
|
---|
994 | # Inputs: 0) ExifTool object reference, 1) source dirInfo reference,
|
---|
995 | # 2) tag table reference
|
---|
996 | # Returns: ICC data block (may be empty if no ICC data)
|
---|
997 | # Notes: Increments ExifTool CHANGED flag if changed
|
---|
998 | sub WriteICC_Profile($$;$)
|
---|
999 | {
|
---|
1000 | my ($et, $dirInfo, $tagTablePtr) = @_;
|
---|
1001 | $et or return 1; # allow dummy access
|
---|
1002 | my $dirName = $$dirInfo{DirName} || 'ICC_Profile';
|
---|
1003 | # (don't write AsShotICCProfile or CurrentICCProfile here)
|
---|
1004 | return undef unless $dirName eq 'ICC_Profile';
|
---|
1005 | my $nvHash = $et->GetNewValueHash($Image::ExifTool::Extra{$dirName});
|
---|
1006 | my $val = $et->GetNewValue($nvHash);
|
---|
1007 | $val = '' unless defined $val;
|
---|
1008 | return undef unless $et->IsOverwriting($nvHash, $val);
|
---|
1009 | ++$$et{CHANGED};
|
---|
1010 | return $val;
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | #------------------------------------------------------------------------------
|
---|
1014 | # Validate ICC data
|
---|
1015 | # Inputs: 0) ICC data reference
|
---|
1016 | # Returns: error string or undef on success
|
---|
1017 | sub ValidateICC($)
|
---|
1018 | {
|
---|
1019 | my $valPtr = shift;
|
---|
1020 | my $err;
|
---|
1021 | length($$valPtr) < 24 and return 'Invalid ICC profile';
|
---|
1022 | $profileClass{substr($$valPtr, 12, 4)} or $err = 'profile class';
|
---|
1023 | my $col = substr($$valPtr, 16, 4); # ColorSpaceData
|
---|
1024 | my $con = substr($$valPtr, 20, 4); # ConnectionSpace
|
---|
1025 | my $match = '(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR)';
|
---|
1026 | $col =~ /$match/ or $err = 'color space';
|
---|
1027 | $con =~ /$match/ or $err = 'connection space';
|
---|
1028 | return $err ? "Invalid ICC profile (bad $err)" : undef;
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | #------------------------------------------------------------------------------
|
---|
1032 | # Process ICC profile file
|
---|
1033 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
1034 | # Returns: 1 if this was an ICC file
|
---|
1035 | sub ProcessICC($$)
|
---|
1036 | {
|
---|
1037 | my ($et, $dirInfo) = @_;
|
---|
1038 | my $raf = $$dirInfo{RAF};
|
---|
1039 | my $buff;
|
---|
1040 | $raf->Read($buff, 24) == 24 or return 0;
|
---|
1041 | # check to see if this is a valid ICC profile file
|
---|
1042 | return 0 if ValidateICC(\$buff);
|
---|
1043 | $et->SetFileType();
|
---|
1044 | # read the profile
|
---|
1045 | my $size = unpack('N', $buff);
|
---|
1046 | if ($size < 128 or $size & 0x80000000) {
|
---|
1047 | $et->Error("Bad ICC Profile length ($size)");
|
---|
1048 | return 1;
|
---|
1049 | }
|
---|
1050 | $raf->Seek(0, 0);
|
---|
1051 | unless ($raf->Read($buff, $size) == $size) {
|
---|
1052 | $et->Error('Truncated ICC profile');
|
---|
1053 | return 1;
|
---|
1054 | }
|
---|
1055 | my %dirInfo = (
|
---|
1056 | DataPt => \$buff,
|
---|
1057 | DataLen => $size,
|
---|
1058 | DirStart => 0,
|
---|
1059 | DirLen => $size,
|
---|
1060 | );
|
---|
1061 | my $tagTablePtr = GetTagTable('Image::ExifTool::ICC_Profile::Main');
|
---|
1062 | return ProcessICC_Profile($et, \%dirInfo, $tagTablePtr);
|
---|
1063 | }
|
---|
1064 |
|
---|
1065 | #------------------------------------------------------------------------------
|
---|
1066 | # Process ICC_Profile APP13 record
|
---|
1067 | # Inputs: 0) ExifTool object reference, 1) Reference to directory information
|
---|
1068 | # 2) Tag table reference (undefined to read ICC file)
|
---|
1069 | # Returns: 1 on success
|
---|
1070 | sub ProcessICC_Profile($$$)
|
---|
1071 | {
|
---|
1072 | my ($et, $dirInfo, $tagTablePtr) = @_;
|
---|
1073 | my $dataPt = $$dirInfo{DataPt};
|
---|
1074 | my $dirStart = $$dirInfo{DirStart} || 0;
|
---|
1075 | my $dirLen = $$dirInfo{DirLen};
|
---|
1076 | my $verbose = $et->Options('Verbose');
|
---|
1077 |
|
---|
1078 | return 0 if $dirLen < 4;
|
---|
1079 |
|
---|
1080 | # extract binary ICC_Profile data block if binary mode or requested
|
---|
1081 | if ((($$et{TAGS_FROM_FILE} and not $$et{EXCL_TAG_LOOKUP}{icc_profile}) or
|
---|
1082 | $$et{REQ_TAG_LOOKUP}{icc_profile}) and
|
---|
1083 | # (don't extract from AsShotICCProfile or CurrentICCProfile)
|
---|
1084 | (not $$dirInfo{Name} or $$dirInfo{Name} eq 'ICC_Profile'))
|
---|
1085 | {
|
---|
1086 | $et->FoundTag('ICC_Profile', substr($$dataPt, $dirStart, $dirLen));
|
---|
1087 | }
|
---|
1088 |
|
---|
1089 | SetByteOrder('MM'); # ICC_Profile is always big-endian
|
---|
1090 |
|
---|
1091 | # check length of table
|
---|
1092 | my $len = Get32u($dataPt, $dirStart);
|
---|
1093 | if ($len != $dirLen or $len < 128) {
|
---|
1094 | $et->Warn("Bad length ICC_Profile (length $len)");
|
---|
1095 | return 0 if $len < 128 or $dirLen < $len;
|
---|
1096 | }
|
---|
1097 | my $pos = $dirStart + 128; # position at start of table
|
---|
1098 | my $numEntries = Get32u($dataPt, $pos);
|
---|
1099 | if ($numEntries < 1 or $numEntries >= 0x100
|
---|
1100 | or $numEntries * 12 + 132 > $dirLen)
|
---|
1101 | {
|
---|
1102 | $et->Warn("Bad ICC_Profile table ($numEntries entries)");
|
---|
1103 | return 0;
|
---|
1104 | }
|
---|
1105 |
|
---|
1106 | if ($verbose) {
|
---|
1107 | $et->VerboseDir('ICC_Profile', $numEntries, $dirLen);
|
---|
1108 | my $fakeInfo = { Name=>'ProfileHeader', SubDirectory => { } };
|
---|
1109 | $et->VerboseInfo(undef, $fakeInfo);
|
---|
1110 | }
|
---|
1111 | # increment ICC dir count
|
---|
1112 | my $dirCount = $$et{DIR_COUNT}{ICC} = ($$et{DIR_COUNT}{ICC} || 0) + 1;
|
---|
1113 | $$et{SET_GROUP1} = '+' . $dirCount if $dirCount > 1;
|
---|
1114 | # process the header block
|
---|
1115 | my %subdirInfo = (
|
---|
1116 | Name => 'ProfileHeader',
|
---|
1117 | DataPt => $dataPt,
|
---|
1118 | DataLen => $$dirInfo{DataLen},
|
---|
1119 | DirStart => $dirStart,
|
---|
1120 | DirLen => 128,
|
---|
1121 | Parent => $$dirInfo{DirName},
|
---|
1122 | DirName => 'Header',
|
---|
1123 | );
|
---|
1124 | my $newTagTable = GetTagTable('Image::ExifTool::ICC_Profile::Header');
|
---|
1125 | $et->ProcessDirectory(\%subdirInfo, $newTagTable);
|
---|
1126 |
|
---|
1127 | $pos += 4; # skip item count
|
---|
1128 | my $index;
|
---|
1129 | for ($index=0; $index<$numEntries; ++$index) {
|
---|
1130 | my $tagID = substr($$dataPt, $pos, 4);
|
---|
1131 | my $offset = Get32u($dataPt, $pos + 4);
|
---|
1132 | my $size = Get32u($dataPt, $pos + 8);
|
---|
1133 | $pos += 12;
|
---|
1134 | my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID);
|
---|
1135 | # unknown tags aren't generated automatically by GetTagInfo()
|
---|
1136 | # if the tagID's aren't numeric, so we must do this manually:
|
---|
1137 | if (not $tagInfo and $$et{OPTIONS}{Unknown}) {
|
---|
1138 | $tagInfo = { Unknown => 1 };
|
---|
1139 | AddTagToTable($tagTablePtr, $tagID, $tagInfo);
|
---|
1140 | }
|
---|
1141 | next unless defined $tagInfo;
|
---|
1142 |
|
---|
1143 | if ($offset + $size > $dirLen) {
|
---|
1144 | $et->Warn("Bad ICC_Profile table (truncated)");
|
---|
1145 | last;
|
---|
1146 | }
|
---|
1147 | my $valuePtr = $dirStart + $offset;
|
---|
1148 |
|
---|
1149 | my $subdir = $$tagInfo{SubDirectory};
|
---|
1150 | # format the value unless this is a subdirectory
|
---|
1151 | my ($value, $fmt);
|
---|
1152 | if ($size > 4) {
|
---|
1153 | $fmt = substr($$dataPt, $valuePtr, 4);
|
---|
1154 | # handle multiLocalizedUnicodeType
|
---|
1155 | if ($fmt eq 'mluc' and not $subdir) {
|
---|
1156 | next if $size < 28;
|
---|
1157 | my $count = Get32u($dataPt, $valuePtr + 8);
|
---|
1158 | my $recLen = Get32u($dataPt, $valuePtr + 12);
|
---|
1159 | next if $recLen < 12;
|
---|
1160 | my $i;
|
---|
1161 | for ($i=0; $i<$count; ++$i) {
|
---|
1162 | my $recPos = $valuePtr + 16 + $i * $recLen;
|
---|
1163 | last if $recPos + $recLen > $valuePtr + $size;
|
---|
1164 | my $lang = substr($$dataPt, $recPos, 4);
|
---|
1165 | my $langInfo;
|
---|
1166 | # validate language code and change to standard case (just in case)
|
---|
1167 | if ($lang =~ s/^([a-z]{2})([A-Z]{2})$/\L$1-\U$2/i and $lang ne 'en-US') {
|
---|
1168 | $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $lang);
|
---|
1169 | }
|
---|
1170 | my $strLen = Get32u($dataPt, $recPos + 4);
|
---|
1171 | my $strPos = Get32u($dataPt, $recPos + 8);
|
---|
1172 | last if $strPos + $strLen > $size;
|
---|
1173 | my $str = substr($$dataPt, $valuePtr + $strPos, $strLen);
|
---|
1174 | $str = $et->Decode($str, 'UTF16');
|
---|
1175 | $et->HandleTag($tagTablePtr, $tagID, $str,
|
---|
1176 | TagInfo => $langInfo || $tagInfo,
|
---|
1177 | Table => $tagTablePtr,
|
---|
1178 | Index => $index,
|
---|
1179 | Value => $str,
|
---|
1180 | DataPt => $dataPt,
|
---|
1181 | Size => $strLen,
|
---|
1182 | Start => $valuePtr + $strPos,
|
---|
1183 | Format => "type '${fmt}'",
|
---|
1184 | );
|
---|
1185 | }
|
---|
1186 | $et->Warn("Corrupted $$tagInfo{Name} data") if $i < $count;
|
---|
1187 | next;
|
---|
1188 | }
|
---|
1189 | } else {
|
---|
1190 | $fmt = 'err ';
|
---|
1191 | }
|
---|
1192 | $value = FormatICCTag($dataPt, $valuePtr, $size) unless $subdir;
|
---|
1193 | $verbose and $et->VerboseInfo($tagID, $tagInfo,
|
---|
1194 | Table => $tagTablePtr,
|
---|
1195 | Index => $index,
|
---|
1196 | Value => $value,
|
---|
1197 | DataPt => $dataPt,
|
---|
1198 | Size => $size,
|
---|
1199 | Start => $valuePtr,
|
---|
1200 | Format => "type '${fmt}'",
|
---|
1201 | );
|
---|
1202 | if ($subdir) {
|
---|
1203 | my $name = $$tagInfo{Name};
|
---|
1204 | undef $newTagTable;
|
---|
1205 | if ($$subdir{TagTable}) {
|
---|
1206 | $newTagTable = GetTagTable($$subdir{TagTable});
|
---|
1207 | unless ($newTagTable) {
|
---|
1208 | warn "Unknown tag table $$subdir{TagTable}\n";
|
---|
1209 | next;
|
---|
1210 | }
|
---|
1211 | } else {
|
---|
1212 | warn "Must specify TagTable for SubDirectory $name\n";
|
---|
1213 | next;
|
---|
1214 | }
|
---|
1215 | %subdirInfo = (
|
---|
1216 | Name => $name,
|
---|
1217 | DataPt => $dataPt,
|
---|
1218 | DataPos => $$dirInfo{DataPos},
|
---|
1219 | DataLen => $$dirInfo{DataLen},
|
---|
1220 | DirStart => $valuePtr,
|
---|
1221 | DirLen => $size,
|
---|
1222 | DirName => $name,
|
---|
1223 | Parent => $$dirInfo{DirName},
|
---|
1224 | );
|
---|
1225 | my $type = substr($$dataPt, $valuePtr, 4);
|
---|
1226 | #### eval Validate ($type)
|
---|
1227 | if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
|
---|
1228 | $et->Warn("Invalid ICC $name data");
|
---|
1229 | } else {
|
---|
1230 | $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
|
---|
1231 | }
|
---|
1232 | } elsif (defined $value) {
|
---|
1233 | $et->FoundTag($tagInfo, $value);
|
---|
1234 | } else {
|
---|
1235 | $value = substr($$dataPt, $valuePtr, $size);
|
---|
1236 | # treat unsupported formats as binary data
|
---|
1237 | $$tagInfo{ValueConv} = '\$val' unless defined $$tagInfo{ValueConv};
|
---|
1238 | $et->FoundTag($tagInfo, $value);
|
---|
1239 | }
|
---|
1240 | }
|
---|
1241 | delete $$et{SET_GROUP1};
|
---|
1242 | return 1;
|
---|
1243 | }
|
---|
1244 |
|
---|
1245 |
|
---|
1246 | 1; # end
|
---|
1247 |
|
---|
1248 |
|
---|
1249 | __END__
|
---|
1250 |
|
---|
1251 | =head1 NAME
|
---|
1252 |
|
---|
1253 | Image::ExifTool::ICC_Profile - Read ICC Profile meta information
|
---|
1254 |
|
---|
1255 | =head1 SYNOPSIS
|
---|
1256 |
|
---|
1257 | This module is loaded automatically by Image::ExifTool when required.
|
---|
1258 |
|
---|
1259 | =head1 DESCRIPTION
|
---|
1260 |
|
---|
1261 | This module contains the definitions to read information from ICC profiles.
|
---|
1262 | ICC (International Color Consortium) profiles are used to translate color
|
---|
1263 | data created on one device into another device's native color space.
|
---|
1264 |
|
---|
1265 | =head1 AUTHOR
|
---|
1266 |
|
---|
1267 | Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
|
---|
1268 |
|
---|
1269 | This library is free software; you can redistribute it and/or modify it
|
---|
1270 | under the same terms as Perl itself.
|
---|
1271 |
|
---|
1272 | =head1 REFERENCES
|
---|
1273 |
|
---|
1274 | =over 4
|
---|
1275 |
|
---|
1276 | =item L<http://www.color.org/icc_specs2.html>
|
---|
1277 |
|
---|
1278 | =item L<http://developer.apple.com/documentation/GraphicsImaging/Reference/ColorSync_Manager/ColorSync_Manager.pdf>
|
---|
1279 |
|
---|
1280 | =back
|
---|
1281 |
|
---|
1282 | =head1 SEE ALSO
|
---|
1283 |
|
---|
1284 | L<Image::ExifTool::TagNames/ICC_Profile Tags>,
|
---|
1285 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
1286 |
|
---|
1287 | =cut
|
---|