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