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