< prev index next >

src/java.desktop/share/classes/java/awt/color/ICC_Profile.java

Print this page




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  **********************************************************************
  28  **********************************************************************
  29  **********************************************************************
  30  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
  31  *** As  an unpublished  work pursuant to Title 17 of the United    ***
  32  *** States Code.  All rights reserved.                             ***
  33  **********************************************************************
  34  **********************************************************************
  35  **********************************************************************/
  36 
  37 package java.awt.color;
  38 
  39 import sun.java2d.cmm.PCMM;
  40 import sun.java2d.cmm.CMSManager;
  41 import sun.java2d.cmm.Profile;
  42 import sun.java2d.cmm.ProfileDataVerifier;
  43 import sun.java2d.cmm.ProfileDeferralMgr;
  44 import sun.java2d.cmm.ProfileDeferralInfo;
  45 import sun.java2d.cmm.ProfileActivator;
  46 
  47 import java.io.File;
  48 import java.io.FileInputStream;
  49 import java.io.FileNotFoundException;
  50 import java.io.FileOutputStream;
  51 import java.io.FilePermission;
  52 import java.io.IOException;
  53 import java.io.InputStream;
  54 import java.io.ObjectInputStream;
  55 import java.io.ObjectOutputStream;
  56 import java.io.ObjectStreamException;
  57 import java.io.OutputStream;
  58 import java.io.Serializable;
  59 
  60 import java.util.StringTokenizer;
  61 
  62 import java.security.AccessController;
  63 import java.security.PrivilegedAction;

  64 







  65 
  66 /**
  67  * A representation of color profile data for device independent and
  68  * device dependent color spaces based on the International Color
  69  * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
  70  * (see <A href="http://www.color.org"> http://www.color.org</A>).
  71  * <p>
  72  * An ICC_ColorSpace object can be constructed from an appropriate
  73  * ICC_Profile.
  74  * Typically, an ICC_ColorSpace would be associated with an ICC
  75  * Profile which is either an input, display, or output profile (see
  76  * the ICC specification).  There are also device link, abstract,
  77  * color space conversion, and named color profiles.  These are less
  78  * useful for tagging a color or image, but are useful for other
  79  * purposes (in particular device link profiles can provide improved
  80  * performance for converting from one device's color space to
  81  * another's).
  82  * <p>
  83  * ICC Profiles represent transformations from the color space of
  84  * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
  85  * Profiles of interest for tagging images or colors have a PCS
  86  * which is one of the two specific device independent
  87  * spaces (one CIEXYZ space and one CIELab space) defined in the
  88  * ICC Profile Format Specification.  Most profiles of interest
  89  * either have invertible transformations or explicitly specify
  90  * transformations going both directions.
  91  * @see ICC_ColorSpace
  92  */
  93 
  94 
  95 public class ICC_Profile implements Serializable {
  96 
  97     private static final long serialVersionUID = -3938515861990936766L;
  98 
  99     private transient Profile cmmProfile;
 100 
 101     private transient ProfileDeferralInfo deferralInfo;
 102     private transient ProfileActivator profileActivator;
 103 
 104     // Registry of singleton profile objects for specific color spaces
 105     // defined in the ColorSpace class (e.g. CS_sRGB), see
 106     // getInstance(int cspace) factory method.
 107     private static ICC_Profile sRGBprofile;
 108     private static ICC_Profile XYZprofile;
 109     private static ICC_Profile PYCCprofile;
 110     private static ICC_Profile GRAYprofile;
 111     private static ICC_Profile LINEAR_RGBprofile;
 112 
 113 
 114     /**
 115      * Profile class is input.
 116      */
 117     public static final int CLASS_INPUT = 0;
 118 
 119     /**
 120      * Profile class is display.
 121      */
 122     public static final int CLASS_DISPLAY = 1;
 123 
 124     /**
 125      * Profile class is output.
 126      */
 127     public static final int CLASS_OUTPUT = 2;
 128 
 129     /**
 130      * Profile class is device link.
 131      */
 132     public static final int CLASS_DEVICELINK = 3;
 133 
 134     /**
 135      * Profile class is color space conversion.
 136      */
 137     public static final int CLASS_COLORSPACECONVERSION = 4;
 138 
 139     /**
 140      * Profile class is abstract.
 141      */
 142     public static final int CLASS_ABSTRACT = 5;
 143 
 144     /**
 145      * Profile class is named color.
 146      */
 147     public static final int CLASS_NAMEDCOLOR = 6;
 148 
 149 
 150     /**
 151      * ICC Profile Color Space Type Signature: 'XYZ '.
 152      */
 153     public static final int icSigXYZData        = 0x58595A20;    /* 'XYZ ' */
 154 
 155     /**
 156      * ICC Profile Color Space Type Signature: 'Lab '.
 157      */
 158     public static final int icSigLabData        = 0x4C616220;    /* 'Lab ' */
 159 
 160     /**
 161      * ICC Profile Color Space Type Signature: 'Luv '.
 162      */
 163     public static final int icSigLuvData        = 0x4C757620;    /* 'Luv ' */
 164 
 165     /**
 166      * ICC Profile Color Space Type Signature: 'YCbr'.
 167      */
 168     public static final int icSigYCbCrData        = 0x59436272;    /* 'YCbr' */
 169 


 304     public static final int icSigColorSpaceClass  = 0x73706163;    /* 'spac' */
 305 
 306     /**
 307      * ICC Profile Class Signature: 'nmcl'.
 308      */
 309     public static final int icSigNamedColorClass  = 0x6e6d636c;    /* 'nmcl' */
 310 
 311 
 312     /**
 313      * ICC Profile Rendering Intent: Perceptual.
 314      */
 315     public static final int icPerceptual            = 0;
 316 
 317     /**
 318      * ICC Profile Rendering Intent: RelativeColorimetric.
 319      */
 320     public static final int icRelativeColorimetric    = 1;
 321 
 322     /**
 323      * ICC Profile Rendering Intent: Media-RelativeColorimetric.

 324      * @since 1.5
 325      */
 326     public static final int icMediaRelativeColorimetric = 1;
 327 
 328     /**
 329      * ICC Profile Rendering Intent: Saturation.
 330      */
 331     public static final int icSaturation            = 2;
 332 
 333     /**
 334      * ICC Profile Rendering Intent: AbsoluteColorimetric.
 335      */
 336     public static final int icAbsoluteColorimetric    = 3;
 337 
 338     /**
 339      * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.

 340      * @since 1.5
 341      */
 342     public static final int icICCAbsoluteColorimetric = 3;
 343 
 344 
 345     /**
 346      * ICC Profile Tag Signature: 'head' - special.
 347      */
 348     public static final int icSigHead      = 0x68656164; /* 'head' - special */
 349 
 350     /**
 351      * ICC Profile Tag Signature: 'A2B0'.
 352      */
 353     public static final int icSigAToB0Tag         = 0x41324230;    /* 'A2B0' */
 354 
 355     /**
 356      * ICC Profile Tag Signature: 'A2B1'.
 357      */
 358     public static final int icSigAToB1Tag         = 0x41324231;    /* 'A2B1' */
 359 
 360     /**
 361      * ICC Profile Tag Signature: 'A2B2'.
 362      */
 363     public static final int icSigAToB2Tag         = 0x41324232;    /* 'A2B2' */
 364 
 365     /**
 366      * ICC Profile Tag Signature: 'bXYZ'.
 367      */
 368     public static final int icSigBlueColorantTag  = 0x6258595A;    /* 'bXYZ' */
 369 
 370     /**
 371      * ICC Profile Tag Signature: 'bXYZ'.

 372      * @since 1.5
 373      */
 374     public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
 375 
 376     /**
 377      * ICC Profile Tag Signature: 'bTRC'.
 378      */
 379     public static final int icSigBlueTRCTag       = 0x62545243;    /* 'bTRC' */
 380 
 381     /**
 382      * ICC Profile Tag Signature: 'B2A0'.
 383      */
 384     public static final int icSigBToA0Tag         = 0x42324130;    /* 'B2A0' */
 385 
 386     /**
 387      * ICC Profile Tag Signature: 'B2A1'.
 388      */
 389     public static final int icSigBToA1Tag         = 0x42324131;    /* 'B2A1' */
 390 
 391     /**


 429      */
 430     public static final int icSigDeviceSettingsTag =  0x64657673;  /* 'devs' */
 431 
 432     /**
 433      * ICC Profile Tag Signature: 'gamt'.
 434      */
 435     public static final int icSigGamutTag         = 0x67616D74;    /* 'gamt' */
 436 
 437     /**
 438      * ICC Profile Tag Signature: 'kTRC'.
 439      */
 440     public static final int icSigGrayTRCTag       = 0x6b545243;    /* 'kTRC' */
 441 
 442     /**
 443      * ICC Profile Tag Signature: 'gXYZ'.
 444      */
 445     public static final int icSigGreenColorantTag = 0x6758595A;    /* 'gXYZ' */
 446 
 447     /**
 448      * ICC Profile Tag Signature: 'gXYZ'.

 449      * @since 1.5
 450      */
 451     public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
 452 
 453     /**
 454      * ICC Profile Tag Signature: 'gTRC'.
 455      */
 456     public static final int icSigGreenTRCTag      = 0x67545243;    /* 'gTRC' */
 457 
 458     /**
 459      * ICC Profile Tag Signature: 'lumi'.
 460      */
 461     public static final int icSigLuminanceTag     = 0x6C756d69;    /* 'lumi' */
 462 
 463     /**
 464      * ICC Profile Tag Signature: 'meas'.
 465      */
 466     public static final int icSigMeasurementTag   = 0x6D656173;    /* 'meas' */
 467 
 468     /**


 533     public static final int icSigPs2CRD3Tag       = 0x70736433;    /* 'psd3' */
 534 
 535     /**
 536      * ICC Profile Tag Signature: 'ps2s'.
 537      */
 538     public static final int icSigPs2CSATag        = 0x70733273;    /* 'ps2s' */
 539 
 540     /**
 541      * ICC Profile Tag Signature: 'ps2i'.
 542      */
 543     public static final int icSigPs2RenderingIntentTag = 0x70733269;
 544                                                                    /* 'ps2i' */
 545 
 546     /**
 547      * ICC Profile Tag Signature: 'rXYZ'.
 548      */
 549     public static final int icSigRedColorantTag   = 0x7258595A;    /* 'rXYZ' */
 550 
 551     /**
 552      * ICC Profile Tag Signature: 'rXYZ'.

 553      * @since 1.5
 554      */
 555     public static final int icSigRedMatrixColumnTag = 0x7258595A;  /* 'rXYZ' */
 556 
 557     /**
 558      * ICC Profile Tag Signature: 'rTRC'.
 559      */
 560     public static final int icSigRedTRCTag        = 0x72545243;    /* 'rTRC' */
 561 
 562     /**
 563      * ICC Profile Tag Signature: 'scrd'.
 564      */
 565     public static final int icSigScreeningDescTag = 0x73637264;    /* 'scrd' */
 566 
 567     /**
 568      * ICC Profile Tag Signature: 'scrn'.
 569      */
 570     public static final int icSigScreeningTag     = 0x7363726E;    /* 'scrn' */
 571 
 572     /**


 579      */
 580     public static final int icSigUcrBgTag         = 0x62666420;    /* 'bfd ' */
 581 
 582     /**
 583      * ICC Profile Tag Signature: 'vued'.
 584      */
 585     public static final int icSigViewingCondDescTag = 0x76756564;  /* 'vued' */
 586 
 587     /**
 588      * ICC Profile Tag Signature: 'view'.
 589      */
 590     public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
 591 
 592     /**
 593      * ICC Profile Tag Signature: 'chrm'.
 594      */
 595     public static final int icSigChromaticityTag  = 0x6368726d;    /* 'chrm' */
 596 
 597     /**
 598      * ICC Profile Tag Signature: 'chad'.

 599      * @since 1.5
 600      */
 601     public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
 602 
 603     /**
 604      * ICC Profile Tag Signature: 'clro'.

 605      * @since 1.5
 606      */
 607     public static final int icSigColorantOrderTag = 0x636C726F;    /* 'clro' */
 608 
 609     /**
 610      * ICC Profile Tag Signature: 'clrt'.

 611      * @since 1.5
 612      */
 613     public static final int icSigColorantTableTag = 0x636C7274;    /* 'clrt' */
 614 
 615 
 616     /**
 617      * ICC Profile Header Location: profile size in bytes.
 618      */
 619     public static final int icHdrSize         = 0;  /* Profile size in bytes */
 620 
 621     /**
 622      * ICC Profile Header Location: CMM for this profile.
 623      */
 624     public static final int icHdrCmmId        = 4;  /* CMM for this profile */
 625 
 626     /**
 627      * ICC Profile Header Location: format version number.
 628      */
 629     public static final int icHdrVersion      = 8;  /* Format version number */
 630 


 678      */
 679     public static final int icHdrAttributes   = 56; /* Device attributes */
 680 
 681     /**
 682      * ICC Profile Header Location: rendering intent.
 683      */
 684     public static final int icHdrRenderingIntent = 64; /* Rendering intent */
 685 
 686     /**
 687      * ICC Profile Header Location: profile illuminant.
 688      */
 689     public static final int icHdrIlluminant   = 68; /* Profile illuminant */
 690 
 691     /**
 692      * ICC Profile Header Location: profile creator.
 693      */
 694     public static final int icHdrCreator      = 80; /* Profile creator */
 695 
 696     /**
 697      * ICC Profile Header Location: profile's ID.

 698      * @since 1.5
 699      */
 700     public static final int icHdrProfileID = 84; /* Profile's ID */
 701 
 702 
 703     /**
 704      * ICC Profile Constant: tag type signature.
 705      */
 706     public static final int icTagType          = 0;    /* tag type signature */
 707 
 708     /**
 709      * ICC Profile Constant: reserved.
 710      */
 711     public static final int icTagReserved      = 4;    /* reserved */
 712 
 713     /**
 714      * ICC Profile Constant: curveType count.
 715      */
 716     public static final int icCurveCount       = 8;    /* curveType count */
 717 
 718     /**
 719      * ICC Profile Constant: curveType data.
 720      */
 721     public static final int icCurveData        = 12;   /* curveType data */
 722 
 723     /**
 724      * ICC Profile Constant: XYZNumber X.
 725      */
 726     public static final int icXYZNumberX       = 8;    /* XYZNumber X */
 727 
 728 
 729     /**
 730      * Constructs an ICC_Profile object with a given ID.
 731      */
 732     ICC_Profile(Profile p) {
 733         this.cmmProfile = p;
 734     }
 735 
 736 
 737     /**
 738      * Constructs an ICC_Profile object whose loading will be deferred.
 739      * The ID will be 0 until the profile is loaded.
 740      */
 741     ICC_Profile(ProfileDeferralInfo pdi) {
 742         this.deferralInfo = pdi;
 743         this.profileActivator = new ProfileActivator() {
 744             public void activate() throws ProfileDataException {
 745                 activateDeferredProfile();
 746             }
 747         };
 748         ProfileDeferralMgr.registerDeferral(this.profileActivator);
 749     }
 750 
 751 
 752     /**
 753      * Frees the resources associated with an ICC_Profile object.
 754      *
 755      * @deprecated The {@code finalize} method has been deprecated.
 756      *     Subclasses that override {@code finalize} in order to perform cleanup
 757      *     should be modified to use alternative cleanup mechanisms and
 758      *     to remove the overriding {@code finalize} method.
 759      *     When overriding the {@code finalize} method, its implementation must explicitly
 760      *     ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
 761      *     See the specification for {@link Object#finalize()} for further
 762      *     information about migration options.

 763      */
 764     @Deprecated(since="9")
 765     protected void finalize () {
 766         if (cmmProfile != null) {
 767             CMSManager.getModule().freeProfile(cmmProfile);
 768         } else if (profileActivator != null) {
 769             ProfileDeferralMgr.unregisterDeferral(profileActivator);
 770         }
 771     }
 772 
 773 
 774     /**
 775      * Constructs an ICC_Profile object corresponding to the data in
 776      * a byte array.  Throws an IllegalArgumentException if the data
 777      * does not correspond to a valid ICC Profile.

 778      * @param data the specified ICC Profile data
 779      * @return an {@code ICC_Profile} object corresponding to
 780      *          the data in the specified {@code data} array.
 781      */
 782     public static ICC_Profile getInstance(byte[] data) {
 783     ICC_Profile thisProfile;
 784 
 785         Profile p = null;
 786 
 787         if (ProfileDeferralMgr.deferring) {
 788             ProfileDeferralMgr.activateProfiles();
 789         }
 790 
 791         ProfileDataVerifier.verify(data);
 792 
 793         try {
 794             p = CMSManager.getModule().loadProfile(data);
 795         } catch (CMMException c) {
 796             throw new IllegalArgumentException("Invalid ICC Profile Data");
 797         }
 798 
 799         try {
 800             if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&


 804             }
 805             else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
 806                 (getData (p, icSigMediaWhitePointTag) != null) &&
 807                 (getData (p, icSigRedColorantTag) != null) &&
 808                 (getData (p, icSigGreenColorantTag) != null) &&
 809                 (getData (p, icSigBlueColorantTag) != null) &&
 810                 (getData (p, icSigRedTRCTag) != null) &&
 811                 (getData (p, icSigGreenTRCTag) != null) &&
 812                 (getData (p, icSigBlueTRCTag) != null)) {
 813                 thisProfile = new ICC_ProfileRGB (p);
 814             }
 815             else {
 816                 thisProfile = new ICC_Profile (p);
 817             }
 818         } catch (CMMException c) {
 819             thisProfile = new ICC_Profile (p);
 820         }
 821         return thisProfile;
 822     }
 823 
 824 
 825 
 826     /**
 827      * Constructs an ICC_Profile corresponding to one of the specific color
 828      * spaces defined by the ColorSpace class (for example CS_sRGB).
 829      * Throws an IllegalArgumentException if cspace is not one of the
 830      * defined color spaces.
 831      *
 832      * @param cspace the type of color space to create a profile for.
 833      * The specified type is one of the color
 834      * space constants defined in the  {@code ColorSpace} class.
 835      *
 836      * @return an {@code ICC_Profile} object corresponding to
 837      *          the specified {@code ColorSpace} type.
 838      * @exception IllegalArgumentException If {@code cspace} is not
 839      * one of the predefined color space types.
 840      */
 841     public static ICC_Profile getInstance (int cspace) {
 842         ICC_Profile thisProfile = null;
 843         String fileName;
 844 
 845         switch (cspace) {
 846         case ColorSpace.CS_sRGB:
 847             synchronized(ICC_Profile.class) {
 848                 if (sRGBprofile == null) {
 849                     /*
 850                      * Deferral is only used for standard profiles.
 851                      * Enabling the appropriate access privileges is handled
 852                      * at a lower level.
 853                      */
 854                     ProfileDeferralInfo pInfo =
 855                         new ProfileDeferralInfo("sRGB.pf",
 856                                                 ColorSpace.TYPE_RGB, 3,
 857                                                 CLASS_DISPLAY);
 858                     sRGBprofile = getDeferredInstance(pInfo);
 859                 }


 914             synchronized(ICC_Profile.class) {
 915                 if (LINEAR_RGBprofile == null) {
 916                     ProfileDeferralInfo pInfo =
 917                         new ProfileDeferralInfo("LINEAR_RGB.pf",
 918                                                 ColorSpace.TYPE_RGB, 3,
 919                                                 CLASS_DISPLAY);
 920                     LINEAR_RGBprofile = getDeferredInstance(pInfo);
 921                 }
 922                 thisProfile = LINEAR_RGBprofile;
 923             }
 924 
 925             break;
 926 
 927         default:
 928             throw new IllegalArgumentException("Unknown color space");
 929         }
 930 
 931         return thisProfile;
 932     }
 933 
 934     /* This asserts system privileges, so is used only for the
 935      * standard profiles.

 936      */
 937     private static ICC_Profile getStandardProfile(final String name) {
 938 
 939         return AccessController.doPrivileged(
 940             new PrivilegedAction<ICC_Profile>() {
 941                  public ICC_Profile run() {
 942                      ICC_Profile p = null;
 943                      try {
 944                          p = getInstance (name);
 945                      } catch (IOException ex) {
 946                          throw new IllegalArgumentException(
 947                                "Can't load standard profile: " + name);
 948                      }
 949                      return p;
 950                  }
 951              });
 952     }
 953 
 954     /**
 955      * Constructs an ICC_Profile corresponding to the data in a file.
 956      * fileName may be an absolute or a relative file specification.
 957      * Relative file names are looked for in several places: first, relative
 958      * to any directories specified by the java.iccprofile.path property;
 959      * second, relative to any directories specified by the java.class.path
 960      * property; finally, in a directory used to store profiles always
 961      * available, such as the profile for sRGB.  Built-in profiles use .pf as
 962      * the file name extension for profiles, e.g. sRGB.pf.
 963      * This method throws an IOException if the specified file cannot be
 964      * opened or if an I/O error occurs while reading the file.  It throws
 965      * an IllegalArgumentException if the file does not contain valid ICC
 966      * Profile data.
 967      * @param fileName The file that contains the data for the profile.
 968      *
 969      * @return an {@code ICC_Profile} object corresponding to
 970      *          the data in the specified file.
 971      * @exception IOException If the specified file cannot be opened or
 972      * an I/O error occurs while reading the file.
 973      *
 974      * @exception IllegalArgumentException If the file does not
 975      * contain valid ICC Profile data.
 976      *
 977      * @exception SecurityException If a security manager is installed
 978      * and it does not permit read access to the given file.
 979      */
 980     public static ICC_Profile getInstance(String fileName) throws IOException {
 981         ICC_Profile thisProfile;
 982         InputStream is = null;
 983 
 984 
 985         File f = getProfileFile(fileName);
 986         if (f != null) {
 987             is = new FileInputStream(f);
 988         } else {
 989             is = getStandardProfileInputStream(fileName);
 990         }
 991         if (is == null) {
 992             throw new IOException("Cannot open file " + fileName);
 993         }
 994 
 995         thisProfile = getInstance(is);
 996 
 997         is.close();    /* close the file */
 998 
 999         return thisProfile;
1000     }
1001 
1002 
1003     /**
1004      * Constructs an ICC_Profile corresponding to the data in an InputStream.
1005      * This method throws an IllegalArgumentException if the stream does not
1006      * contain valid ICC Profile data.  It throws an IOException if an I/O
1007      * error occurs while reading the stream.
1008      * @param s The input stream from which to read the profile data.
1009      *
1010      * @return an {@code ICC_Profile} object corresponding to the
1011      *     data in the specified {@code InputStream}.
1012      *
1013      * @exception IOException If an I/O error occurs while reading the stream.
1014      *
1015      * @exception IllegalArgumentException If the stream does not
1016      * contain valid ICC Profile data.
1017      */
1018     public static ICC_Profile getInstance(InputStream s) throws IOException {
1019     byte[] profileData;
1020 
1021         if (s instanceof ProfileDeferralInfo) {
1022             /* hack to detect profiles whose loading can be deferred */
1023             return getDeferredInstance((ProfileDeferralInfo) s);
1024         }
1025 
1026         if ((profileData = getProfileDataFromStream(s)) == null) {
1027             throw new IllegalArgumentException("Invalid ICC Profile Data");
1028         }
1029 
1030         return getInstance(profileData);
1031     }
1032 
1033 
1034     static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1035     byte[] profileData;
1036     int profileSize;


1053         }
1054         profileSize = ((header[0] & 0xff) << 24) |
1055                       ((header[1] & 0xff) << 16) |
1056                       ((header[2] & 0xff) <<  8) |
1057                        (header[3] & 0xff);
1058         profileData = new byte[profileSize];
1059         System.arraycopy(header, 0, profileData, 0, 128);
1060         bytestoread = profileSize - 128;
1061         bytesread = 128;
1062         while (bytestoread != 0) {
1063             if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1064                 return null;
1065             }
1066             bytesread += n;
1067             bytestoread -= n;
1068         }
1069 
1070         return profileData;
1071     }
1072 
1073 
1074     /**
1075      * Constructs an ICC_Profile for which the actual loading of the
1076      * profile data from a file and the initialization of the CMM should
1077      * be deferred as long as possible.
1078      * Deferral is only used for standard profiles.
1079      * If deferring is disabled, then getStandardProfile() ensures
1080      * that all of the appropriate access privileges are granted
1081      * when loading this profile.
1082      * If deferring is enabled, then the deferred activation
1083      * code will take care of access privileges.
1084      * @see #activateDeferredProfile()
1085      */
1086     static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1087         if (!ProfileDeferralMgr.deferring) {
1088             return getStandardProfile(pdi.filename);
1089         }
1090         if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1091             return new ICC_ProfileRGB(pdi);
1092         } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1093             return new ICC_ProfileGray(pdi);
1094         } else {
1095             return new ICC_Profile(pdi);
1096         }
1097     }
1098 
1099 
1100     void activateDeferredProfile() throws ProfileDataException {
1101         byte[] profileData;
1102         final String fileName = deferralInfo.filename;
1103 


1114         catch (IOException e) {
1115             ProfileDataException pde = new
1116                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1117             pde.initCause(e);
1118             throw pde;
1119         }
1120         if (profileData == null) {
1121             throw new ProfileDataException("Invalid ICC Profile Data" +
1122                 fileName);
1123         }
1124         try {
1125             cmmProfile = CMSManager.getModule().loadProfile(profileData);
1126         } catch (CMMException c) {
1127             ProfileDataException pde = new
1128                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1129             pde.initCause(c);
1130             throw pde;
1131         }
1132     }
1133 
1134 
1135     /**
1136      * Returns profile major version.
1137      * @return  The major version of the profile.

1138      */
1139     public int getMajorVersion() {
1140     byte[] theHeader;
1141 
1142         theHeader = getData(icSigHead); /* getData will activate deferred
1143                                            profiles if necessary */
1144 
1145         return (int) theHeader[8];
1146     }
1147 
1148     /**
1149      * Returns profile minor version.
1150      * @return The minor version of the profile.

1151      */
1152     public int getMinorVersion() {
1153     byte[] theHeader;
1154 
1155         theHeader = getData(icSigHead); /* getData will activate deferred
1156                                            profiles if necessary */
1157 
1158         return (int) theHeader[9];
1159     }
1160 
1161     /**
1162      * Returns the profile class.
1163      * @return One of the predefined profile class constants.

1164      */
1165     public int getProfileClass() {
1166     byte[] theHeader;
1167     int theClassSig, theClass;
1168 
1169         if (deferralInfo != null) {
1170             return deferralInfo.profileClass; /* Need to have this info for
1171                                                  ICC_ColorSpace without
1172                                                  causing a deferred profile
1173                                                  to be loaded */
1174         }
1175 
1176         theHeader = getData(icSigHead);
1177 
1178         theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1179 
1180         switch (theClassSig) {
1181         case icSigInputClass:
1182             theClass = CLASS_INPUT;
1183             break;


1198             theClass = CLASS_COLORSPACECONVERSION;
1199             break;
1200 
1201         case icSigAbstractClass:
1202             theClass = CLASS_ABSTRACT;
1203             break;
1204 
1205         case icSigNamedColorClass:
1206             theClass = CLASS_NAMEDCOLOR;
1207             break;
1208 
1209         default:
1210             throw new IllegalArgumentException("Unknown profile class");
1211         }
1212 
1213         return theClass;
1214     }
1215 
1216     /**
1217      * Returns the color space type.  Returns one of the color space type
1218      * constants defined by the ColorSpace class.  This is the
1219      * "input" color space of the profile.  The type defines the
1220      * number of components of the color space and the interpretation,
1221      * e.g. TYPE_RGB identifies a color space with three components - red,
1222      * green, and blue.  It does not define the particular color
1223      * characteristics of the space, e.g. the chromaticities of the
1224      * primaries.
1225      * @return One of the color space type constants defined in the
1226      * {@code ColorSpace} class.
1227      */
1228     public int getColorSpaceType() {
1229         if (deferralInfo != null) {
1230             return deferralInfo.colorSpaceType; /* Need to have this info for
1231                                                    ICC_ColorSpace without
1232                                                    causing a deferred profile
1233                                                    to be loaded */
1234         }
1235         return    getColorSpaceType(cmmProfile);
1236     }
1237 
1238     static int getColorSpaceType(Profile p) {
1239     byte[] theHeader;
1240     int theColorSpaceSig, theColorSpace;
1241 
1242         theHeader = getData(p, icSigHead);
1243         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1244         theColorSpace = iccCStoJCS (theColorSpaceSig);
1245         return theColorSpace;
1246     }
1247 
1248     /**
1249      * Returns the color space type of the Profile Connection Space (PCS).
1250      * Returns one of the color space type constants defined by the
1251      * ColorSpace class.  This is the "output" color space of the
1252      * profile.  For an input, display, or output profile useful
1253      * for tagging colors or images, this will be either TYPE_XYZ or
1254      * TYPE_Lab and should be interpreted as the corresponding specific
1255      * color space defined in the ICC specification.  For a device
1256      * link profile, this could be any of the color space type constants.
1257      * @return One of the color space type constants defined in the
1258      * {@code ColorSpace} class.

1259      */
1260     public int getPCSType() {
1261         if (ProfileDeferralMgr.deferring) {
1262             ProfileDeferralMgr.activateProfiles();
1263         }
1264         return getPCSType(cmmProfile);
1265     }
1266 
1267 
1268     static int getPCSType(Profile p) {
1269     byte[] theHeader;
1270     int thePCSSig, thePCS;
1271 
1272         theHeader = getData(p, icSigHead);
1273         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1274         thePCS = iccCStoJCS(thePCSSig);
1275         return thePCS;
1276     }
1277 
1278 
1279     /**
1280      * Write this ICC_Profile to a file.
1281      *
1282      * @param fileName The file to write the profile data to.
1283      *
1284      * @exception IOException If the file cannot be opened for writing
1285      * or an I/O error occurs while writing to the file.

1286      */
1287     public void write(String fileName) throws IOException {
1288     FileOutputStream outputFile;
1289     byte[] profileData;
1290 
1291         profileData = getData(); /* this will activate deferred
1292                                     profiles if necessary */
1293         outputFile = new FileOutputStream(fileName);
1294         outputFile.write(profileData);
1295         outputFile.close ();
1296     }
1297 
1298 
1299     /**
1300      * Write this ICC_Profile to an OutputStream.
1301      *
1302      * @param s The stream to write the profile data to.
1303      *
1304      * @exception IOException If an I/O error occurs while writing to the
1305      * stream.
1306      */
1307     public void write(OutputStream s) throws IOException {
1308     byte[] profileData;
1309 
1310         profileData = getData(); /* this will activate deferred
1311                                     profiles if necessary */
1312         s.write(profileData);
1313     }
1314 
1315 
1316     /**
1317      * Returns a byte array corresponding to the data of this ICC_Profile.
1318      * @return A byte array that contains the profile data.


1319      * @see #setData(int, byte[])
1320      */
1321     public byte[] getData() {
1322     int profileSize;
1323     byte[] profileData;
1324 
1325         if (ProfileDeferralMgr.deferring) {
1326             ProfileDeferralMgr.activateProfiles();
1327         }
1328 
1329         PCMM mdl = CMSManager.getModule();
1330 
1331         /* get the number of bytes needed for this profile */
1332         profileSize = mdl.getProfileSize(cmmProfile);
1333 
1334         profileData = new byte [profileSize];
1335 
1336         /* get the data for the profile */
1337         mdl.getProfileData(cmmProfile, profileData);
1338 
1339         return profileData;
1340     }
1341 
1342 
1343     /**
1344      * Returns a particular tagged data element from the profile as
1345      * a byte array.  Elements are identified by signatures
1346      * as defined in the ICC specification.  The signature
1347      * icSigHead can be used to get the header.  This method is useful
1348      * for advanced applets or applications which need to access
1349      * profile data directly.
1350      *
1351      * @param tagSignature The ICC tag signature for the data element you
1352      * want to get.
1353      *
1354      * @return A byte array that contains the tagged data element. Returns


1355      * {@code null} if the specified tag doesn't exist.
1356      * @see #setData(int, byte[])
1357      */
1358     public byte[] getData(int tagSignature) {
1359 
1360         if (ProfileDeferralMgr.deferring) {
1361             ProfileDeferralMgr.activateProfiles();
1362         }
1363 
1364         return getData(cmmProfile, tagSignature);
1365     }
1366 
1367 
1368     static byte[] getData(Profile p, int tagSignature) {
1369     int tagSize;
1370     byte[] tagData;
1371 
1372         try {
1373             PCMM mdl = CMSManager.getModule();
1374 
1375             /* get the number of bytes needed for this tag */
1376             tagSize = mdl.getTagSize(p, tagSignature);
1377 
1378             tagData = new byte[tagSize]; /* get an array for the tag */
1379 
1380             /* get the tag's data */
1381             mdl.getTagData(p, tagSignature, tagData);
1382         } catch(CMMException c) {
1383             tagData = null;
1384         }
1385 
1386         return tagData;
1387     }
1388 
1389     /**
1390      * Sets a particular tagged data element in the profile from
1391      * a byte array. The array should contain data in a format, corresponded
1392      * to the {@code tagSignature} as defined in the ICC specification, section 10.
1393      * This method is useful for advanced applets or applications which need to
1394      * access profile data directly.
1395      *
1396      * @param tagSignature The ICC tag signature for the data element
1397      * you want to set.
1398      * @param tagData the data to set for the specified tag signature
1399      * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1400      *         as defined in the ICC specification.
1401      * @throws IllegalArgumentException if a content of the {@code tagData}
1402      *         array can not be interpreted as valid tag data, corresponding
1403      *         to the {@code tagSignature}.
1404      * @see #getData
1405      */
1406     public void setData(int tagSignature, byte[] tagData) {
1407 
1408         if (ProfileDeferralMgr.deferring) {
1409             ProfileDeferralMgr.activateProfiles();
1410         }
1411 
1412         CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1413     }
1414 
1415     /**
1416      * Sets the rendering intent of the profile.
1417      * This is used to select the proper transform from a profile that
1418      * has multiple transforms.
1419      */
1420     void setRenderingIntent(int renderingIntent) {
1421         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1422                                                  profiles if necessary */
1423         intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1424                                                  /* set the rendering intent */
1425         setData (icSigHead, theHeader);
1426     }
1427 
1428 
1429     /**
1430      * Returns the rendering intent of the profile.
1431      * This is used to select the proper transform from a profile that
1432      * has multiple transforms.  It is typically set in a source profile
1433      * to select a transform from an output profile.
1434      */
1435     int getRenderingIntent() {
1436         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1437                                                  profiles if necessary */
1438 
1439         int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1440                                                  /* set the rendering intent */
1441 
1442         /* According to ICC spec, only the least-significant 16 bits shall be
1443          * used to encode the rendering intent. The most significant 16 bits
1444          * shall be set to zero. Thus, we are ignoring two most significant
1445          * bytes here.
1446          *
1447          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1448          */
1449         return (0xffff & renderingIntent);
1450     }
1451 
1452 
1453     /**
1454      * Returns the number of color components in the "input" color
1455      * space of this profile.  For example if the color space type
1456      * of this profile is TYPE_RGB, then this method will return 3.
1457      *
1458      * @return The number of color components in the profile's input
1459      * color space.
1460      *
1461      * @throws ProfileDataException if color space is in the profile
1462      *         is invalid
1463      */
1464     public int getNumComponents() {
1465     byte[]    theHeader;
1466     int    theColorSpaceSig, theNumComponents;
1467 
1468         if (deferralInfo != null) {
1469             return deferralInfo.numComponents; /* Need to have this info for
1470                                                   ICC_ColorSpace without
1471                                                   causing a deferred profile
1472                                                   to be loaded */
1473         }
1474         theHeader = getData(icSigHead);
1475 
1476         theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1477 
1478         switch (theColorSpaceSig) {
1479         case icSigGrayData:
1480             theNumComponents = 1;
1481             break;
1482 


1536 
1537         case icSigSpaceDCLR:
1538             theNumComponents = 13;
1539             break;
1540 
1541         case icSigSpaceECLR:
1542             theNumComponents = 14;
1543             break;
1544 
1545         case icSigSpaceFCLR:
1546             theNumComponents = 15;
1547             break;
1548 
1549         default:
1550             throw new ProfileDataException ("invalid ICC color space");
1551         }
1552 
1553         return theNumComponents;
1554     }
1555 
1556 
1557     /**
1558      * Returns a float array of length 3 containing the X, Y, and Z
1559      * components of the mediaWhitePointTag in the ICC profile.
1560      */
1561     float[] getMediaWhitePoint() {
1562         return getXYZTag(icSigMediaWhitePointTag);
1563                                            /* get the media white point tag */
1564     }
1565 
1566 
1567     /**
1568      * Returns a float array of length 3 containing the X, Y, and Z
1569      * components encoded in an XYZType tag.
1570      */
1571     float[] getXYZTag(int theTagSignature) {
1572     byte[] theData;
1573     float[] theXYZNumber;
1574     int i1, i2, theS15Fixed16;
1575 
1576         theData = getData(theTagSignature); /* get the tag data */
1577                                             /* getData will activate deferred
1578                                                profiles if necessary */
1579 
1580         theXYZNumber = new float [3];        /* array to return */
1581 
1582         /* convert s15Fixed16Number to float */
1583         for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1584             theS15Fixed16 = intFromBigEndian(theData, i2);
1585             theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1586         }
1587         return theXYZNumber;
1588     }
1589 
1590 
1591     /**
1592      * Returns a gamma value representing a tone reproduction
1593      * curve (TRC).  If the profile represents the TRC as a table rather
1594      * than a single gamma value, then an exception is thrown.  In this
1595      * case the actual table can be obtained via getTRC().
1596      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1597      * icSigGreenTRCTag, or icSigBlueTRCTag.
1598      * @return the gamma value as a float.
1599      * @exception ProfileDataException if the profile does not specify
1600      *            the TRC as a single gamma value.

1601      */
1602     float getGamma(int theTagSignature) {
1603     byte[] theTRCData;
1604     float theGamma;
1605     int theU8Fixed8;
1606 
1607         theTRCData = getData(theTagSignature); /* get the TRC */
1608                                                /* getData will activate deferred
1609                                                   profiles if necessary */
1610 
1611         if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1612             throw new ProfileDataException ("TRC is not a gamma");
1613         }
1614 
1615         /* convert u8Fixed8 to float */
1616         theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1617 
1618         theGamma = ((float) theU8Fixed8) / 256.0f;
1619 
1620         return theGamma;
1621     }
1622 
1623 
1624     /**
1625      * Returns the TRC as an array of shorts.  If the profile has
1626      * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1627      * value, this method throws an exception, and the getGamma() method
1628      * should be used to get the gamma value.  Otherwise the short array
1629      * returned here represents a lookup table where the input Gray value
1630      * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
1631      * to array index 0 and value 1.0 maps to array index length-1.
1632      * Interpolation may be used to generate output values for
1633      * input values which do not map exactly to an index in the
1634      * array.  Output values also map linearly to the range [0.0, 1.0].
1635      * Value 0.0 is represented by an array value of 0x0000 and
1636      * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1637      * short values, although they are returned in a short array.
1638      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1639      * icSigGreenTRCTag, or icSigBlueTRCTag.
1640      * @return a short array representing the TRC.
1641      * @exception ProfileDataException if the profile does not specify
1642      *            the TRC as a table.
1643      */
1644     short[] getTRC(int theTagSignature) {
1645     byte[] theTRCData;
1646     short[] theTRC;
1647     int i1, i2, nElements, theU8Fixed8;
1648 
1649         theTRCData = getData(theTagSignature); /* get the TRC */
1650                                                /* getData will activate deferred
1651                                                   profiles if necessary */
1652 
1653         nElements = intFromBigEndian(theTRCData, icCurveCount);
1654 
1655         if (nElements == 1) {
1656             throw new ProfileDataException("TRC is not a table");
1657         }
1658 
1659         /* make the short array */
1660         theTRC = new short [nElements];
1661 
1662         for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1663             theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1664         }
1665 
1666         return theTRC;
1667     }
1668 
1669 
1670     /* convert an ICC color space signature into a Java color space type */

1671     static int iccCStoJCS(int theColorSpaceSig) {
1672     int theColorSpace;
1673 
1674         switch (theColorSpaceSig) {
1675         case icSigXYZData:
1676             theColorSpace = ColorSpace.TYPE_XYZ;
1677             break;
1678 
1679         case icSigLabData:
1680             theColorSpace = ColorSpace.TYPE_Lab;
1681             break;
1682 
1683         case icSigLuvData:
1684             theColorSpace = ColorSpace.TYPE_Luv;
1685             break;
1686 
1687         case icSigYCbCrData:
1688             theColorSpace = ColorSpace.TYPE_YCbCr;
1689             break;
1690 


1758 
1759         case icSigSpaceCCLR:
1760             theColorSpace = ColorSpace.TYPE_CCLR;
1761             break;
1762 
1763         case icSigSpaceDCLR:
1764             theColorSpace = ColorSpace.TYPE_DCLR;
1765             break;
1766 
1767         case icSigSpaceECLR:
1768             theColorSpace = ColorSpace.TYPE_ECLR;
1769             break;
1770 
1771         case icSigSpaceFCLR:
1772             theColorSpace = ColorSpace.TYPE_FCLR;
1773             break;
1774 
1775         default:
1776             throw new IllegalArgumentException ("Unknown color space");
1777         }
1778 
1779         return theColorSpace;
1780     }
1781 
1782 
1783     static int intFromBigEndian(byte[] array, int index) {
1784         return (((array[index]   & 0xff) << 24) |
1785                 ((array[index+1] & 0xff) << 16) |
1786                 ((array[index+2] & 0xff) <<  8) |
1787                  (array[index+3] & 0xff));
1788     }
1789 
1790 
1791     static void intToBigEndian(int value, byte[] array, int index) {
1792             array[index]   = (byte) (value >> 24);
1793             array[index+1] = (byte) (value >> 16);
1794             array[index+2] = (byte) (value >>  8);
1795             array[index+3] = (byte) (value);
1796     }
1797 
1798 
1799     static short shortFromBigEndian(byte[] array, int index) {
1800         return (short) (((array[index]   & 0xff) << 8) |
1801                          (array[index+1] & 0xff));
1802     }
1803 
1804 
1805     static void shortToBigEndian(short value, byte[] array, int index) {
1806             array[index]   = (byte) (value >> 8);
1807             array[index+1] = (byte) (value);
1808     }
1809 
1810 
1811     /*
1812      * fileName may be an absolute or a relative file specification.
1813      * Relative file names are looked for in several places: first, relative
1814      * to any directories specified by the java.iccprofile.path property;
1815      * second, relative to any directories specified by the java.class.path.
1816      * The built-in profile files are now loaded as resources, since they
1817      * may not be individual disk files, and so this method will not find
1818      * these and on a null return, the caller needs to try as resources.
1819      * Built-in profiles use .pf as the file name extension for profiles,
1820      * e.g. sRGB.pf.
1821      */
1822     private static File getProfileFile(String fileName) {
1823         String path, dir, fullPath;
1824 
1825         File f = new File(fileName); /* try absolute file name */
1826         if (f.isAbsolute()) {
1827             /* Rest of code has little sense for an absolute pathname,
1828                so return here. */
1829             return f.isFile() ? f : null;
1830         }
1831         if ((!f.isFile()) &&
1832                 ((path = System.getProperty("java.iccprofile.path")) != null)){
1833                                     /* try relative to java.iccprofile.path */
1834                 StringTokenizer st =
1835                     new StringTokenizer(path, File.pathSeparator);
1836                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1837                     dir = st.nextToken();
1838                         fullPath = dir + File.separatorChar + fileName;
1839                     f = new File(fullPath);
1840                     if (!isChildOf(f, dir)) {


1845 
1846         if (((f == null) || (!f.isFile())) &&
1847                 ((path = System.getProperty("java.class.path")) != null)) {
1848                                     /* try relative to java.class.path */
1849                 StringTokenizer st =
1850                     new StringTokenizer(path, File.pathSeparator);
1851                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1852                     dir = st.nextToken();
1853                         fullPath = dir + File.separatorChar + fileName;
1854                     f = new File(fullPath);
1855                 }
1856         }
1857 
1858         if (f != null && !f.isFile()) {
1859             f = null;
1860         }
1861         return f;
1862     }
1863 
1864     /**
1865      * Returns a stream corresponding to a built-in profile
1866      * specified by fileName.
1867      * If there is no built-in profile with such name, then the method
1868      * returns null.
1869      */
1870     private static InputStream getStandardProfileInputStream(String fileName) {
1871         return AccessController.doPrivileged(
1872             new PrivilegedAction<InputStream>() {
1873                 public InputStream run () {
1874                     return
1875                         PCMM.class.getResourceAsStream("profiles/" + fileName);
1876                 }
1877             }, null, new FilePermission("<<ALL FILES>>", "read"),
1878                      new RuntimePermission("accessSystemModules"));
1879     }
1880 
1881     /**
1882      * Checks whether given file resides inside give directory.
1883      */
1884     private static boolean isChildOf(File f, String dirName) {
1885         try {
1886             File dir = new File(dirName);
1887             String canonicalDirName = dir.getCanonicalPath();
1888             if (!canonicalDirName.endsWith(File.separator)) {


1892             return canonicalFileName.startsWith(canonicalDirName);
1893         } catch (IOException e) {
1894             /* we do not expect the IOException here, because invocation
1895              * of this function is always preceded by isFile() call.
1896              */
1897             return false;
1898         }
1899     }
1900 
1901     /**
1902      * Checks whether built-in profile specified by fileName exists.
1903      */
1904     private static boolean standardProfileExists(final String fileName) {
1905         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1906                 public Boolean run() {
1907                     return PCMM.class.getResource("profiles/"+fileName) != null;
1908                 }
1909             });
1910     }
1911 
1912 
1913     /*
1914      * Serialization support.
1915      *
1916      * Directly deserialized profiles are useless since they are not
1917      * registered with CMM.  We don't allow constructor to be called
1918      * directly and instead have clients to call one of getInstance
1919      * factory methods that will register the profile with CMM.  For
1920      * deserialization we implement readResolve method that will
1921      * resolve the bogus deserialized profile object with one obtained
1922      * with getInstance as well.
1923      *
1924      * There are two primary factory methods for construction of ICC
1925      * profiles: getInstance(int cspace) and getInstance(byte[] data).
1926      * This implementation of ICC_Profile uses the former to return a
1927      * cached singleton profile object, other implementations will
1928      * likely use this technique too.  To preserve the singleton
1929      * pattern across serialization we serialize cached singleton
1930      * profiles in such a way that deserializing VM could call
1931      * getInstance(int cspace) method that will resolve deserialized
1932      * object into the corresponding singleton as well.
1933      *
1934      * Since the singletons are private to ICC_Profile the readResolve
1935      * method have to be `protected' instead of `private' so that
1936      * singletons that are instances of subclasses of ICC_Profile
1937      * could be correctly deserialized.
1938      */
1939 
1940 
1941     /**
1942      * Version of the format of additional serialized data in the
1943      * stream.  Version&nbsp;{@code 1} corresponds to Java&nbsp;2
1944      * Platform,&nbsp;v1.3.
1945      * @since 1.3
1946      * @serial

1947      */
1948     private int iccProfileSerializedDataVersion = 1;
1949 
1950 
1951     /**
1952      * Writes default serializable fields to the stream.  Writes a
1953      * string and an array of bytes to the stream as additional data.
1954      *
1955      * @param s stream used for serialization.
1956      * @throws IOException
1957      *     thrown by {@code ObjectInputStream}.
1958      * @serialData
1959      *     The {@code String} is the name of one of
1960      *     <code>CS_<var>*</var></code> constants defined in the
1961      *     {@link ColorSpace} class if the profile object is a profile
1962      *     for a predefined color space (for example
1963      *     {@code "CS_sRGB"}).  The string is {@code null}
1964      *     otherwise.
1965      *     <p>
1966      *     The {@code byte[]} array is the profile data for the
1967      *     profile.  For predefined color spaces {@code null} is
1968      *     written instead of the profile data.  If in the future
1969      *     versions of Java API new predefined color spaces will be
1970      *     added, future versions of this class may choose to write
1971      *     for new predefined color spaces not only the color space
1972      *     name, but the profile data as well so that older versions
1973      *     could still deserialize the object.
1974      */
1975     private void writeObject(ObjectOutputStream s)
1976       throws IOException
1977     {
1978         s.defaultWriteObject();
1979 
1980         String csName = null;
1981         if (this == sRGBprofile) {
1982             csName = "CS_sRGB";
1983         } else if (this == XYZprofile) {
1984             csName = "CS_CIEXYZ";
1985         } else if (this == PYCCprofile) {
1986             csName = "CS_PYCC";
1987         } else if (this == GRAYprofile) {
1988             csName = "CS_GRAY";
1989         } else if (this == LINEAR_RGBprofile) {
1990             csName = "CS_LINEAR_RGB";
1991         }
1992 
1993         // Future versions may choose to write profile data for new
1994         // predefined color spaces as well, if any will be introduced,
1995         // so that old versions that don't recognize the new CS name
1996         // may fall back to constructing profile from the data.
1997         byte[] data = null;
1998         if (csName == null) {
1999             // getData will activate deferred profile if necessary
2000             data = getData();
2001         }
2002 
2003         s.writeObject(csName);
2004         s.writeObject(data);
2005     }
2006 
2007     // Temporary storage used by readObject to store resolved profile
2008     // (obtained with getInstance) for readResolve to return.
2009     private transient ICC_Profile resolvedDeserializedProfile;
2010 
2011     /**
2012      * Reads default serializable fields from the stream.  Reads from
2013      * the stream a string and an array of bytes as additional data.
2014      *
2015      * @param s stream used for deserialization.
2016      * @throws IOException
2017      *     thrown by {@code ObjectInputStream}.
2018      * @throws ClassNotFoundException
2019      *     thrown by {@code ObjectInputStream}.
2020      * @serialData
2021      *     The {@code String} is the name of one of
2022      *     <code>CS_<var>*</var></code> constants defined in the
2023      *     {@link ColorSpace} class if the profile object is a profile
2024      *     for a predefined color space (for example
2025      *     {@code "CS_sRGB"}).  The string is {@code null}
2026      *     otherwise.
2027      *     <p>
2028      *     The {@code byte[]} array is the profile data for the
2029      *     profile.  It will usually be {@code null} for the
2030      *     predefined profiles.
2031      *     <p>
2032      *     If the string is recognized as a constant name for
2033      *     predefined color space the object will be resolved into
2034      *     profile obtained with
2035      *     <code>getInstance(int&nbsp;cspace)</code> and the profile
2036      *     data are ignored.  Otherwise the object will be resolved
2037      *     into profile obtained with

2038      *     <code>getInstance(byte[]&nbsp;data)</code>.
2039      * @see #readResolve()
2040      * @see #getInstance(int)
2041      * @see #getInstance(byte[])
2042      */
2043     private void readObject(ObjectInputStream s)
2044       throws IOException, ClassNotFoundException
2045     {
2046         s.defaultReadObject();
2047 
2048         String csName = (String)s.readObject();
2049         byte[] data = (byte[])s.readObject();
2050 
2051         int cspace = 0;         // ColorSpace.CS_* constant if known
2052         boolean isKnownPredefinedCS = false;
2053         if (csName != null) {
2054             isKnownPredefinedCS = true;
2055             if (csName.equals("CS_sRGB")) {
2056                 cspace = ColorSpace.CS_sRGB;
2057             } else if (csName.equals("CS_CIEXYZ")) {
2058                 cspace = ColorSpace.CS_CIEXYZ;
2059             } else if (csName.equals("CS_PYCC")) {
2060                 cspace = ColorSpace.CS_PYCC;
2061             } else if (csName.equals("CS_GRAY")) {
2062                 cspace = ColorSpace.CS_GRAY;
2063             } else if (csName.equals("CS_LINEAR_RGB")) {
2064                 cspace = ColorSpace.CS_LINEAR_RGB;
2065             } else {
2066                 isKnownPredefinedCS = false;
2067             }
2068         }
2069 
2070         if (isKnownPredefinedCS) {
2071             resolvedDeserializedProfile = getInstance(cspace);
2072         } else {
2073             resolvedDeserializedProfile = getInstance(data);
2074         }
2075     }
2076 
2077     /**
2078      * Resolves instances being deserialized into instances registered
2079      * with CMM.
2080      * @return ICC_Profile object for profile registered with CMM.
2081      * @throws ObjectStreamException
2082      *     never thrown, but mandated by the serialization spec.
2083      * @since 1.3
2084      */
2085     protected Object readResolve() throws ObjectStreamException {
2086         return resolvedDeserializedProfile;
2087     }
2088 }


   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 


 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     /**


 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     /**


 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     /**


 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 


 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         if (cmmProfile != null) {
 764             CMSManager.getModule().freeProfile(cmmProfile);
 765         } else if (profileActivator != null) {
 766             ProfileDeferralMgr.unregisterDeferral(profileActivator);
 767         }
 768     }
 769 

 770     /**
 771      * Constructs an {@code ICC_Profile} object corresponding to the data in a
 772      * byte array. Throws an {@code IllegalArgumentException} if the data does
 773      * not correspond to a valid ICC Profile.
 774      *
 775      * @param  data the specified ICC Profile data
 776      * @return an {@code ICC_Profile} object corresponding to the data in the
 777      *         specified {@code data} array
 778      */
 779     public static ICC_Profile getInstance(byte[] data) {
 780     ICC_Profile thisProfile;
 781 
 782         Profile p = null;
 783 
 784         if (ProfileDeferralMgr.deferring) {
 785             ProfileDeferralMgr.activateProfiles();
 786         }
 787 
 788         ProfileDataVerifier.verify(data);
 789 
 790         try {
 791             p = CMSManager.getModule().loadProfile(data);
 792         } catch (CMMException c) {
 793             throw new IllegalArgumentException("Invalid ICC Profile Data");
 794         }
 795 
 796         try {
 797             if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&


 801             }
 802             else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
 803                 (getData (p, icSigMediaWhitePointTag) != null) &&
 804                 (getData (p, icSigRedColorantTag) != null) &&
 805                 (getData (p, icSigGreenColorantTag) != null) &&
 806                 (getData (p, icSigBlueColorantTag) != null) &&
 807                 (getData (p, icSigRedTRCTag) != null) &&
 808                 (getData (p, icSigGreenTRCTag) != null) &&
 809                 (getData (p, icSigBlueTRCTag) != null)) {
 810                 thisProfile = new ICC_ProfileRGB (p);
 811             }
 812             else {
 813                 thisProfile = new ICC_Profile (p);
 814             }
 815         } catch (CMMException c) {
 816             thisProfile = new ICC_Profile (p);
 817         }
 818         return thisProfile;
 819     }
 820 


 821     /**
 822      * Constructs an {@code ICC_Profile} corresponding to one of the specific
 823      * color spaces defined by the {@code ColorSpace} class (for example
 824      * {@code CS_sRGB}). Throws an {@code IllegalArgumentException} if cspace is
 825      * not one of the defined color spaces.
 826      *
 827      * @param  cspace the type of color space to create a profile for. The
 828      *         specified type is one of the color space constants defined in the
 829      *         {@code ColorSpace} class.
 830      * @return an {@code ICC_Profile} object corresponding to the specified
 831      *         {@code ColorSpace} type
 832      * @throws IllegalArgumentException If {@code cspace} is not one of the
 833      *         predefined color space types

 834      */
 835     public static ICC_Profile getInstance (int cspace) {
 836         ICC_Profile thisProfile = null;
 837         String fileName;
 838 
 839         switch (cspace) {
 840         case ColorSpace.CS_sRGB:
 841             synchronized(ICC_Profile.class) {
 842                 if (sRGBprofile == null) {
 843                     /*
 844                      * Deferral is only used for standard profiles.
 845                      * Enabling the appropriate access privileges is handled
 846                      * at a lower level.
 847                      */
 848                     ProfileDeferralInfo pInfo =
 849                         new ProfileDeferralInfo("sRGB.pf",
 850                                                 ColorSpace.TYPE_RGB, 3,
 851                                                 CLASS_DISPLAY);
 852                     sRGBprofile = getDeferredInstance(pInfo);
 853                 }


 908             synchronized(ICC_Profile.class) {
 909                 if (LINEAR_RGBprofile == null) {
 910                     ProfileDeferralInfo pInfo =
 911                         new ProfileDeferralInfo("LINEAR_RGB.pf",
 912                                                 ColorSpace.TYPE_RGB, 3,
 913                                                 CLASS_DISPLAY);
 914                     LINEAR_RGBprofile = getDeferredInstance(pInfo);
 915                 }
 916                 thisProfile = LINEAR_RGBprofile;
 917             }
 918 
 919             break;
 920 
 921         default:
 922             throw new IllegalArgumentException("Unknown color space");
 923         }
 924 
 925         return thisProfile;
 926     }
 927 
 928     /**
 929      * This method asserts system privileges, so is used only for the standard
 930      * profiles.
 931      */
 932     private static ICC_Profile getStandardProfile(final String name) {

 933         return AccessController.doPrivileged(
 934                 new PrivilegedAction<ICC_Profile>() {
 935                     public ICC_Profile run() {
 936                         ICC_Profile p = null;
 937                         try {
 938                             p = getInstance(name);
 939                         } catch (IOException ex) {
 940                             throw new IllegalArgumentException(
 941                                     "Can't load standard profile: " + name);
 942                         }
 943                         return p;
 944                     }
 945                 });
 946     }
 947 
 948     /**
 949      * Constructs an {@code ICC_Profile} corresponding to the data in a file.
 950      * {@code fileName} may be an absolute or a relative file specification.
 951      * Relative file names are looked for in several places: first, relative to
 952      * any directories specified by the {@code java.iccprofile.path} property;
 953      * second, relative to any directories specified by the
 954      * {@code java.class.path} property; finally, in a directory used to store
 955      * profiles always available, such as the profile for sRGB. Built-in
 956      * profiles use {@code .pf} as the file name extension for profiles, e.g.
 957      * {@code sRGB.pf}. This method throws an {@code IOException} if the
 958      * specified file cannot be opened or if an I/O error occurs while reading
 959      * the file. It throws an {@code IllegalArgumentException} if the file does
 960      * not contain valid ICC Profile data.
 961      *
 962      * @param  fileName the file that contains the data for the profile
 963      * @return an {@code ICC_Profile} object corresponding to the data in the
 964      *         specified file
 965      * @throws IOException If the specified file cannot be opened or an I/O
 966      *         error occurs while reading the file
 967      * @throws IllegalArgumentException If the file does not contain valid ICC
 968      *         Profile data
 969      * @throws SecurityException If a security manager is installed and it does
 970      *         not permit read access to the given file


 971      */
 972     public static ICC_Profile getInstance(String fileName) throws IOException {
 973         ICC_Profile thisProfile;
 974         InputStream is = null;
 975 
 976 
 977         File f = getProfileFile(fileName);
 978         if (f != null) {
 979             is = new FileInputStream(f);
 980         } else {
 981             is = getStandardProfileInputStream(fileName);
 982         }
 983         if (is == null) {
 984             throw new IOException("Cannot open file " + fileName);
 985         }
 986 
 987         thisProfile = getInstance(is);
 988 
 989         is.close();    /* close the file */
 990 
 991         return thisProfile;
 992     }
 993 

 994     /**
 995      * Constructs an {@code ICC_Profile} corresponding to the data in an
 996      * {@code InputStream}. This method throws an
 997      * {@code IllegalArgumentException} if the stream does not contain valid ICC
 998      * Profile data. It throws an {@code IOException} if an I/O error occurs
 999      * while reading the stream.
1000      *
1001      * @param  s the input stream from which to read the profile data
1002      * @return an {@code ICC_Profile} object corresponding to the data in the
1003      *         specified {@code InputStream}
1004      * @throws IOException If an I/O error occurs while reading the stream
1005      * @throws IllegalArgumentException If the stream does not contain valid ICC
1006      *         Profile data

1007      */
1008     public static ICC_Profile getInstance(InputStream s) throws IOException {
1009     byte[] profileData;
1010 
1011         if (s instanceof ProfileDeferralInfo) {
1012             /* hack to detect profiles whose loading can be deferred */
1013             return getDeferredInstance((ProfileDeferralInfo) s);
1014         }
1015 
1016         if ((profileData = getProfileDataFromStream(s)) == null) {
1017             throw new IllegalArgumentException("Invalid ICC Profile Data");
1018         }
1019 
1020         return getInstance(profileData);
1021     }
1022 
1023 
1024     static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1025     byte[] profileData;
1026     int profileSize;


1043         }
1044         profileSize = ((header[0] & 0xff) << 24) |
1045                       ((header[1] & 0xff) << 16) |
1046                       ((header[2] & 0xff) <<  8) |
1047                        (header[3] & 0xff);
1048         profileData = new byte[profileSize];
1049         System.arraycopy(header, 0, profileData, 0, 128);
1050         bytestoread = profileSize - 128;
1051         bytesread = 128;
1052         while (bytestoread != 0) {
1053             if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1054                 return null;
1055             }
1056             bytesread += n;
1057             bytestoread -= n;
1058         }
1059 
1060         return profileData;
1061     }
1062 

1063     /**
1064      * Constructs an {@code ICC_Profile} for which the actual loading of the
1065      * profile data from a file and the initialization of the CMM should be
1066      * deferred as long as possible. Deferral is only used for standard
1067      * profiles. If deferring is disabled, then getStandardProfile() ensures
1068      * that all of the appropriate access privileges are granted when loading
1069      * this profile. If deferring is enabled, then the deferred activation code
1070      * will take care of access privileges.
1071      *

1072      * @see #activateDeferredProfile()
1073      */
1074     static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1075         if (!ProfileDeferralMgr.deferring) {
1076             return getStandardProfile(pdi.filename);
1077         }
1078         if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1079             return new ICC_ProfileRGB(pdi);
1080         } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1081             return new ICC_ProfileGray(pdi);
1082         } else {
1083             return new ICC_Profile(pdi);
1084         }
1085     }
1086 
1087 
1088     void activateDeferredProfile() throws ProfileDataException {
1089         byte[] profileData;
1090         final String fileName = deferralInfo.filename;
1091 


1102         catch (IOException e) {
1103             ProfileDataException pde = new
1104                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1105             pde.initCause(e);
1106             throw pde;
1107         }
1108         if (profileData == null) {
1109             throw new ProfileDataException("Invalid ICC Profile Data" +
1110                 fileName);
1111         }
1112         try {
1113             cmmProfile = CMSManager.getModule().loadProfile(profileData);
1114         } catch (CMMException c) {
1115             ProfileDataException pde = new
1116                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1117             pde.initCause(c);
1118             throw pde;
1119         }
1120     }
1121 

1122     /**
1123      * Returns profile major version.
1124      *
1125      * @return the major version of the profile
1126      */
1127     public int getMajorVersion() {
1128     byte[] theHeader;
1129 
1130         theHeader = getData(icSigHead); /* getData will activate deferred
1131                                            profiles if necessary */
1132 
1133         return (int) theHeader[8];
1134     }
1135 
1136     /**
1137      * Returns profile minor version.
1138      *
1139      * @return the minor version of the profile
1140      */
1141     public int getMinorVersion() {
1142     byte[] theHeader;
1143 
1144         theHeader = getData(icSigHead); /* getData will activate deferred
1145                                            profiles if necessary */
1146 
1147         return (int) theHeader[9];
1148     }
1149 
1150     /**
1151      * Returns the profile class.
1152      *
1153      * @return one of the predefined profile class constants
1154      */
1155     public int getProfileClass() {
1156     byte[] theHeader;
1157     int theClassSig, theClass;
1158 
1159         if (deferralInfo != null) {
1160             return deferralInfo.profileClass; /* Need to have this info for
1161                                                  ICC_ColorSpace without
1162                                                  causing a deferred profile
1163                                                  to be loaded */
1164         }
1165 
1166         theHeader = getData(icSigHead);
1167 
1168         theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1169 
1170         switch (theClassSig) {
1171         case icSigInputClass:
1172             theClass = CLASS_INPUT;
1173             break;


1188             theClass = CLASS_COLORSPACECONVERSION;
1189             break;
1190 
1191         case icSigAbstractClass:
1192             theClass = CLASS_ABSTRACT;
1193             break;
1194 
1195         case icSigNamedColorClass:
1196             theClass = CLASS_NAMEDCOLOR;
1197             break;
1198 
1199         default:
1200             throw new IllegalArgumentException("Unknown profile class");
1201         }
1202 
1203         return theClass;
1204     }
1205 
1206     /**
1207      * Returns the color space type. Returns one of the color space type
1208      * constants defined by the {@code ColorSpace} class. This is the "input"
1209      * color space of the profile. The type defines the number of components of
1210      * the color space and the interpretation, e.g. {@code TYPE_RGB} identifies
1211      * a color space with three components - red, green, and blue. It does not
1212      * define the particular color characteristics of the space, e.g. the
1213      * chromaticities of the primaries.
1214      *
1215      * @return one of the color space type constants defined in the
1216      *         {@code ColorSpace} class
1217      */
1218     public int getColorSpaceType() {
1219         if (deferralInfo != null) {
1220             return deferralInfo.colorSpaceType; /* Need to have this info for
1221                                                    ICC_ColorSpace without
1222                                                    causing a deferred profile
1223                                                    to be loaded */
1224         }
1225         return    getColorSpaceType(cmmProfile);
1226     }
1227 
1228     static int getColorSpaceType(Profile p) {
1229     byte[] theHeader;
1230     int theColorSpaceSig, theColorSpace;
1231 
1232         theHeader = getData(p, icSigHead);
1233         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1234         theColorSpace = iccCStoJCS (theColorSpaceSig);
1235         return theColorSpace;
1236     }
1237 
1238     /**
1239      * Returns the color space type of the Profile Connection Space (PCS).
1240      * Returns one of the color space type constants defined by the ColorSpace
1241      * class. This is the "output" color space of the profile. For an input,
1242      * display, or output profile useful for tagging colors or images, this will
1243      * be either {@code TYPE_XYZ} or {@code TYPE_Lab} and should be interpreted
1244      * as the corresponding specific color space defined in the ICC
1245      * specification. For a device link profile, this could be any of the color
1246      * space type constants.
1247      *
1248      * @return one of the color space type constants defined in the
1249      *         {@code ColorSpace} class
1250      */
1251     public int getPCSType() {
1252         if (ProfileDeferralMgr.deferring) {
1253             ProfileDeferralMgr.activateProfiles();
1254         }
1255         return getPCSType(cmmProfile);
1256     }
1257 
1258 
1259     static int getPCSType(Profile p) {
1260     byte[] theHeader;
1261     int thePCSSig, thePCS;
1262 
1263         theHeader = getData(p, icSigHead);
1264         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1265         thePCS = iccCStoJCS(thePCSSig);
1266         return thePCS;
1267     }
1268 

1269     /**
1270      * Write this {@code ICC_Profile} to a file.


1271      *
1272      * @param  fileName the file to write the profile data to
1273      * @throws IOException If the file cannot be opened for writing or an I/O
1274      *         error occurs while writing to the file
1275      */
1276     public void write(String fileName) throws IOException {
1277     FileOutputStream outputFile;
1278     byte[] profileData;
1279 
1280         profileData = getData(); /* this will activate deferred
1281                                     profiles if necessary */
1282         outputFile = new FileOutputStream(fileName);
1283         outputFile.write(profileData);
1284         outputFile.close ();
1285     }
1286 

1287     /**
1288      * Write this {@code ICC_Profile} to an {@code OutputStream}.
1289      *
1290      * @param  s the stream to write the profile data to
1291      * @throws IOException If an I/O error occurs while writing to the stream


1292      */
1293     public void write(OutputStream s) throws IOException {
1294     byte[] profileData;
1295 
1296         profileData = getData(); /* this will activate deferred
1297                                     profiles if necessary */
1298         s.write(profileData);
1299     }
1300 

1301     /**
1302      * Returns a byte array corresponding to the data of this
1303      * {@code ICC_Profile}.
1304      *
1305      * @return a byte array that contains the profile data
1306      * @see #setData(int, byte[])
1307      */
1308     public byte[] getData() {
1309     int profileSize;
1310     byte[] profileData;
1311 
1312         if (ProfileDeferralMgr.deferring) {
1313             ProfileDeferralMgr.activateProfiles();
1314         }
1315 
1316         PCMM mdl = CMSManager.getModule();
1317 
1318         /* get the number of bytes needed for this profile */
1319         profileSize = mdl.getProfileSize(cmmProfile);
1320 
1321         profileData = new byte [profileSize];
1322 
1323         /* get the data for the profile */
1324         mdl.getProfileData(cmmProfile, profileData);
1325 
1326         return profileData;
1327     }
1328 

1329     /**
1330      * Returns a particular tagged data element from the profile as a byte
1331      * array. Elements are identified by signatures as defined in the ICC
1332      * specification. The signature icSigHead can be used to get the header.
1333      * This method is useful for advanced applets or applications which need to
1334      * access profile data directly.




1335      *
1336      * @param  tagSignature the ICC tag signature for the data element you want
1337      *         to get
1338      * @return a byte array that contains the tagged data element. Returns
1339      *         {@code null} if the specified tag doesn't exist.
1340      * @see #setData(int, byte[])
1341      */
1342     public byte[] getData(int tagSignature) {
1343 
1344         if (ProfileDeferralMgr.deferring) {
1345             ProfileDeferralMgr.activateProfiles();
1346         }
1347 
1348         return getData(cmmProfile, tagSignature);
1349     }
1350 
1351 
1352     static byte[] getData(Profile p, int tagSignature) {
1353     int tagSize;
1354     byte[] tagData;
1355 
1356         try {
1357             PCMM mdl = CMSManager.getModule();
1358 
1359             /* get the number of bytes needed for this tag */
1360             tagSize = mdl.getTagSize(p, tagSignature);
1361 
1362             tagData = new byte[tagSize]; /* get an array for the tag */
1363 
1364             /* get the tag's data */
1365             mdl.getTagData(p, tagSignature, tagData);
1366         } catch(CMMException c) {
1367             tagData = null;
1368         }
1369 
1370         return tagData;
1371     }
1372 
1373     /**
1374      * Sets a particular tagged data element in the profile from a byte array.
1375      * The array should contain data in a format, corresponded to the
1376      * {@code tagSignature} as defined in the ICC specification, section 10.
1377      * This method is useful for advanced applets or applications which need to
1378      * access profile data directly.
1379      *
1380      * @param  tagSignature the ICC tag signature for the data element you want
1381      *         to set
1382      * @param  tagData the data to set for the specified tag signature
1383      * @throws IllegalArgumentException if {@code tagSignature} is not a
1384      *         signature as defined in the ICC specification.
1385      * @throws IllegalArgumentException if a content of the {@code tagData}
1386      *         array can not be interpreted as valid tag data, corresponding to
1387      *         the {@code tagSignature}
1388      * @see #getData
1389      */
1390     public void setData(int tagSignature, byte[] tagData) {
1391 
1392         if (ProfileDeferralMgr.deferring) {
1393             ProfileDeferralMgr.activateProfiles();
1394         }
1395 
1396         CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1397     }
1398 
1399     /**
1400      * Sets the rendering intent of the profile. This is used to select the
1401      * proper transform from a profile that has multiple transforms.

1402      */
1403     void setRenderingIntent(int renderingIntent) {
1404         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1405                                                  profiles if necessary */
1406         intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1407                                                  /* set the rendering intent */
1408         setData (icSigHead, theHeader);
1409     }
1410 

1411     /**
1412      * Returns the rendering intent of the profile. This is used to select the
1413      * proper transform from a profile that has multiple transforms. It is
1414      * typically set in a source profile to select a transform from an output
1415      * profile.
1416      */
1417     int getRenderingIntent() {
1418         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1419                                                  profiles if necessary */
1420 
1421         int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1422                                                  /* set the rendering intent */
1423 
1424         /* According to ICC spec, only the least-significant 16 bits shall be
1425          * used to encode the rendering intent. The most significant 16 bits
1426          * shall be set to zero. Thus, we are ignoring two most significant
1427          * bytes here.
1428          *
1429          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1430          */
1431         return (0xffff & renderingIntent);
1432     }
1433 

1434     /**
1435      * Returns the number of color components in the "input" color space of this
1436      * profile. For example if the color space type of this profile is
1437      * {@code TYPE_RGB}, then this method will return 3.



1438      *
1439      * @return the number of color components in the profile's input color space
1440      * @throws ProfileDataException if color space is in the profile is invalid
1441      */
1442     public int getNumComponents() {
1443     byte[]    theHeader;
1444     int    theColorSpaceSig, theNumComponents;
1445 
1446         if (deferralInfo != null) {
1447             return deferralInfo.numComponents; /* Need to have this info for
1448                                                   ICC_ColorSpace without
1449                                                   causing a deferred profile
1450                                                   to be loaded */
1451         }
1452         theHeader = getData(icSigHead);
1453 
1454         theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1455 
1456         switch (theColorSpaceSig) {
1457         case icSigGrayData:
1458             theNumComponents = 1;
1459             break;
1460 


1514 
1515         case icSigSpaceDCLR:
1516             theNumComponents = 13;
1517             break;
1518 
1519         case icSigSpaceECLR:
1520             theNumComponents = 14;
1521             break;
1522 
1523         case icSigSpaceFCLR:
1524             theNumComponents = 15;
1525             break;
1526 
1527         default:
1528             throw new ProfileDataException ("invalid ICC color space");
1529         }
1530 
1531         return theNumComponents;
1532     }
1533 

1534     /**
1535      * Returns a float array of length 3 containing the X, Y, and Z components
1536      * of the mediaWhitePointTag in the ICC profile.
1537      */
1538     float[] getMediaWhitePoint() {
1539         return getXYZTag(icSigMediaWhitePointTag);
1540                                            /* get the media white point tag */
1541     }
1542 

1543     /**
1544      * Returns a float array of length 3 containing the X, Y, and Z components
1545      * encoded in an XYZType tag.
1546      */
1547     float[] getXYZTag(int theTagSignature) {
1548     byte[] theData;
1549     float[] theXYZNumber;
1550     int i1, i2, theS15Fixed16;
1551 
1552         theData = getData(theTagSignature); /* get the tag data */
1553                                             /* getData will activate deferred
1554                                                profiles if necessary */
1555 
1556         theXYZNumber = new float [3];        /* array to return */
1557 
1558         /* convert s15Fixed16Number to float */
1559         for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1560             theS15Fixed16 = intFromBigEndian(theData, i2);
1561             theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1562         }
1563         return theXYZNumber;
1564     }
1565 

1566     /**
1567      * Returns a gamma value representing a tone reproduction curve (TRC). If
1568      * the profile represents the TRC as a table rather than a single gamma
1569      * value, then an exception is thrown. In this case the actual table can be
1570      * obtained via {@link #getTRC}. {@code theTagSignature} should be one of
1571      * {@code icSigGrayTRCTag}, {@code icSigRedTRCTag},
1572      * {@code icSigGreenTRCTag}, or {@code icSigBlueTRCTag}.
1573      *
1574      * @return the gamma value as a float
1575      * @throws ProfileDataException if the profile does not specify the TRC as a
1576      *         single gamma value
1577      */
1578     float getGamma(int theTagSignature) {
1579     byte[] theTRCData;
1580     float theGamma;
1581     int theU8Fixed8;
1582 
1583         theTRCData = getData(theTagSignature); /* get the TRC */
1584                                                /* getData will activate deferred
1585                                                   profiles if necessary */
1586 
1587         if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1588             throw new ProfileDataException ("TRC is not a gamma");
1589         }
1590 
1591         /* convert u8Fixed8 to float */
1592         theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1593 
1594         theGamma = ((float) theU8Fixed8) / 256.0f;
1595 
1596         return theGamma;
1597     }
1598 

1599     /**
1600      * Returns the TRC as an array of shorts. If the profile has specified the
1601      * TRC as linear (gamma = 1.0) or as a simple gamma value, this method
1602      * throws an exception, and the {@link #getGamma} method should be used to
1603      * get the gamma value. Otherwise the short array returned here represents a
1604      * lookup table where the input Gray value is conceptually in the range
1605      * [0.0, 1.0]. Value 0.0 maps to array index 0 and value 1.0 maps to array
1606      * index length-1. Interpolation may be used to generate output values for
1607      * input values which do not map exactly to an index in the array. Output
1608      * values also map linearly to the range [0.0, 1.0]. Value 0.0 is
1609      * represented by an array value of 0x0000 and value 1.0 by 0xFFFF, i.e. the
1610      * values are really unsigned short values, although they are returned in a
1611      * short array. {@code theTagSignature} should be one of
1612      * {@code icSigGrayTRCTag}, {@code icSigRedTRCTag},
1613      * {@code icSigGreenTRCTag}, or {@code icSigBlueTRCTag}.
1614      *
1615      * @return a short array representing the TRC
1616      * @throws ProfileDataException if the profile does not specify the TRC as a
1617      *         table
1618      */
1619     short[] getTRC(int theTagSignature) {
1620     byte[] theTRCData;
1621     short[] theTRC;
1622     int i1, i2, nElements, theU8Fixed8;
1623 
1624         theTRCData = getData(theTagSignature); /* get the TRC */
1625                                                /* getData will activate deferred
1626                                                   profiles if necessary */
1627 
1628         nElements = intFromBigEndian(theTRCData, icCurveCount);
1629 
1630         if (nElements == 1) {
1631             throw new ProfileDataException("TRC is not a table");
1632         }
1633 
1634         /* make the short array */
1635         theTRC = new short [nElements];
1636 
1637         for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1638             theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1639         }
1640 
1641         return theTRC;
1642     }
1643 
1644     /**
1645      * Convert an ICC color space signature into a Java color space type.
1646      */
1647     static int iccCStoJCS(int theColorSpaceSig) {
1648     int theColorSpace;
1649 
1650         switch (theColorSpaceSig) {
1651         case icSigXYZData:
1652             theColorSpace = ColorSpace.TYPE_XYZ;
1653             break;
1654 
1655         case icSigLabData:
1656             theColorSpace = ColorSpace.TYPE_Lab;
1657             break;
1658 
1659         case icSigLuvData:
1660             theColorSpace = ColorSpace.TYPE_Luv;
1661             break;
1662 
1663         case icSigYCbCrData:
1664             theColorSpace = ColorSpace.TYPE_YCbCr;
1665             break;
1666 


1734 
1735         case icSigSpaceCCLR:
1736             theColorSpace = ColorSpace.TYPE_CCLR;
1737             break;
1738 
1739         case icSigSpaceDCLR:
1740             theColorSpace = ColorSpace.TYPE_DCLR;
1741             break;
1742 
1743         case icSigSpaceECLR:
1744             theColorSpace = ColorSpace.TYPE_ECLR;
1745             break;
1746 
1747         case icSigSpaceFCLR:
1748             theColorSpace = ColorSpace.TYPE_FCLR;
1749             break;
1750 
1751         default:
1752             throw new IllegalArgumentException ("Unknown color space");
1753         }

1754         return theColorSpace;
1755     }
1756 
1757 
1758     static int intFromBigEndian(byte[] array, int index) {
1759         return (((array[index]   & 0xff) << 24) |
1760                 ((array[index+1] & 0xff) << 16) |
1761                 ((array[index+2] & 0xff) <<  8) |
1762                  (array[index+3] & 0xff));
1763     }
1764 
1765 
1766     static void intToBigEndian(int value, byte[] array, int index) {
1767             array[index]   = (byte) (value >> 24);
1768             array[index+1] = (byte) (value >> 16);
1769             array[index+2] = (byte) (value >>  8);
1770             array[index+3] = (byte) (value);
1771     }
1772 
1773 
1774     static short shortFromBigEndian(byte[] array, int index) {
1775         return (short) (((array[index]   & 0xff) << 8) |
1776                          (array[index+1] & 0xff));
1777     }
1778 
1779 
1780     static void shortToBigEndian(short value, byte[] array, int index) {
1781             array[index]   = (byte) (value >> 8);
1782             array[index+1] = (byte) (value);
1783     }
1784 
1785     /**
1786      * {@code fileName} may be an absolute or a relative file specification.
1787      * Relative file names are looked for in several places: first, relative to
1788      * any directories specified by the {@code java.iccprofile.path} property;
1789      * second, relative to any directories specified by the
1790      * {@code java.class.path}. The built-in profile files are now loaded as
1791      * resources, since they may not be individual disk files, and so this
1792      * method will not find these and on a {@code null} return, the caller needs
1793      * to try as resources. Built-in profiles use {@code .pf} as the file name
1794      * extension for profiles, e.g. {@code sRGB.pf}.

1795      */
1796     private static File getProfileFile(String fileName) {
1797         String path, dir, fullPath;
1798 
1799         File f = new File(fileName); /* try absolute file name */
1800         if (f.isAbsolute()) {
1801             /* Rest of code has little sense for an absolute pathname,
1802                so return here. */
1803             return f.isFile() ? f : null;
1804         }
1805         if ((!f.isFile()) &&
1806                 ((path = System.getProperty("java.iccprofile.path")) != null)){
1807                                     /* try relative to java.iccprofile.path */
1808                 StringTokenizer st =
1809                     new StringTokenizer(path, File.pathSeparator);
1810                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1811                     dir = st.nextToken();
1812                         fullPath = dir + File.separatorChar + fileName;
1813                     f = new File(fullPath);
1814                     if (!isChildOf(f, dir)) {


1819 
1820         if (((f == null) || (!f.isFile())) &&
1821                 ((path = System.getProperty("java.class.path")) != null)) {
1822                                     /* try relative to java.class.path */
1823                 StringTokenizer st =
1824                     new StringTokenizer(path, File.pathSeparator);
1825                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1826                     dir = st.nextToken();
1827                         fullPath = dir + File.separatorChar + fileName;
1828                     f = new File(fullPath);
1829                 }
1830         }
1831 
1832         if (f != null && !f.isFile()) {
1833             f = null;
1834         }
1835         return f;
1836     }
1837 
1838     /**
1839      * Returns a stream corresponding to a built-in profile specified by
1840      * fileName. If there is no built-in profile with such name, then the method
1841      * returns {@code null}.

1842      */
1843     private static InputStream getStandardProfileInputStream(String fileName) {
1844         return AccessController.doPrivileged(
1845             new PrivilegedAction<InputStream>() {
1846                 public InputStream run () {
1847                     return
1848                         PCMM.class.getResourceAsStream("profiles/" + fileName);
1849                 }
1850             }, null, new FilePermission("<<ALL FILES>>", "read"),
1851                      new RuntimePermission("accessSystemModules"));
1852     }
1853 
1854     /**
1855      * Checks whether given file resides inside give directory.
1856      */
1857     private static boolean isChildOf(File f, String dirName) {
1858         try {
1859             File dir = new File(dirName);
1860             String canonicalDirName = dir.getCanonicalPath();
1861             if (!canonicalDirName.endsWith(File.separator)) {


1865             return canonicalFileName.startsWith(canonicalDirName);
1866         } catch (IOException e) {
1867             /* we do not expect the IOException here, because invocation
1868              * of this function is always preceded by isFile() call.
1869              */
1870             return false;
1871         }
1872     }
1873 
1874     /**
1875      * Checks whether built-in profile specified by fileName exists.
1876      */
1877     private static boolean standardProfileExists(final String fileName) {
1878         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1879                 public Boolean run() {
1880                     return PCMM.class.getResource("profiles/"+fileName) != null;
1881                 }
1882             });
1883     }
1884 

1885     /*
1886      * Serialization support.
1887      *
1888      * Directly deserialized profiles are useless since they are not registered
1889      * with CMM. We don't allow constructor to be called directly and instead
1890      * have clients to call one of getInstance factory methods that will
1891      * register the profile with CMM. For deserialization we implement
1892      * readResolve method that will resolve the bogus deserialized profile
1893      * object with one obtained with getInstance as well.
1894      *
1895      * There are two primary factory methods for construction of ICC profiles:
1896      * getInstance(int cspace) and getInstance(byte[] data). This implementation
1897      * of ICC_Profile uses the former to return a cached singleton profile
1898      * object, other implementations will likely use this technique too. To
1899      * preserve the singleton pattern across serialization we serialize cached
1900      * singleton profiles in such a way that deserializing VM could call
1901      * getInstance(int cspace) method that will resolve deserialized object into
1902      * the corresponding singleton as well.
1903      *
1904      * Since the singletons are private to ICC_Profile the readResolve method
1905      * have to be `protected' instead of `private' so that singletons that are
1906      * instances of subclasses of ICC_Profile could be correctly deserialized.



1907      */
1908 

1909     /**
1910      * Version of the format of additional serialized data in the stream.
1911      * Version&nbsp;{@code 1} corresponds to Java&nbsp;2 Platform,&nbsp;v1.3.
1912      *

1913      * @serial
1914      * @since 1.3
1915      */
1916     private int iccProfileSerializedDataVersion = 1;
1917 

1918     /**
1919      * Writes default serializable fields to the stream. Writes a string and an
1920      * array of bytes to the stream as additional data.
1921      *
1922      * @param  s stream used for serialization
1923      * @throws IOException thrown by {@code ObjectInputStream}
1924      * @serialData the {@code String} is the name of one of


1925      *         <code>CS_<var>*</var></code> constants defined in the
1926      *         {@link ColorSpace} class if the profile object is a profile for a
1927      *         predefined color space (for example {@code "CS_sRGB"}). The
1928      *         string is {@code null} otherwise.

1929      *         <p>
1930      *         The {@code byte[]} array is the profile data for the profile. For
1931      *         predefined color spaces {@code null} is written instead of the
1932      *         profile data. If in the future versions of Java API new
1933      *         predefined color spaces will be added, future versions of this
1934      *         class may choose to write for new predefined color spaces not
1935      *         only the color space name, but the profile data as well so that
1936      *         older versions could still deserialize the object.

1937      */
1938     private void writeObject(ObjectOutputStream s)
1939       throws IOException
1940     {
1941         s.defaultWriteObject();
1942 
1943         String csName = null;
1944         if (this == sRGBprofile) {
1945             csName = "CS_sRGB";
1946         } else if (this == XYZprofile) {
1947             csName = "CS_CIEXYZ";
1948         } else if (this == PYCCprofile) {
1949             csName = "CS_PYCC";
1950         } else if (this == GRAYprofile) {
1951             csName = "CS_GRAY";
1952         } else if (this == LINEAR_RGBprofile) {
1953             csName = "CS_LINEAR_RGB";
1954         }
1955 
1956         // Future versions may choose to write profile data for new
1957         // predefined color spaces as well, if any will be introduced,
1958         // so that old versions that don't recognize the new CS name
1959         // may fall back to constructing profile from the data.
1960         byte[] data = null;
1961         if (csName == null) {
1962             // getData will activate deferred profile if necessary
1963             data = getData();
1964         }
1965 
1966         s.writeObject(csName);
1967         s.writeObject(data);
1968     }
1969 
1970     // Temporary storage used by readObject to store resolved profile
1971     // (obtained with getInstance) for readResolve to return.
1972     private transient ICC_Profile resolvedDeserializedProfile;
1973 
1974     /**
1975      * Reads default serializable fields from the stream. Reads from the stream
1976      * a string and an array of bytes as additional data.
1977      *
1978      * @param  s stream used for deserialization
1979      * @throws IOException thrown by {@code ObjectInputStream}
1980      * @throws ClassNotFoundException thrown by {@code
1981      *         ObjectInputStream}
1982      * @serialData the {@code String} is the name of one of


1983      *         <code>CS_<var>*</var></code> constants defined in the
1984      *         {@link ColorSpace} class if the profile object is a profile for a
1985      *         predefined color space (for example {@code "CS_sRGB"}). The
1986      *         string is {@code null} otherwise.

1987      *         <p>
1988      *         The {@code byte[]} array is the profile data for the profile. It
1989      *         will usually be {@code null} for the predefined profiles.

1990      *         <p>
1991      *         If the string is recognized as a constant name for predefined
1992      *         color space the object will be resolved into profile obtained
1993      *         with
1994      *         <code>getInstance(int&nbsp;cspace)</code> and the profile data
1995      *         are
1996      *         ignored. Otherwise the object will be resolved into profile
1997      *         obtained with
1998      *         <code>getInstance(byte[]&nbsp;data)</code>.
1999      * @see #readResolve()
2000      * @see #getInstance(int)
2001      * @see #getInstance(byte[])
2002      */
2003     private void readObject(ObjectInputStream s)
2004       throws IOException, ClassNotFoundException
2005     {
2006         s.defaultReadObject();
2007 
2008         String csName = (String)s.readObject();
2009         byte[] data = (byte[])s.readObject();
2010 
2011         int cspace = 0;         // ColorSpace.CS_* constant if known
2012         boolean isKnownPredefinedCS = false;
2013         if (csName != null) {
2014             isKnownPredefinedCS = true;
2015             if (csName.equals("CS_sRGB")) {
2016                 cspace = ColorSpace.CS_sRGB;
2017             } else if (csName.equals("CS_CIEXYZ")) {
2018                 cspace = ColorSpace.CS_CIEXYZ;
2019             } else if (csName.equals("CS_PYCC")) {
2020                 cspace = ColorSpace.CS_PYCC;
2021             } else if (csName.equals("CS_GRAY")) {
2022                 cspace = ColorSpace.CS_GRAY;
2023             } else if (csName.equals("CS_LINEAR_RGB")) {
2024                 cspace = ColorSpace.CS_LINEAR_RGB;
2025             } else {
2026                 isKnownPredefinedCS = false;
2027             }
2028         }
2029 
2030         if (isKnownPredefinedCS) {
2031             resolvedDeserializedProfile = getInstance(cspace);
2032         } else {
2033             resolvedDeserializedProfile = getInstance(data);
2034         }
2035     }
2036 
2037     /**
2038      * Resolves instances being deserialized into instances registered with CMM.
2039      *
2040      * @return ICC_Profile object for profile registered with CMM
2041      * @throws ObjectStreamException never thrown, but mandated by the
2042      *         serialization spec
2043      * @since 1.3
2044      */
2045     protected Object readResolve() throws ObjectStreamException {
2046         return resolvedDeserializedProfile;
2047     }
2048 }
< prev index next >