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