1 /*
2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  **********************************************************************
28  **********************************************************************
29  **********************************************************************
30  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
31  *** As  an unpublished  work pursuant to Title 17 of the United    ***
32  *** States Code.  All rights reserved.                             ***
33  **********************************************************************
34  **********************************************************************
35  **********************************************************************/
36 
37 package java.awt.color;
38 
39 import sun.java2d.cmm.PCMM;
40 import sun.java2d.cmm.CMSManager;
41 import sun.java2d.cmm.Profile;
42 import sun.java2d.cmm.ProfileDataVerifier;
43 import sun.java2d.cmm.ProfileDeferralMgr;
44 import sun.java2d.cmm.ProfileDeferralInfo;
45 import sun.java2d.cmm.ProfileActivator;
46 import sun.misc.IOUtils;
47 
48 import java.io.BufferedInputStream;
49 import java.io.File;
50 import java.io.FileInputStream;
51 import java.io.FileNotFoundException;
52 import java.io.FileOutputStream;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.io.ObjectInputStream;
56 import java.io.ObjectOutputStream;
57 import java.io.ObjectStreamException;
58 import java.io.OutputStream;
59 import java.io.Serializable;
60 
61 import java.util.StringTokenizer;
62 
63 import java.security.AccessController;
64 import java.security.PrivilegedAction;
65 
66 
67 /**
68  * A representation of color profile data for device independent and
69  * device dependent color spaces based on the International Color
70  * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
71  * (see <A href="http://www.color.org"> http://www.color.org</A>).
72  * <p>
73  * An ICC_ColorSpace object can be constructed from an appropriate
74  * ICC_Profile.
75  * Typically, an ICC_ColorSpace would be associated with an ICC
76  * Profile which is either an input, display, or output profile (see
77  * the ICC specification).  There are also device link, abstract,
78  * color space conversion, and named color profiles.  These are less
79  * useful for tagging a color or image, but are useful for other
80  * purposes (in particular device link profiles can provide improved
81  * performance for converting from one device's color space to
82  * another's).
83  * <p>
84  * ICC Profiles represent transformations from the color space of
85  * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
86  * Profiles of interest for tagging images or colors have a PCS
87  * which is one of the two specific device independent
88  * spaces (one CIEXYZ space and one CIELab space) defined in the
89  * ICC Profile Format Specification.  Most profiles of interest
90  * either have invertible transformations or explicitly specify
91  * transformations going both directions.
92  * @see ICC_ColorSpace
93  */
94 
95 
96 public class ICC_Profile implements Serializable {
97 
98     private static final long serialVersionUID = -3938515861990936766L;
99 
100     private transient Profile cmmProfile;
101 
102     private transient ProfileDeferralInfo deferralInfo;
103     private transient ProfileActivator profileActivator;
104 
105     // Registry of singleton profile objects for specific color spaces
106     // defined in the ColorSpace class (e.g. CS_sRGB), see
107     // getInstance(int cspace) factory method.
108     private static ICC_Profile sRGBprofile;
109     private static ICC_Profile XYZprofile;
110     private static ICC_Profile PYCCprofile;
111     private static ICC_Profile GRAYprofile;
112     private static ICC_Profile LINEAR_RGBprofile;
113 
114 
115     /**
116      * Profile class is input.
117      */
118     public static final int CLASS_INPUT = 0;
119 
120     /**
121      * Profile class is display.
122      */
123     public static final int CLASS_DISPLAY = 1;
124 
125     /**
126      * Profile class is output.
127      */
128     public static final int CLASS_OUTPUT = 2;
129 
130     /**
131      * Profile class is device link.
132      */
133     public static final int CLASS_DEVICELINK = 3;
134 
135     /**
136      * Profile class is color space conversion.
137      */
138     public static final int CLASS_COLORSPACECONVERSION = 4;
139 
140     /**
141      * Profile class is abstract.
142      */
143     public static final int CLASS_ABSTRACT = 5;
144 
145     /**
146      * Profile class is named color.
147      */
148     public static final int CLASS_NAMEDCOLOR = 6;
149 
150 
151     /**
152      * ICC Profile Color Space Type Signature: 'XYZ '.
153      */
154     public static final int icSigXYZData        = 0x58595A20;    /* 'XYZ ' */
155 
156     /**
157      * ICC Profile Color Space Type Signature: 'Lab '.
158      */
159     public static final int icSigLabData        = 0x4C616220;    /* 'Lab ' */
160 
161     /**
162      * ICC Profile Color Space Type Signature: 'Luv '.
163      */
164     public static final int icSigLuvData        = 0x4C757620;    /* 'Luv ' */
165 
166     /**
167      * ICC Profile Color Space Type Signature: 'YCbr'.
168      */
169     public static final int icSigYCbCrData        = 0x59436272;    /* 'YCbr' */
170 
171     /**
172      * ICC Profile Color Space Type Signature: 'Yxy '.
173      */
174     public static final int icSigYxyData        = 0x59787920;    /* 'Yxy ' */
175 
176     /**
177      * ICC Profile Color Space Type Signature: 'RGB '.
178      */
179     public static final int icSigRgbData        = 0x52474220;    /* 'RGB ' */
180 
181     /**
182      * ICC Profile Color Space Type Signature: 'GRAY'.
183      */
184     public static final int icSigGrayData        = 0x47524159;    /* 'GRAY' */
185 
186     /**
187      * ICC Profile Color Space Type Signature: 'HSV'.
188      */
189     public static final int icSigHsvData        = 0x48535620;    /* 'HSV ' */
190 
191     /**
192      * ICC Profile Color Space Type Signature: 'HLS'.
193      */
194     public static final int icSigHlsData        = 0x484C5320;    /* 'HLS ' */
195 
196     /**
197      * ICC Profile Color Space Type Signature: 'CMYK'.
198      */
199     public static final int icSigCmykData        = 0x434D594B;    /* 'CMYK' */
200 
201     /**
202      * ICC Profile Color Space Type Signature: 'CMY '.
203      */
204     public static final int icSigCmyData        = 0x434D5920;    /* 'CMY ' */
205 
206     /**
207      * ICC Profile Color Space Type Signature: '2CLR'.
208      */
209     public static final int icSigSpace2CLR        = 0x32434C52;    /* '2CLR' */
210 
211     /**
212      * ICC Profile Color Space Type Signature: '3CLR'.
213      */
214     public static final int icSigSpace3CLR        = 0x33434C52;    /* '3CLR' */
215 
216     /**
217      * ICC Profile Color Space Type Signature: '4CLR'.
218      */
219     public static final int icSigSpace4CLR        = 0x34434C52;    /* '4CLR' */
220 
221     /**
222      * ICC Profile Color Space Type Signature: '5CLR'.
223      */
224     public static final int icSigSpace5CLR        = 0x35434C52;    /* '5CLR' */
225 
226     /**
227      * ICC Profile Color Space Type Signature: '6CLR'.
228      */
229     public static final int icSigSpace6CLR        = 0x36434C52;    /* '6CLR' */
230 
231     /**
232      * ICC Profile Color Space Type Signature: '7CLR'.
233      */
234     public static final int icSigSpace7CLR        = 0x37434C52;    /* '7CLR' */
235 
236     /**
237      * ICC Profile Color Space Type Signature: '8CLR'.
238      */
239     public static final int icSigSpace8CLR        = 0x38434C52;    /* '8CLR' */
240 
241     /**
242      * ICC Profile Color Space Type Signature: '9CLR'.
243      */
244     public static final int icSigSpace9CLR        = 0x39434C52;    /* '9CLR' */
245 
246     /**
247      * ICC Profile Color Space Type Signature: 'ACLR'.
248      */
249     public static final int icSigSpaceACLR        = 0x41434C52;    /* 'ACLR' */
250 
251     /**
252      * ICC Profile Color Space Type Signature: 'BCLR'.
253      */
254     public static final int icSigSpaceBCLR        = 0x42434C52;    /* 'BCLR' */
255 
256     /**
257      * ICC Profile Color Space Type Signature: 'CCLR'.
258      */
259     public static final int icSigSpaceCCLR        = 0x43434C52;    /* 'CCLR' */
260 
261     /**
262      * ICC Profile Color Space Type Signature: 'DCLR'.
263      */
264     public static final int icSigSpaceDCLR        = 0x44434C52;    /* 'DCLR' */
265 
266     /**
267      * ICC Profile Color Space Type Signature: 'ECLR'.
268      */
269     public static final int icSigSpaceECLR        = 0x45434C52;    /* 'ECLR' */
270 
271     /**
272      * ICC Profile Color Space Type Signature: 'FCLR'.
273      */
274     public static final int icSigSpaceFCLR        = 0x46434C52;    /* 'FCLR' */
275 
276 
277     /**
278      * ICC Profile Class Signature: 'scnr'.
279      */
280     public static final int icSigInputClass       = 0x73636E72;    /* 'scnr' */
281 
282     /**
283      * ICC Profile Class Signature: 'mntr'.
284      */
285     public static final int icSigDisplayClass     = 0x6D6E7472;    /* 'mntr' */
286 
287     /**
288      * ICC Profile Class Signature: 'prtr'.
289      */
290     public static final int icSigOutputClass      = 0x70727472;    /* 'prtr' */
291 
292     /**
293      * ICC Profile Class Signature: 'link'.
294      */
295     public static final int icSigLinkClass        = 0x6C696E6B;    /* 'link' */
296 
297     /**
298      * ICC Profile Class Signature: 'abst'.
299      */
300     public static final int icSigAbstractClass    = 0x61627374;    /* 'abst' */
301 
302     /**
303      * ICC Profile Class Signature: 'spac'.
304      */
305     public static final int icSigColorSpaceClass  = 0x73706163;    /* 'spac' */
306 
307     /**
308      * ICC Profile Class Signature: 'nmcl'.
309      */
310     public static final int icSigNamedColorClass  = 0x6e6d636c;    /* 'nmcl' */
311 
312 
313     /**
314      * ICC Profile Rendering Intent: Perceptual.
315      */
316     public static final int icPerceptual            = 0;
317 
318     /**
319      * ICC Profile Rendering Intent: RelativeColorimetric.
320      */
321     public static final int icRelativeColorimetric    = 1;
322 
323     /**
324      * ICC Profile Rendering Intent: Media-RelativeColorimetric.
325      * @since 1.5
326      */
327     public static final int icMediaRelativeColorimetric = 1;
328 
329     /**
330      * ICC Profile Rendering Intent: Saturation.
331      */
332     public static final int icSaturation            = 2;
333 
334     /**
335      * ICC Profile Rendering Intent: AbsoluteColorimetric.
336      */
337     public static final int icAbsoluteColorimetric    = 3;
338 
339     /**
340      * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
341      * @since 1.5
342      */
343     public static final int icICCAbsoluteColorimetric = 3;
344 
345 
346     /**
347      * ICC Profile Tag Signature: 'head' - special.
348      */
349     public static final int icSigHead      = 0x68656164; /* 'head' - special */
350 
351     /**
352      * ICC Profile Tag Signature: 'A2B0'.
353      */
354     public static final int icSigAToB0Tag         = 0x41324230;    /* 'A2B0' */
355 
356     /**
357      * ICC Profile Tag Signature: 'A2B1'.
358      */
359     public static final int icSigAToB1Tag         = 0x41324231;    /* 'A2B1' */
360 
361     /**
362      * ICC Profile Tag Signature: 'A2B2'.
363      */
364     public static final int icSigAToB2Tag         = 0x41324232;    /* 'A2B2' */
365 
366     /**
367      * ICC Profile Tag Signature: 'bXYZ'.
368      */
369     public static final int icSigBlueColorantTag  = 0x6258595A;    /* 'bXYZ' */
370 
371     /**
372      * ICC Profile Tag Signature: 'bXYZ'.
373      * @since 1.5
374      */
375     public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
376 
377     /**
378      * ICC Profile Tag Signature: 'bTRC'.
379      */
380     public static final int icSigBlueTRCTag       = 0x62545243;    /* 'bTRC' */
381 
382     /**
383      * ICC Profile Tag Signature: 'B2A0'.
384      */
385     public static final int icSigBToA0Tag         = 0x42324130;    /* 'B2A0' */
386 
387     /**
388      * ICC Profile Tag Signature: 'B2A1'.
389      */
390     public static final int icSigBToA1Tag         = 0x42324131;    /* 'B2A1' */
391 
392     /**
393      * ICC Profile Tag Signature: 'B2A2'.
394      */
395     public static final int icSigBToA2Tag         = 0x42324132;    /* 'B2A2' */
396 
397     /**
398      * ICC Profile Tag Signature: 'calt'.
399      */
400     public static final int icSigCalibrationDateTimeTag = 0x63616C74;
401                                                                    /* 'calt' */
402 
403     /**
404      * ICC Profile Tag Signature: 'targ'.
405      */
406     public static final int icSigCharTargetTag    = 0x74617267;    /* 'targ' */
407 
408     /**
409      * ICC Profile Tag Signature: 'cprt'.
410      */
411     public static final int icSigCopyrightTag     = 0x63707274;    /* 'cprt' */
412 
413     /**
414      * ICC Profile Tag Signature: 'crdi'.
415      */
416     public static final int icSigCrdInfoTag       = 0x63726469;    /* 'crdi' */
417 
418     /**
419      * ICC Profile Tag Signature: 'dmnd'.
420      */
421     public static final int icSigDeviceMfgDescTag = 0x646D6E64;    /* 'dmnd' */
422 
423     /**
424      * ICC Profile Tag Signature: 'dmdd'.
425      */
426     public static final int icSigDeviceModelDescTag = 0x646D6464;  /* 'dmdd' */
427 
428     /**
429      * ICC Profile Tag Signature: 'devs'.
430      */
431     public static final int icSigDeviceSettingsTag =  0x64657673;  /* 'devs' */
432 
433     /**
434      * ICC Profile Tag Signature: 'gamt'.
435      */
436     public static final int icSigGamutTag         = 0x67616D74;    /* 'gamt' */
437 
438     /**
439      * ICC Profile Tag Signature: 'kTRC'.
440      */
441     public static final int icSigGrayTRCTag       = 0x6b545243;    /* 'kTRC' */
442 
443     /**
444      * ICC Profile Tag Signature: 'gXYZ'.
445      */
446     public static final int icSigGreenColorantTag = 0x6758595A;    /* 'gXYZ' */
447 
448     /**
449      * ICC Profile Tag Signature: 'gXYZ'.
450      * @since 1.5
451      */
452     public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
453 
454     /**
455      * ICC Profile Tag Signature: 'gTRC'.
456      */
457     public static final int icSigGreenTRCTag      = 0x67545243;    /* 'gTRC' */
458 
459     /**
460      * ICC Profile Tag Signature: 'lumi'.
461      */
462     public static final int icSigLuminanceTag     = 0x6C756d69;    /* 'lumi' */
463 
464     /**
465      * ICC Profile Tag Signature: 'meas'.
466      */
467     public static final int icSigMeasurementTag   = 0x6D656173;    /* 'meas' */
468 
469     /**
470      * ICC Profile Tag Signature: 'bkpt'.
471      */
472     public static final int icSigMediaBlackPointTag = 0x626B7074;  /* 'bkpt' */
473 
474     /**
475      * ICC Profile Tag Signature: 'wtpt'.
476      */
477     public static final int icSigMediaWhitePointTag = 0x77747074;  /* 'wtpt' */
478 
479     /**
480      * ICC Profile Tag Signature: 'ncl2'.
481      */
482     public static final int icSigNamedColor2Tag   = 0x6E636C32;    /* 'ncl2' */
483 
484     /**
485      * ICC Profile Tag Signature: 'resp'.
486      */
487     public static final int icSigOutputResponseTag = 0x72657370;   /* 'resp' */
488 
489     /**
490      * ICC Profile Tag Signature: 'pre0'.
491      */
492     public static final int icSigPreview0Tag      = 0x70726530;    /* 'pre0' */
493 
494     /**
495      * ICC Profile Tag Signature: 'pre1'.
496      */
497     public static final int icSigPreview1Tag      = 0x70726531;    /* 'pre1' */
498 
499     /**
500      * ICC Profile Tag Signature: 'pre2'.
501      */
502     public static final int icSigPreview2Tag      = 0x70726532;    /* 'pre2' */
503 
504     /**
505      * ICC Profile Tag Signature: 'desc'.
506      */
507     public static final int icSigProfileDescriptionTag = 0x64657363;
508                                                                    /* 'desc' */
509 
510     /**
511      * ICC Profile Tag Signature: 'pseq'.
512      */
513     public static final int icSigProfileSequenceDescTag = 0x70736571;
514                                                                    /* 'pseq' */
515 
516     /**
517      * ICC Profile Tag Signature: 'psd0'.
518      */
519     public static final int icSigPs2CRD0Tag       = 0x70736430;    /* 'psd0' */
520 
521     /**
522      * ICC Profile Tag Signature: 'psd1'.
523      */
524     public static final int icSigPs2CRD1Tag       = 0x70736431;    /* 'psd1' */
525 
526     /**
527      * ICC Profile Tag Signature: 'psd2'.
528      */
529     public static final int icSigPs2CRD2Tag       = 0x70736432;    /* 'psd2' */
530 
531     /**
532      * ICC Profile Tag Signature: 'psd3'.
533      */
534     public static final int icSigPs2CRD3Tag       = 0x70736433;    /* 'psd3' */
535 
536     /**
537      * ICC Profile Tag Signature: 'ps2s'.
538      */
539     public static final int icSigPs2CSATag        = 0x70733273;    /* 'ps2s' */
540 
541     /**
542      * ICC Profile Tag Signature: 'ps2i'.
543      */
544     public static final int icSigPs2RenderingIntentTag = 0x70733269;
545                                                                    /* 'ps2i' */
546 
547     /**
548      * ICC Profile Tag Signature: 'rXYZ'.
549      */
550     public static final int icSigRedColorantTag   = 0x7258595A;    /* 'rXYZ' */
551 
552     /**
553      * ICC Profile Tag Signature: 'rXYZ'.
554      * @since 1.5
555      */
556     public static final int icSigRedMatrixColumnTag = 0x7258595A;  /* 'rXYZ' */
557 
558     /**
559      * ICC Profile Tag Signature: 'rTRC'.
560      */
561     public static final int icSigRedTRCTag        = 0x72545243;    /* 'rTRC' */
562 
563     /**
564      * ICC Profile Tag Signature: 'scrd'.
565      */
566     public static final int icSigScreeningDescTag = 0x73637264;    /* 'scrd' */
567 
568     /**
569      * ICC Profile Tag Signature: 'scrn'.
570      */
571     public static final int icSigScreeningTag     = 0x7363726E;    /* 'scrn' */
572 
573     /**
574      * ICC Profile Tag Signature: 'tech'.
575      */
576     public static final int icSigTechnologyTag    = 0x74656368;    /* 'tech' */
577 
578     /**
579      * ICC Profile Tag Signature: 'bfd '.
580      */
581     public static final int icSigUcrBgTag         = 0x62666420;    /* 'bfd ' */
582 
583     /**
584      * ICC Profile Tag Signature: 'vued'.
585      */
586     public static final int icSigViewingCondDescTag = 0x76756564;  /* 'vued' */
587 
588     /**
589      * ICC Profile Tag Signature: 'view'.
590      */
591     public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
592 
593     /**
594      * ICC Profile Tag Signature: 'chrm'.
595      */
596     public static final int icSigChromaticityTag  = 0x6368726d;    /* 'chrm' */
597 
598     /**
599      * ICC Profile Tag Signature: 'chad'.
600      * @since 1.5
601      */
602     public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
603 
604     /**
605      * ICC Profile Tag Signature: 'clro'.
606      * @since 1.5
607      */
608     public static final int icSigColorantOrderTag = 0x636C726F;    /* 'clro' */
609 
610     /**
611      * ICC Profile Tag Signature: 'clrt'.
612      * @since 1.5
613      */
614     public static final int icSigColorantTableTag = 0x636C7274;    /* 'clrt' */
615 
616 
617     /**
618      * ICC Profile Header Location: profile size in bytes.
619      */
620     public static final int icHdrSize         = 0;  /* Profile size in bytes */
621 
622     /**
623      * ICC Profile Header Location: CMM for this profile.
624      */
625     public static final int icHdrCmmId        = 4;  /* CMM for this profile */
626 
627     /**
628      * ICC Profile Header Location: format version number.
629      */
630     public static final int icHdrVersion      = 8;  /* Format version number */
631 
632     /**
633      * ICC Profile Header Location: type of profile.
634      */
635     public static final int icHdrDeviceClass  = 12; /* Type of profile */
636 
637     /**
638      * ICC Profile Header Location: color space of data.
639      */
640     public static final int icHdrColorSpace   = 16; /* Color space of data */
641 
642     /**
643      * ICC Profile Header Location: PCS - XYZ or Lab only.
644      */
645     public static final int icHdrPcs          = 20; /* PCS - XYZ or Lab only */
646 
647     /**
648      * ICC Profile Header Location: date profile was created.
649      */
650     public static final int icHdrDate       = 24; /* Date profile was created */
651 
652     /**
653      * ICC Profile Header Location: icMagicNumber.
654      */
655     public static final int icHdrMagic        = 36; /* icMagicNumber */
656 
657     /**
658      * ICC Profile Header Location: primary platform.
659      */
660     public static final int icHdrPlatform     = 40; /* Primary Platform */
661 
662     /**
663      * ICC Profile Header Location: various bit settings.
664      */
665     public static final int icHdrFlags        = 44; /* Various bit settings */
666 
667     /**
668      * ICC Profile Header Location: device manufacturer.
669      */
670     public static final int icHdrManufacturer = 48; /* Device manufacturer */
671 
672     /**
673      * ICC Profile Header Location: device model number.
674      */
675     public static final int icHdrModel        = 52; /* Device model number */
676 
677     /**
678      * ICC Profile Header Location: device attributes.
679      */
680     public static final int icHdrAttributes   = 56; /* Device attributes */
681 
682     /**
683      * ICC Profile Header Location: rendering intent.
684      */
685     public static final int icHdrRenderingIntent = 64; /* Rendering intent */
686 
687     /**
688      * ICC Profile Header Location: profile illuminant.
689      */
690     public static final int icHdrIlluminant   = 68; /* Profile illuminant */
691 
692     /**
693      * ICC Profile Header Location: profile creator.
694      */
695     public static final int icHdrCreator      = 80; /* Profile creator */
696 
697     /**
698      * ICC Profile Header Location: profile's ID.
699      * @since 1.5
700      */
701     public static final int icHdrProfileID = 84; /* Profile's ID */
702 
703 
704     /**
705      * ICC Profile Constant: tag type signaturE.
706      */
707     public static final int icTagType          = 0;    /* tag type signature */
708 
709     /**
710      * ICC Profile Constant: reserved.
711      */
712     public static final int icTagReserved      = 4;    /* reserved */
713 
714     /**
715      * ICC Profile Constant: curveType count.
716      */
717     public static final int icCurveCount       = 8;    /* curveType count */
718 
719     /**
720      * ICC Profile Constant: curveType data.
721      */
722     public static final int icCurveData        = 12;   /* curveType data */
723 
724     /**
725      * ICC Profile Constant: XYZNumber X.
726      */
727     public static final int icXYZNumberX       = 8;    /* XYZNumber X */
728 
729 
730     /**
731      * Constructs an ICC_Profile object with a given ID.
732      */
ICC_Profile(Profile p)733     ICC_Profile(Profile p) {
734         this.cmmProfile = p;
735     }
736 
737 
738     /**
739      * Constructs an ICC_Profile object whose loading will be deferred.
740      * The ID will be 0 until the profile is loaded.
741      */
ICC_Profile(ProfileDeferralInfo pdi)742     ICC_Profile(ProfileDeferralInfo pdi) {
743         this.deferralInfo = pdi;
744         this.profileActivator = new ProfileActivator() {
745             public void activate() throws ProfileDataException {
746                 activateDeferredProfile();
747             }
748         };
749         ProfileDeferralMgr.registerDeferral(this.profileActivator);
750     }
751 
752 
753     /**
754      * Frees the resources associated with an ICC_Profile object.
755      */
finalize()756     protected void finalize () {
757         if (cmmProfile != null) {
758             CMSManager.getModule().freeProfile(cmmProfile);
759         } else if (profileActivator != null) {
760             ProfileDeferralMgr.unregisterDeferral(profileActivator);
761         }
762     }
763 
764 
765     /**
766      * Constructs an ICC_Profile object corresponding to the data in
767      * a byte array.  Throws an IllegalArgumentException if the data
768      * does not correspond to a valid ICC Profile.
769      * @param data the specified ICC Profile data
770      * @return an <code>ICC_Profile</code> object corresponding to
771      *          the data in the specified <code>data</code> array.
772      */
getInstance(byte[] data)773     public static ICC_Profile getInstance(byte[] data) {
774     ICC_Profile thisProfile;
775 
776         Profile p = null;
777 
778         if (ProfileDeferralMgr.deferring) {
779             ProfileDeferralMgr.activateProfiles();
780         }
781 
782         ProfileDataVerifier.verify(data);
783 
784         try {
785             p = CMSManager.getModule().loadProfile(data);
786         } catch (CMMException c) {
787             throw new IllegalArgumentException("Invalid ICC Profile Data");
788         }
789 
790         try {
791             if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
792                 (getData (p, icSigMediaWhitePointTag) != null) &&
793                 (getData (p, icSigGrayTRCTag) != null)) {
794                 thisProfile = new ICC_ProfileGray (p);
795             }
796             else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
797                 (getData (p, icSigMediaWhitePointTag) != null) &&
798                 (getData (p, icSigRedColorantTag) != null) &&
799                 (getData (p, icSigGreenColorantTag) != null) &&
800                 (getData (p, icSigBlueColorantTag) != null) &&
801                 (getData (p, icSigRedTRCTag) != null) &&
802                 (getData (p, icSigGreenTRCTag) != null) &&
803                 (getData (p, icSigBlueTRCTag) != null)) {
804                 thisProfile = new ICC_ProfileRGB (p);
805             }
806             else {
807                 thisProfile = new ICC_Profile (p);
808             }
809         } catch (CMMException c) {
810             thisProfile = new ICC_Profile (p);
811         }
812         return thisProfile;
813     }
814 
815 
816 
817     /**
818      * Constructs an ICC_Profile corresponding to one of the specific color
819      * spaces defined by the ColorSpace class (for example CS_sRGB).
820      * Throws an IllegalArgumentException if cspace is not one of the
821      * defined color spaces.
822      *
823      * @param cspace the type of color space to create a profile for.
824      * The specified type is one of the color
825      * space constants defined in the  <CODE>ColorSpace</CODE> class.
826      *
827      * @return an <code>ICC_Profile</code> object corresponding to
828      *          the specified <code>ColorSpace</code> type.
829      * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
830      * one of the predefined color space types.
831      */
getInstance(int cspace)832     public static ICC_Profile getInstance (int cspace) {
833         ICC_Profile thisProfile = null;
834         String fileName;
835 
836         switch (cspace) {
837         case ColorSpace.CS_sRGB:
838             synchronized(ICC_Profile.class) {
839                 if (sRGBprofile == null) {
840                     /*
841                      * Deferral is only used for standard profiles.
842                      * Enabling the appropriate access privileges is handled
843                      * at a lower level.
844                      */
845                     ProfileDeferralInfo pInfo =
846                         new ProfileDeferralInfo("sRGB.pf",
847                                                 ColorSpace.TYPE_RGB, 3,
848                                                 CLASS_DISPLAY);
849                     sRGBprofile = getDeferredInstance(pInfo);
850                 }
851                 thisProfile = sRGBprofile;
852             }
853 
854             break;
855 
856         case ColorSpace.CS_CIEXYZ:
857             synchronized(ICC_Profile.class) {
858                 if (XYZprofile == null) {
859                     ProfileDeferralInfo pInfo =
860                         new ProfileDeferralInfo("CIEXYZ.pf",
861                                                 ColorSpace.TYPE_XYZ, 3,
862                                                 CLASS_DISPLAY);
863                     XYZprofile = getDeferredInstance(pInfo);
864                 }
865                 thisProfile = XYZprofile;
866             }
867 
868             break;
869 
870         case ColorSpace.CS_PYCC:
871             synchronized(ICC_Profile.class) {
872                 if (PYCCprofile == null) {
873                     if (standardProfileExists("PYCC.pf"))
874                     {
875                         ProfileDeferralInfo pInfo =
876                             new ProfileDeferralInfo("PYCC.pf",
877                                                     ColorSpace.TYPE_3CLR, 3,
878                                                     CLASS_DISPLAY);
879                         PYCCprofile = getDeferredInstance(pInfo);
880                     } else {
881                         throw new IllegalArgumentException(
882                                 "Can't load standard profile: PYCC.pf");
883                     }
884                 }
885                 thisProfile = PYCCprofile;
886             }
887 
888             break;
889 
890         case ColorSpace.CS_GRAY:
891             synchronized(ICC_Profile.class) {
892                 if (GRAYprofile == null) {
893                     ProfileDeferralInfo pInfo =
894                         new ProfileDeferralInfo("GRAY.pf",
895                                                 ColorSpace.TYPE_GRAY, 1,
896                                                 CLASS_DISPLAY);
897                     GRAYprofile = getDeferredInstance(pInfo);
898                 }
899                 thisProfile = GRAYprofile;
900             }
901 
902             break;
903 
904         case ColorSpace.CS_LINEAR_RGB:
905             synchronized(ICC_Profile.class) {
906                 if (LINEAR_RGBprofile == null) {
907                     ProfileDeferralInfo pInfo =
908                         new ProfileDeferralInfo("LINEAR_RGB.pf",
909                                                 ColorSpace.TYPE_RGB, 3,
910                                                 CLASS_DISPLAY);
911                     LINEAR_RGBprofile = getDeferredInstance(pInfo);
912                 }
913                 thisProfile = LINEAR_RGBprofile;
914             }
915 
916             break;
917 
918         default:
919             throw new IllegalArgumentException("Unknown color space");
920         }
921 
922         return thisProfile;
923     }
924 
925     /* This asserts system privileges, so is used only for the
926      * standard profiles.
927      */
getStandardProfile(final String name)928     private static ICC_Profile getStandardProfile(final String name) {
929 
930         return AccessController.doPrivileged(
931             new PrivilegedAction<ICC_Profile>() {
932                  public ICC_Profile run() {
933                      ICC_Profile p = null;
934                      try {
935                          p = getInstance (name);
936                      } catch (IOException ex) {
937                          throw new IllegalArgumentException(
938                                "Can't load standard profile: " + name);
939                      }
940                      return p;
941                  }
942              });
943     }
944 
945     /**
946      * Constructs an ICC_Profile corresponding to the data in a file.
947      * fileName may be an absolute or a relative file specification.
948      * Relative file names are looked for in several places: first, relative
949      * to any directories specified by the java.iccprofile.path property;
950      * second, relative to any directories specified by the java.class.path
951      * property; finally, in a directory used to store profiles always
952      * available, such as the profile for sRGB.  Built-in profiles use .pf as
953      * the file name extension for profiles, e.g. sRGB.pf.
954      * This method throws an IOException if the specified file cannot be
955      * opened or if an I/O error occurs while reading the file.  It throws
956      * an IllegalArgumentException if the file does not contain valid ICC
957      * Profile data.
958      * @param fileName The file that contains the data for the profile.
959      *
960      * @return an <code>ICC_Profile</code> object corresponding to
961      *          the data in the specified file.
962      * @exception IOException If the specified file cannot be opened or
963      * an I/O error occurs while reading the file.
964      *
965      * @exception IllegalArgumentException If the file does not
966      * contain valid ICC Profile data.
967      *
968      * @exception SecurityException If a security manager is installed
969      * and it does not permit read access to the given file.
970      */
971     public static ICC_Profile getInstance(String fileName) throws IOException {
972         ICC_Profile thisProfile;
973         FileInputStream fis = null;
974 
975 
976         File f = getProfileFile(fileName);
977         if (f != null) {
978             fis = new FileInputStream(f);
979         }
980         if (fis == null) {
981             throw new IOException("Cannot open file " + fileName);
982         }
983 
984         thisProfile = getInstance(fis);
985 
986         fis.close();    /* close the file */
987 
988         return thisProfile;
989     }
990 
991 
992     /**
993      * Constructs an ICC_Profile corresponding to the data in an InputStream.
994      * This method throws an IllegalArgumentException if the stream does not
995      * contain valid ICC Profile data.  It throws an IOException if an I/O
996      * error occurs while reading the stream.
997      * @param s The input stream from which to read the profile data.
998      *
999      * @return an <CODE>ICC_Profile</CODE> object corresponding to the
1000      *     data in the specified <code>InputStream</code>.
1001      *
1002      * @exception IOException If an I/O error occurs while reading the stream.
1003      *
1004      * @exception IllegalArgumentException If the stream does not
1005      * contain valid ICC Profile data.
1006      */
1007     public static ICC_Profile getInstance(InputStream s) throws IOException {
1008     byte profileData[];
1009 
1010         if (s instanceof ProfileDeferralInfo) {
1011             /* hack to detect profiles whose loading can be deferred */
1012             return getDeferredInstance((ProfileDeferralInfo) s);
1013         }
1014 
1015         if ((profileData = getProfileDataFromStream(s)) == null) {
1016             throw new IllegalArgumentException("Invalid ICC Profile Data");
1017         }
1018 
1019         return getInstance(profileData);
1020     }
1021 
1022 
1023     static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1024 
1025         BufferedInputStream bis = new BufferedInputStream(s);
1026         bis.mark(128);
1027 
1028         byte[] header = IOUtils.readNBytes(bis, 128);
1029         if (header[36] != 0x61 || header[37] != 0x63 ||
1030             header[38] != 0x73 || header[39] != 0x70) {
1031             return null;   /* not a valid profile */
1032         }
1033         int profileSize = ((header[0] & 0xff) << 24) |
1034                           ((header[1] & 0xff) << 16) |
1035                           ((header[2] & 0xff) << 8) |
1036                           (header[3] & 0xff);
1037         bis.reset();
1038         try {
1039             return IOUtils.readNBytes(bis, profileSize);
1040         } catch (OutOfMemoryError e) {
1041             throw new IOException("Color profile is too big");
1042         }
1043     }
1044 
1045 
1046     /**
1047      * Constructs an ICC_Profile for which the actual loading of the
1048      * profile data from a file and the initialization of the CMM should
1049      * be deferred as long as possible.
1050      * Deferral is only used for standard profiles.
1051      * If deferring is disabled, then getStandardProfile() ensures
1052      * that all of the appropriate access privileges are granted
1053      * when loading this profile.
1054      * If deferring is enabled, then the deferred activation
1055      * code will take care of access privileges.
1056      * @see activateDeferredProfile()
1057      */
1058     static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1059         if (!ProfileDeferralMgr.deferring) {
1060             return getStandardProfile(pdi.filename);
1061         }
1062         if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1063             return new ICC_ProfileRGB(pdi);
1064         } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1065             return new ICC_ProfileGray(pdi);
1066         } else {
1067             return new ICC_Profile(pdi);
1068         }
1069     }
1070 
1071 
1072     void activateDeferredProfile() throws ProfileDataException {
1073         byte profileData[];
1074         FileInputStream fis;
1075         final String fileName = deferralInfo.filename;
1076 
1077         profileActivator = null;
1078         deferralInfo = null;
1079         PrivilegedAction<FileInputStream> pa = new PrivilegedAction<FileInputStream>() {
1080             public FileInputStream run() {
1081                 File f = getStandardProfileFile(fileName);
1082                 if (f != null) {
1083                     try {
1084                         return new FileInputStream(f);
1085                     } catch (FileNotFoundException e) {}
1086                 }
1087                 return null;
1088             }
1089         };
1090         if ((fis = AccessController.doPrivileged(pa)) == null) {
1091             throw new ProfileDataException("Cannot open file " + fileName);
1092         }
1093         try {
1094             profileData = getProfileDataFromStream(fis);
1095             fis.close();    /* close the file */
1096         }
1097         catch (IOException e) {
1098             ProfileDataException pde = new
1099                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1100             pde.initCause(e);
1101             throw pde;
1102         }
1103         if (profileData == null) {
1104             throw new ProfileDataException("Invalid ICC Profile Data" +
1105                 fileName);
1106         }
1107         try {
1108             cmmProfile = CMSManager.getModule().loadProfile(profileData);
1109         } catch (CMMException c) {
1110             ProfileDataException pde = new
1111                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1112             pde.initCause(c);
1113             throw pde;
1114         }
1115     }
1116 
1117 
1118     /**
1119      * Returns profile major version.
1120      * @return  The major version of the profile.
1121      */
1122     public int getMajorVersion() {
1123     byte[] theHeader;
1124 
1125         theHeader = getData(icSigHead); /* getData will activate deferred
1126                                            profiles if necessary */
1127 
1128         return (int) theHeader[8];
1129     }
1130 
1131     /**
1132      * Returns profile minor version.
1133      * @return The minor version of the profile.
1134      */
1135     public int getMinorVersion() {
1136     byte[] theHeader;
1137 
1138         theHeader = getData(icSigHead); /* getData will activate deferred
1139                                            profiles if necessary */
1140 
1141         return (int) theHeader[9];
1142     }
1143 
1144     /**
1145      * Returns the profile class.
1146      * @return One of the predefined profile class constants.
1147      */
1148     public int getProfileClass() {
1149     byte[] theHeader;
1150     int theClassSig, theClass;
1151 
1152         if (deferralInfo != null) {
1153             return deferralInfo.profileClass; /* Need to have this info for
1154                                                  ICC_ColorSpace without
1155                                                  causing a deferred profile
1156                                                  to be loaded */
1157         }
1158 
1159         theHeader = getData(icSigHead);
1160 
1161         theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1162 
1163         switch (theClassSig) {
1164         case icSigInputClass:
1165             theClass = CLASS_INPUT;
1166             break;
1167 
1168         case icSigDisplayClass:
1169             theClass = CLASS_DISPLAY;
1170             break;
1171 
1172         case icSigOutputClass:
1173             theClass = CLASS_OUTPUT;
1174             break;
1175 
1176         case icSigLinkClass:
1177             theClass = CLASS_DEVICELINK;
1178             break;
1179 
1180         case icSigColorSpaceClass:
1181             theClass = CLASS_COLORSPACECONVERSION;
1182             break;
1183 
1184         case icSigAbstractClass:
1185             theClass = CLASS_ABSTRACT;
1186             break;
1187 
1188         case icSigNamedColorClass:
1189             theClass = CLASS_NAMEDCOLOR;
1190             break;
1191 
1192         default:
1193             throw new IllegalArgumentException("Unknown profile class");
1194         }
1195 
1196         return theClass;
1197     }
1198 
1199     /**
1200      * Returns the color space type.  Returns one of the color space type
1201      * constants defined by the ColorSpace class.  This is the
1202      * "input" color space of the profile.  The type defines the
1203      * number of components of the color space and the interpretation,
1204      * e.g. TYPE_RGB identifies a color space with three components - red,
1205      * green, and blue.  It does not define the particular color
1206      * characteristics of the space, e.g. the chromaticities of the
1207      * primaries.
1208      * @return One of the color space type constants defined in the
1209      * <CODE>ColorSpace</CODE> class.
1210      */
1211     public int getColorSpaceType() {
1212         if (deferralInfo != null) {
1213             return deferralInfo.colorSpaceType; /* Need to have this info for
1214                                                    ICC_ColorSpace without
1215                                                    causing a deferred profile
1216                                                    to be loaded */
1217         }
1218         return    getColorSpaceType(cmmProfile);
1219     }
1220 
1221     static int getColorSpaceType(Profile p) {
1222     byte[] theHeader;
1223     int theColorSpaceSig, theColorSpace;
1224 
1225         theHeader = getData(p, icSigHead);
1226         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1227         theColorSpace = iccCStoJCS (theColorSpaceSig);
1228         return theColorSpace;
1229     }
1230 
1231     /**
1232      * Returns the color space type of the Profile Connection Space (PCS).
1233      * Returns one of the color space type constants defined by the
1234      * ColorSpace class.  This is the "output" color space of the
1235      * profile.  For an input, display, or output profile useful
1236      * for tagging colors or images, this will be either TYPE_XYZ or
1237      * TYPE_Lab and should be interpreted as the corresponding specific
1238      * color space defined in the ICC specification.  For a device
1239      * link profile, this could be any of the color space type constants.
1240      * @return One of the color space type constants defined in the
1241      * <CODE>ColorSpace</CODE> class.
1242      */
1243     public int getPCSType() {
1244         if (ProfileDeferralMgr.deferring) {
1245             ProfileDeferralMgr.activateProfiles();
1246         }
1247         return getPCSType(cmmProfile);
1248     }
1249 
1250 
1251     static int getPCSType(Profile p) {
1252     byte[] theHeader;
1253     int thePCSSig, thePCS;
1254 
1255         theHeader = getData(p, icSigHead);
1256         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1257         thePCS = iccCStoJCS(thePCSSig);
1258         return thePCS;
1259     }
1260 
1261 
1262     /**
1263      * Write this ICC_Profile to a file.
1264      *
1265      * @param fileName The file to write the profile data to.
1266      *
1267      * @exception IOException If the file cannot be opened for writing
1268      * or an I/O error occurs while writing to the file.
1269      */
1270     public void write(String fileName) throws IOException {
1271     FileOutputStream outputFile;
1272     byte profileData[];
1273 
1274         profileData = getData(); /* this will activate deferred
1275                                     profiles if necessary */
1276         outputFile = new FileOutputStream(fileName);
1277         outputFile.write(profileData);
1278         outputFile.close ();
1279     }
1280 
1281 
1282     /**
1283      * Write this ICC_Profile to an OutputStream.
1284      *
1285      * @param s The stream to write the profile data to.
1286      *
1287      * @exception IOException If an I/O error occurs while writing to the
1288      * stream.
1289      */
1290     public void write(OutputStream s) throws IOException {
1291     byte profileData[];
1292 
1293         profileData = getData(); /* this will activate deferred
1294                                     profiles if necessary */
1295         s.write(profileData);
1296     }
1297 
1298 
1299     /**
1300      * Returns a byte array corresponding to the data of this ICC_Profile.
1301      * @return A byte array that contains the profile data.
1302      * @see #setData(int, byte[])
1303      */
1304     public byte[] getData() {
1305     int profileSize;
1306     byte[] profileData;
1307 
1308         if (ProfileDeferralMgr.deferring) {
1309             ProfileDeferralMgr.activateProfiles();
1310         }
1311 
1312         PCMM mdl = CMSManager.getModule();
1313 
1314         /* get the number of bytes needed for this profile */
1315         profileSize = mdl.getProfileSize(cmmProfile);
1316 
1317         profileData = new byte [profileSize];
1318 
1319         /* get the data for the profile */
1320         mdl.getProfileData(cmmProfile, profileData);
1321 
1322         return profileData;
1323     }
1324 
1325 
1326     /**
1327      * Returns a particular tagged data element from the profile as
1328      * a byte array.  Elements are identified by signatures
1329      * as defined in the ICC specification.  The signature
1330      * icSigHead can be used to get the header.  This method is useful
1331      * for advanced applets or applications which need to access
1332      * profile data directly.
1333      *
1334      * @param tagSignature The ICC tag signature for the data element you
1335      * want to get.
1336      *
1337      * @return A byte array that contains the tagged data element. Returns
1338      * <code>null</code> if the specified tag doesn't exist.
1339      * @see #setData(int, byte[])
1340      */
1341     public byte[] getData(int tagSignature) {
1342 
1343         if (ProfileDeferralMgr.deferring) {
1344             ProfileDeferralMgr.activateProfiles();
1345         }
1346 
1347         return getData(cmmProfile, tagSignature);
1348     }
1349 
1350 
1351     static byte[] getData(Profile p, int tagSignature) {
1352     int tagSize;
1353     byte[] tagData;
1354 
1355         try {
1356             PCMM mdl = CMSManager.getModule();
1357 
1358             /* get the number of bytes needed for this tag */
1359             tagSize = mdl.getTagSize(p, tagSignature);
1360 
1361             tagData = new byte[tagSize]; /* get an array for the tag */
1362 
1363             /* get the tag's data */
1364             mdl.getTagData(p, tagSignature, tagData);
1365         } catch(CMMException c) {
1366             tagData = null;
1367         }
1368 
1369         return tagData;
1370     }
1371 
1372     /**
1373      * Sets a particular tagged data element in the profile from
1374      * a byte array. The array should contain data in a format, corresponded
1375      * to the {@code tagSignature} as defined in the ICC specification, section 10.
1376      * This method is useful for advanced applets or applications which need to
1377      * access profile data directly.
1378      *
1379      * @param tagSignature The ICC tag signature for the data element
1380      * you want to set.
1381      * @param tagData the data to set for the specified tag signature
1382      * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1383      *         as defined in the ICC specification.
1384      * @throws IllegalArgumentException if a content of the {@code tagData}
1385      *         array can not be interpreted as valid tag data, corresponding
1386      *         to the {@code tagSignature}.
1387      * @see #getData
1388      */
1389     public void setData(int tagSignature, byte[] tagData) {
1390 
1391         if (ProfileDeferralMgr.deferring) {
1392             ProfileDeferralMgr.activateProfiles();
1393         }
1394 
1395         CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1396     }
1397 
1398     /**
1399      * Sets the rendering intent of the profile.
1400      * This is used to select the proper transform from a profile that
1401      * has multiple transforms.
1402      */
1403     void setRenderingIntent(int renderingIntent) {
1404         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1405                                                  profiles if necessary */
1406         intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1407                                                  /* set the rendering intent */
1408         setData (icSigHead, theHeader);
1409     }
1410 
1411 
1412     /**
1413      * Returns the rendering intent of the profile.
1414      * This is used to select the proper transform from a profile that
1415      * has multiple transforms.  It is typically set in a source profile
1416      * to select a transform from an output profile.
1417      */
1418     int getRenderingIntent() {
1419         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1420                                                  profiles if necessary */
1421 
1422         int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1423                                                  /* set the rendering intent */
1424 
1425         /* According to ICC spec, only the least-significant 16 bits shall be
1426          * used to encode the rendering intent. The most significant 16 bits
1427          * shall be set to zero. Thus, we are ignoring two most significant
1428          * bytes here.
1429          *
1430          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1431          */
1432         return (0xffff & renderingIntent);
1433     }
1434 
1435 
1436     /**
1437      * Returns the number of color components in the "input" color
1438      * space of this profile.  For example if the color space type
1439      * of this profile is TYPE_RGB, then this method will return 3.
1440      *
1441      * @return The number of color components in the profile's input
1442      * color space.
1443      *
1444      * @throws ProfileDataException if color space is in the profile
1445      *         is invalid
1446      */
1447     public int getNumComponents() {
1448     byte[]    theHeader;
1449     int    theColorSpaceSig, theNumComponents;
1450 
1451         if (deferralInfo != null) {
1452             return deferralInfo.numComponents; /* Need to have this info for
1453                                                   ICC_ColorSpace without
1454                                                   causing a deferred profile
1455                                                   to be loaded */
1456         }
1457         theHeader = getData(icSigHead);
1458 
1459         theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1460 
1461         switch (theColorSpaceSig) {
1462         case icSigGrayData:
1463             theNumComponents = 1;
1464             break;
1465 
1466         case icSigSpace2CLR:
1467             theNumComponents = 2;
1468             break;
1469 
1470         case icSigXYZData:
1471         case icSigLabData:
1472         case icSigLuvData:
1473         case icSigYCbCrData:
1474         case icSigYxyData:
1475         case icSigRgbData:
1476         case icSigHsvData:
1477         case icSigHlsData:
1478         case icSigCmyData:
1479         case icSigSpace3CLR:
1480             theNumComponents = 3;
1481             break;
1482 
1483         case icSigCmykData:
1484         case icSigSpace4CLR:
1485             theNumComponents = 4;
1486             break;
1487 
1488         case icSigSpace5CLR:
1489             theNumComponents = 5;
1490             break;
1491 
1492         case icSigSpace6CLR:
1493             theNumComponents = 6;
1494             break;
1495 
1496         case icSigSpace7CLR:
1497             theNumComponents = 7;
1498             break;
1499 
1500         case icSigSpace8CLR:
1501             theNumComponents = 8;
1502             break;
1503 
1504         case icSigSpace9CLR:
1505             theNumComponents = 9;
1506             break;
1507 
1508         case icSigSpaceACLR:
1509             theNumComponents = 10;
1510             break;
1511 
1512         case icSigSpaceBCLR:
1513             theNumComponents = 11;
1514             break;
1515 
1516         case icSigSpaceCCLR:
1517             theNumComponents = 12;
1518             break;
1519 
1520         case icSigSpaceDCLR:
1521             theNumComponents = 13;
1522             break;
1523 
1524         case icSigSpaceECLR:
1525             theNumComponents = 14;
1526             break;
1527 
1528         case icSigSpaceFCLR:
1529             theNumComponents = 15;
1530             break;
1531 
1532         default:
1533             throw new ProfileDataException ("invalid ICC color space");
1534         }
1535 
1536         return theNumComponents;
1537     }
1538 
1539 
1540     /**
1541      * Returns a float array of length 3 containing the X, Y, and Z
1542      * components of the mediaWhitePointTag in the ICC profile.
1543      */
1544     float[] getMediaWhitePoint() {
1545         return getXYZTag(icSigMediaWhitePointTag);
1546                                            /* get the media white point tag */
1547     }
1548 
1549 
1550     /**
1551      * Returns a float array of length 3 containing the X, Y, and Z
1552      * components encoded in an XYZType tag.
1553      */
1554     float[] getXYZTag(int theTagSignature) {
1555     byte[] theData;
1556     float[] theXYZNumber;
1557     int i1, i2, theS15Fixed16;
1558 
1559         theData = getData(theTagSignature); /* get the tag data */
1560                                             /* getData will activate deferred
1561                                                profiles if necessary */
1562 
1563         theXYZNumber = new float [3];        /* array to return */
1564 
1565         /* convert s15Fixed16Number to float */
1566         for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1567             theS15Fixed16 = intFromBigEndian(theData, i2);
1568             theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1569         }
1570         return theXYZNumber;
1571     }
1572 
1573 
1574     /**
1575      * Returns a gamma value representing a tone reproduction
1576      * curve (TRC).  If the profile represents the TRC as a table rather
1577      * than a single gamma value, then an exception is thrown.  In this
1578      * case the actual table can be obtained via getTRC().
1579      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1580      * icSigGreenTRCTag, or icSigBlueTRCTag.
1581      * @return the gamma value as a float.
1582      * @exception ProfileDataException if the profile does not specify
1583      *            the TRC as a single gamma value.
1584      */
1585     float getGamma(int theTagSignature) {
1586     byte[] theTRCData;
1587     float theGamma;
1588     int theU8Fixed8;
1589 
1590         theTRCData = getData(theTagSignature); /* get the TRC */
1591                                                /* getData will activate deferred
1592                                                   profiles if necessary */
1593 
1594         if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1595             throw new ProfileDataException ("TRC is not a gamma");
1596         }
1597 
1598         /* convert u8Fixed8 to float */
1599         theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1600 
1601         theGamma = ((float) theU8Fixed8) / 256.0f;
1602 
1603         return theGamma;
1604     }
1605 
1606 
1607     /**
1608      * Returns the TRC as an array of shorts.  If the profile has
1609      * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1610      * value, this method throws an exception, and the getGamma() method
1611      * should be used to get the gamma value.  Otherwise the short array
1612      * returned here represents a lookup table where the input Gray value
1613      * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
1614      * to array index 0 and value 1.0 maps to array index length-1.
1615      * Interpolation may be used to generate output values for
1616      * input values which do not map exactly to an index in the
1617      * array.  Output values also map linearly to the range [0.0, 1.0].
1618      * Value 0.0 is represented by an array value of 0x0000 and
1619      * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1620      * short values, although they are returned in a short array.
1621      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1622      * icSigGreenTRCTag, or icSigBlueTRCTag.
1623      * @return a short array representing the TRC.
1624      * @exception ProfileDataException if the profile does not specify
1625      *            the TRC as a table.
1626      */
1627     short[] getTRC(int theTagSignature) {
1628     byte[] theTRCData;
1629     short[] theTRC;
1630     int i1, i2, nElements, theU8Fixed8;
1631 
1632         theTRCData = getData(theTagSignature); /* get the TRC */
1633                                                /* getData will activate deferred
1634                                                   profiles if necessary */
1635 
1636         nElements = intFromBigEndian(theTRCData, icCurveCount);
1637 
1638         if (nElements == 1) {
1639             throw new ProfileDataException("TRC is not a table");
1640         }
1641 
1642         /* make the short array */
1643         theTRC = new short [nElements];
1644 
1645         for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1646             theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1647         }
1648 
1649         return theTRC;
1650     }
1651 
1652 
1653     /* convert an ICC color space signature into a Java color space type */
1654     static int iccCStoJCS(int theColorSpaceSig) {
1655     int theColorSpace;
1656 
1657         switch (theColorSpaceSig) {
1658         case icSigXYZData:
1659             theColorSpace = ColorSpace.TYPE_XYZ;
1660             break;
1661 
1662         case icSigLabData:
1663             theColorSpace = ColorSpace.TYPE_Lab;
1664             break;
1665 
1666         case icSigLuvData:
1667             theColorSpace = ColorSpace.TYPE_Luv;
1668             break;
1669 
1670         case icSigYCbCrData:
1671             theColorSpace = ColorSpace.TYPE_YCbCr;
1672             break;
1673 
1674         case icSigYxyData:
1675             theColorSpace = ColorSpace.TYPE_Yxy;
1676             break;
1677 
1678         case icSigRgbData:
1679             theColorSpace = ColorSpace.TYPE_RGB;
1680             break;
1681 
1682         case icSigGrayData:
1683             theColorSpace = ColorSpace.TYPE_GRAY;
1684             break;
1685 
1686         case icSigHsvData:
1687             theColorSpace = ColorSpace.TYPE_HSV;
1688             break;
1689 
1690         case icSigHlsData:
1691             theColorSpace = ColorSpace.TYPE_HLS;
1692             break;
1693 
1694         case icSigCmykData:
1695             theColorSpace = ColorSpace.TYPE_CMYK;
1696             break;
1697 
1698         case icSigCmyData:
1699             theColorSpace = ColorSpace.TYPE_CMY;
1700             break;
1701 
1702         case icSigSpace2CLR:
1703             theColorSpace = ColorSpace.TYPE_2CLR;
1704             break;
1705 
1706         case icSigSpace3CLR:
1707             theColorSpace = ColorSpace.TYPE_3CLR;
1708             break;
1709 
1710         case icSigSpace4CLR:
1711             theColorSpace = ColorSpace.TYPE_4CLR;
1712             break;
1713 
1714         case icSigSpace5CLR:
1715             theColorSpace = ColorSpace.TYPE_5CLR;
1716             break;
1717 
1718         case icSigSpace6CLR:
1719             theColorSpace = ColorSpace.TYPE_6CLR;
1720             break;
1721 
1722         case icSigSpace7CLR:
1723             theColorSpace = ColorSpace.TYPE_7CLR;
1724             break;
1725 
1726         case icSigSpace8CLR:
1727             theColorSpace = ColorSpace.TYPE_8CLR;
1728             break;
1729 
1730         case icSigSpace9CLR:
1731             theColorSpace = ColorSpace.TYPE_9CLR;
1732             break;
1733 
1734         case icSigSpaceACLR:
1735             theColorSpace = ColorSpace.TYPE_ACLR;
1736             break;
1737 
1738         case icSigSpaceBCLR:
1739             theColorSpace = ColorSpace.TYPE_BCLR;
1740             break;
1741 
1742         case icSigSpaceCCLR:
1743             theColorSpace = ColorSpace.TYPE_CCLR;
1744             break;
1745 
1746         case icSigSpaceDCLR:
1747             theColorSpace = ColorSpace.TYPE_DCLR;
1748             break;
1749 
1750         case icSigSpaceECLR:
1751             theColorSpace = ColorSpace.TYPE_ECLR;
1752             break;
1753 
1754         case icSigSpaceFCLR:
1755             theColorSpace = ColorSpace.TYPE_FCLR;
1756             break;
1757 
1758         default:
1759             throw new IllegalArgumentException ("Unknown color space");
1760         }
1761 
1762         return theColorSpace;
1763     }
1764 
1765 
1766     static int intFromBigEndian(byte[] array, int index) {
1767         return (((array[index]   & 0xff) << 24) |
1768                 ((array[index+1] & 0xff) << 16) |
1769                 ((array[index+2] & 0xff) <<  8) |
1770                  (array[index+3] & 0xff));
1771     }
1772 
1773 
1774     static void intToBigEndian(int value, byte[] array, int index) {
1775             array[index]   = (byte) (value >> 24);
1776             array[index+1] = (byte) (value >> 16);
1777             array[index+2] = (byte) (value >>  8);
1778             array[index+3] = (byte) (value);
1779     }
1780 
1781 
1782     static short shortFromBigEndian(byte[] array, int index) {
1783         return (short) (((array[index]   & 0xff) << 8) |
1784                          (array[index+1] & 0xff));
1785     }
1786 
1787 
1788     static void shortToBigEndian(short value, byte[] array, int index) {
1789             array[index]   = (byte) (value >> 8);
1790             array[index+1] = (byte) (value);
1791     }
1792 
1793 
1794     /*
1795      * fileName may be an absolute or a relative file specification.
1796      * Relative file names are looked for in several places: first, relative
1797      * to any directories specified by the java.iccprofile.path property;
1798      * second, relative to any directories specified by the java.class.path
1799      * property; finally, in a directory used to store profiles always
1800      * available, such as a profile for sRGB.  Built-in profiles use .pf as
1801      * the file name extension for profiles, e.g. sRGB.pf.
1802      */
1803     private static File getProfileFile(String fileName) {
1804         String path, dir, fullPath;
1805 
1806         File f = new File(fileName); /* try absolute file name */
1807         if (f.isAbsolute()) {
1808             /* Rest of code has little sense for an absolute pathname,
1809                so return here. */
1810             return f.isFile() ? f : null;
1811         }
1812         if ((!f.isFile()) &&
1813                 ((path = System.getProperty("java.iccprofile.path")) != null)){
1814                                     /* try relative to java.iccprofile.path */
1815                 StringTokenizer st =
1816                     new StringTokenizer(path, File.pathSeparator);
1817                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1818                     dir = st.nextToken();
1819                         fullPath = dir + File.separatorChar + fileName;
1820                     f = new File(fullPath);
1821                     if (!isChildOf(f, dir)) {
1822                         f = null;
1823                     }
1824                 }
1825             }
1826 
1827         if (((f == null) || (!f.isFile())) &&
1828                 ((path = System.getProperty("java.class.path")) != null)) {
1829                                     /* try relative to java.class.path */
1830                 StringTokenizer st =
1831                     new StringTokenizer(path, File.pathSeparator);
1832                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1833                     dir = st.nextToken();
1834                         fullPath = dir + File.separatorChar + fileName;
1835                     f = new File(fullPath);
1836                 }
1837             }
1838 
1839         if ((f == null) || (!f.isFile())) {
1840             /* try the directory of built-in profiles */
1841             f = getStandardProfileFile(fileName);
1842         }
1843         if (f != null && f.isFile()) {
1844             return f;
1845         }
1846         return null;
1847     }
1848 
1849     /**
1850      * Returns a file object corresponding to a built-in profile
1851      * specified by fileName.
1852      * If there is no built-in profile with such name, then the method
1853      * returns null.
1854      */
1855     private static File getStandardProfileFile(String fileName) {
1856         String dir = System.getProperty("java.home") +
1857             File.separatorChar + "lib" + File.separatorChar + "cmm";
1858         String fullPath = dir + File.separatorChar + fileName;
1859         File f = new File(fullPath);
1860         return (f.isFile() && isChildOf(f, dir)) ? f : null;
1861     }
1862 
1863     /**
1864      * Checks whether given file resides inside give directory.
1865      */
1866     private static boolean isChildOf(File f, String dirName) {
1867         try {
1868             File dir = new File(dirName);
1869             String canonicalDirName = dir.getCanonicalPath();
1870             if (!canonicalDirName.endsWith(File.separator)) {
1871                 canonicalDirName += File.separator;
1872             }
1873             String canonicalFileName = f.getCanonicalPath();
1874             return canonicalFileName.startsWith(canonicalDirName);
1875         } catch (IOException e) {
1876             /* we do not expect the IOException here, because invocation
1877              * of this function is always preceeded by isFile() call.
1878              */
1879             return false;
1880         }
1881     }
1882 
1883     /**
1884      * Checks whether built-in profile specified by fileName exists.
1885      */
1886     private static boolean standardProfileExists(final String fileName) {
1887         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1888                 public Boolean run() {
1889                     return getStandardProfileFile(fileName) != null;
1890                 }
1891             });
1892     }
1893 
1894 
1895     /*
1896      * Serialization support.
1897      *
1898      * Directly deserialized profiles are useless since they are not
1899      * registered with CMM.  We don't allow constructor to be called
1900      * directly and instead have clients to call one of getInstance
1901      * factory methods that will register the profile with CMM.  For
1902      * deserialization we implement readResolve method that will
1903      * resolve the bogus deserialized profile object with one obtained
1904      * with getInstance as well.
1905      *
1906      * There're two primary factory methods for construction of ICC
1907      * profiles: getInstance(int cspace) and getInstance(byte[] data).
1908      * This implementation of ICC_Profile uses the former to return a
1909      * cached singleton profile object, other implementations will
1910      * likely use this technique too.  To preserve the singleton
1911      * pattern across serialization we serialize cached singleton
1912      * profiles in such a way that deserializing VM could call
1913      * getInstance(int cspace) method that will resolve deserialized
1914      * object into the corresponding singleton as well.
1915      *
1916      * Since the singletons are private to ICC_Profile the readResolve
1917      * method have to be `protected' instead of `private' so that
1918      * singletons that are instances of subclasses of ICC_Profile
1919      * could be correctly deserialized.
1920      */
1921 
1922 
1923     /**
1924      * Version of the format of additional serialized data in the
1925      * stream.  Version&nbsp;<code>1</code> corresponds to Java&nbsp;2
1926      * Platform,&nbsp;v1.3.
1927      * @since 1.3
1928      * @serial
1929      */
1930     private int iccProfileSerializedDataVersion = 1;
1931 
1932 
1933     /**
1934      * Writes default serializable fields to the stream.  Writes a
1935      * string and an array of bytes to the stream as additional data.
1936      *
1937      * @param s stream used for serialization.
1938      * @throws IOException
1939      *     thrown by <code>ObjectInputStream</code>.
1940      * @serialData
1941      *     The <code>String</code> is the name of one of
1942      *     <code>CS_<var>*</var></code> constants defined in the
1943      *     {@link ColorSpace} class if the profile object is a profile
1944      *     for a predefined color space (for example
1945      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
1946      *     otherwise.
1947      *     <p>
1948      *     The <code>byte[]</code> array is the profile data for the
1949      *     profile.  For predefined color spaces <code>null</code> is
1950      *     written instead of the profile data.  If in the future
1951      *     versions of Java API new predefined color spaces will be
1952      *     added, future versions of this class may choose to write
1953      *     for new predefined color spaces not only the color space
1954      *     name, but the profile data as well so that older versions
1955      *     could still deserialize the object.
1956      */
1957     private void writeObject(ObjectOutputStream s)
1958       throws IOException
1959     {
1960         s.defaultWriteObject();
1961 
1962         String csName = null;
1963         if (this == sRGBprofile) {
1964             csName = "CS_sRGB";
1965         } else if (this == XYZprofile) {
1966             csName = "CS_CIEXYZ";
1967         } else if (this == PYCCprofile) {
1968             csName = "CS_PYCC";
1969         } else if (this == GRAYprofile) {
1970             csName = "CS_GRAY";
1971         } else if (this == LINEAR_RGBprofile) {
1972             csName = "CS_LINEAR_RGB";
1973         }
1974 
1975         // Future versions may choose to write profile data for new
1976         // predefined color spaces as well, if any will be introduced,
1977         // so that old versions that don't recognize the new CS name
1978         // may fall back to constructing profile from the data.
1979         byte[] data = null;
1980         if (csName == null) {
1981             // getData will activate deferred profile if necessary
1982             data = getData();
1983         }
1984 
1985         s.writeObject(csName);
1986         s.writeObject(data);
1987     }
1988 
1989     // Temporary storage used by readObject to store resolved profile
1990     // (obtained with getInstance) for readResolve to return.
1991     private transient ICC_Profile resolvedDeserializedProfile;
1992 
1993     /**
1994      * Reads default serializable fields from the stream.  Reads from
1995      * the stream a string and an array of bytes as additional data.
1996      *
1997      * @param s stream used for deserialization.
1998      * @throws IOException
1999      *     thrown by <code>ObjectInputStream</code>.
2000      * @throws ClassNotFoundException
2001      *     thrown by <code>ObjectInputStream</code>.
2002      * @serialData
2003      *     The <code>String</code> is the name of one of
2004      *     <code>CS_<var>*</var></code> constants defined in the
2005      *     {@link ColorSpace} class if the profile object is a profile
2006      *     for a predefined color space (for example
2007      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
2008      *     otherwise.
2009      *     <p>
2010      *     The <code>byte[]</code> array is the profile data for the
2011      *     profile.  It will usually be <code>null</code> for the
2012      *     predefined profiles.
2013      *     <p>
2014      *     If the string is recognized as a constant name for
2015      *     predefined color space the object will be resolved into
2016      *     profile obtained with
2017      *     <code>getInstance(int&nbsp;cspace)</code> and the profile
2018      *     data are ignored.  Otherwise the object will be resolved
2019      *     into profile obtained with
2020      *     <code>getInstance(byte[]&nbsp;data)</code>.
2021      * @see #readResolve()
2022      * @see #getInstance(int)
2023      * @see #getInstance(byte[])
2024      */
2025     private void readObject(ObjectInputStream s)
2026       throws IOException, ClassNotFoundException
2027     {
2028         s.defaultReadObject();
2029 
2030         String csName = (String)s.readObject();
2031         byte[] data = (byte[])s.readObject();
2032 
2033         int cspace = 0;         // ColorSpace.CS_* constant if known
2034         boolean isKnownPredefinedCS = false;
2035         if (csName != null) {
2036             isKnownPredefinedCS = true;
2037             if (csName.equals("CS_sRGB")) {
2038                 cspace = ColorSpace.CS_sRGB;
2039             } else if (csName.equals("CS_CIEXYZ")) {
2040                 cspace = ColorSpace.CS_CIEXYZ;
2041             } else if (csName.equals("CS_PYCC")) {
2042                 cspace = ColorSpace.CS_PYCC;
2043             } else if (csName.equals("CS_GRAY")) {
2044                 cspace = ColorSpace.CS_GRAY;
2045             } else if (csName.equals("CS_LINEAR_RGB")) {
2046                 cspace = ColorSpace.CS_LINEAR_RGB;
2047             } else {
2048                 isKnownPredefinedCS = false;
2049             }
2050         }
2051 
2052         if (isKnownPredefinedCS) {
2053             resolvedDeserializedProfile = getInstance(cspace);
2054         } else {
2055             resolvedDeserializedProfile = getInstance(data);
2056         }
2057     }
2058 
2059     /**
2060      * Resolves instances being deserialized into instances registered
2061      * with CMM.
2062      * @return ICC_Profile object for profile registered with CMM.
2063      * @throws ObjectStreamException
2064      *     never thrown, but mandated by the serialization spec.
2065      * @since 1.3
2066      */
2067     protected Object readResolve() throws ObjectStreamException {
2068         return resolvedDeserializedProfile;
2069     }
2070 }
2071