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