1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  **********************************************************************
  28  **********************************************************************
  29  **********************************************************************
  30  *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
  31  *** As  an unpublished  work pursuant to Title 17 of the United    ***
  32  *** States Code.  All rights reserved.                             ***
  33  **********************************************************************
  34  **********************************************************************
  35  **********************************************************************/
  36 
  37 package java.awt.color;
  38 
  39 import sun.java2d.cmm.ColorTransform;
  40 import sun.java2d.cmm.CMSManager;
  41 import sun.java2d.cmm.PCMM;
  42 
  43 
  44 /**
  45  *
  46  * The ICC_ColorSpace class is an implementation of the abstract
  47  * ColorSpace class.  This representation of
  48  * device independent and device dependent color spaces is based on the
  49  * International Color Consortium Specification ICC.1:2001-12, File Format for
  50  * Color Profiles (see <A href="http://www.color.org">http://www.color.org</A>).
  51  * <p>
  52  * Typically, a Color or ColorModel would be associated with an ICC
  53  * Profile which is either an input, display, or output profile (see
  54  * the ICC specification).  There are other types of ICC Profiles, e.g.
  55  * abstract profiles, device link profiles, and named color profiles,
  56  * which do not contain information appropriate for representing the color
  57  * space of a color, image, or device (see ICC_Profile).
  58  * Attempting to create an ICC_ColorSpace object from an inappropriate ICC
  59  * Profile is an error.
  60  * <p>
  61  * ICC Profiles represent transformations from the color space of
  62  * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
  63  * Profiles of interest for tagging images or colors have a
  64  * PCS which is one of the device independent
  65  * spaces (one CIEXYZ space and two CIELab spaces) defined in the
  66  * ICC Profile Format Specification.  Most profiles of interest
  67  * either have invertible transformations or explicitly specify
  68  * transformations going both directions.  Should an ICC_ColorSpace
  69  * object be used in a way requiring a conversion from PCS to
  70  * the profile's native space and there is inadequate data to
  71  * correctly perform the conversion, the ICC_ColorSpace object will
  72  * produce output in the specified type of color space (e.g. TYPE_RGB,
  73  * TYPE_CMYK, etc.), but the specific color values of the output data
  74  * will be undefined.
  75  * <p>
  76  * The details of this class are not important for simple applets,
  77  * which draw in a default color space or manipulate and display
  78  * imported images with a known color space.  At most, such applets
  79  * would need to get one of the default color spaces via
  80  * ColorSpace.getInstance().
  81  * @see ColorSpace
  82  * @see ICC_Profile
  83  */
  84 
  85 
  86 
  87 public class ICC_ColorSpace extends ColorSpace {
  88 
  89     static final long serialVersionUID = 3455889114070431483L;
  90 
  91     private ICC_Profile    thisProfile;
  92     private float[] minVal;
  93     private float[] maxVal;
  94     private float[] diffMinMax;
  95     private float[] invDiffMinMax;
  96     private boolean needScaleInit = true;
  97 
  98     // {to,from}{RGB,CIEXYZ} methods create and cache these when needed
  99     private transient ColorTransform this2srgb;
 100     private transient ColorTransform srgb2this;
 101     private transient ColorTransform this2xyz;
 102     private transient ColorTransform xyz2this;
 103 
 104 
 105     /**
 106     * Constructs a new ICC_ColorSpace from an ICC_Profile object.
 107     * @param profile the specified ICC_Profile object
 108     * @exception IllegalArgumentException if profile is inappropriate for
 109     *            representing a ColorSpace.
 110     */
 111     public ICC_ColorSpace (ICC_Profile profile) {
 112         super (profile.getColorSpaceType(), profile.getNumComponents());
 113 
 114         int profileClass = profile.getProfileClass();
 115 
 116         /* REMIND - is NAMEDCOLOR OK? */
 117         if ((profileClass != ICC_Profile.CLASS_INPUT) &&
 118             (profileClass != ICC_Profile.CLASS_DISPLAY) &&
 119             (profileClass != ICC_Profile.CLASS_OUTPUT) &&
 120             (profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) &&
 121             (profileClass != ICC_Profile.CLASS_NAMEDCOLOR) &&
 122             (profileClass != ICC_Profile.CLASS_ABSTRACT)) {
 123             throw new IllegalArgumentException("Invalid profile type");
 124         }
 125 
 126         thisProfile = profile;
 127         setMinMax();
 128     }
 129 
 130     /**
 131     * Returns the ICC_Profile for this ICC_ColorSpace.
 132     * @return the ICC_Profile for this ICC_ColorSpace.
 133     */
 134     public ICC_Profile getProfile() {
 135         return thisProfile;
 136     }
 137 
 138     /**
 139      * Transforms a color value assumed to be in this ColorSpace
 140      * into a value in the default CS_sRGB color space.
 141      * <p>
 142      * This method transforms color values using algorithms designed
 143      * to produce the best perceptual match between input and output
 144      * colors.  In order to do colorimetric conversion of color values,
 145      * you should use the <code>toCIEXYZ</code>
 146      * method of this color space to first convert from the input
 147      * color space to the CS_CIEXYZ color space, and then use the
 148      * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
 149      * convert from CS_CIEXYZ to the output color space.
 150      * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
 151      * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
 152      *
 153      * @param colorvalue a float array with length of at least the number
 154      *      of components in this ColorSpace.
 155      * @return a float array of length 3.
 156      * @throws ArrayIndexOutOfBoundsException if array length is not
 157      * at least the number of components in this ColorSpace.
 158      */
 159     public float[]    toRGB (float[] colorvalue) {
 160 
 161         if (this2srgb == null) {
 162             ColorTransform[] transformList = new ColorTransform [2];
 163             ICC_ColorSpace srgbCS =
 164                 (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
 165             PCMM mdl = CMSManager.getModule();
 166             transformList[0] = mdl.createTransform(
 167                 thisProfile, ColorTransform.Any, ColorTransform.In);
 168             transformList[1] = mdl.createTransform(
 169                 srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
 170             this2srgb = mdl.createTransform(transformList);
 171             if (needScaleInit) {
 172                 setComponentScaling();
 173             }
 174         }
 175 
 176         int nc = this.getNumComponents();
 177         short tmp[] = new short[nc];
 178         for (int i = 0; i < nc; i++) {
 179             tmp[i] = (short)
 180                 ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
 181         }
 182         tmp = this2srgb.colorConvert(tmp, null);
 183         float[] result = new float [3];
 184         for (int i = 0; i < 3; i++) {
 185             result[i] = ((float) (tmp[i] & 0xffff)) / 65535.0f;
 186         }
 187         return result;
 188     }
 189 
 190     /**
 191      * Transforms a color value assumed to be in the default CS_sRGB
 192      * color space into this ColorSpace.
 193      * <p>
 194      * This method transforms color values using algorithms designed
 195      * to produce the best perceptual match between input and output
 196      * colors.  In order to do colorimetric conversion of color values,
 197      * you should use the <code>toCIEXYZ</code>
 198      * method of the CS_sRGB color space to first convert from the input
 199      * color space to the CS_CIEXYZ color space, and then use the
 200      * <code>fromCIEXYZ</code> method of this color space to
 201      * convert from CS_CIEXYZ to the output color space.
 202      * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
 203      * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
 204      *
 205      * @param rgbvalue a float array with length of at least 3.
 206      * @return a float array with length equal to the number of
 207      *       components in this ColorSpace.
 208      * @throws ArrayIndexOutOfBoundsException if array length is not
 209      * at least 3.
 210      */
 211     public float[]    fromRGB(float[] rgbvalue) {
 212 
 213         if (srgb2this == null) {
 214             ColorTransform[] transformList = new ColorTransform [2];
 215             ICC_ColorSpace srgbCS =
 216                 (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
 217             PCMM mdl = CMSManager.getModule();
 218             transformList[0] = mdl.createTransform(
 219                 srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In);
 220             transformList[1] = mdl.createTransform(
 221                 thisProfile, ColorTransform.Any, ColorTransform.Out);
 222             srgb2this = mdl.createTransform(transformList);
 223             if (needScaleInit) {
 224                 setComponentScaling();
 225             }
 226         }
 227 
 228         short tmp[] = new short[3];
 229         for (int i = 0; i < 3; i++) {
 230             tmp[i] = (short) ((rgbvalue[i] * 65535.0f) + 0.5f);
 231         }
 232         tmp = srgb2this.colorConvert(tmp, null);
 233         int nc = this.getNumComponents();
 234         float[] result = new float [nc];
 235         for (int i = 0; i < nc; i++) {
 236             result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
 237                         diffMinMax[i] + minVal[i];
 238         }
 239         return result;
 240     }
 241 
 242 
 243     /**
 244      * Transforms a color value assumed to be in this ColorSpace
 245      * into the CS_CIEXYZ conversion color space.
 246      * <p>
 247      * This method transforms color values using relative colorimetry,
 248      * as defined by the ICC Specification.  This
 249      * means that the XYZ values returned by this method are represented
 250      * relative to the D50 white point of the CS_CIEXYZ color space.
 251      * This representation is useful in a two-step color conversion
 252      * process in which colors are transformed from an input color
 253      * space to CS_CIEXYZ and then to an output color space.  This
 254      * representation is not the same as the XYZ values that would
 255      * be measured from the given color value by a colorimeter.
 256      * A further transformation is necessary to compute the XYZ values
 257      * that would be measured using current CIE recommended practices.
 258      * The paragraphs below explain this in more detail.
 259      * <p>
 260      * The ICC standard uses a device independent color space (DICS) as the
 261      * mechanism for converting color from one device to another device.  In
 262      * this architecture, colors are converted from the source device's color
 263      * space to the ICC DICS and then from the ICC DICS to the destination
 264      * device's color space.  The ICC standard defines device profiles which
 265      * contain transforms which will convert between a device's color space
 266      * and the ICC DICS.  The overall conversion of colors from a source
 267      * device to colors of a destination device is done by connecting the
 268      * device-to-DICS transform of the profile for the source device to the
 269      * DICS-to-device transform of the profile for the destination device.
 270      * For this reason, the ICC DICS is commonly referred to as the profile
 271      * connection space (PCS).  The color space used in the methods
 272      * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
 273      * Specification.  This is also the color space represented by
 274      * ColorSpace.CS_CIEXYZ.
 275      * <p>
 276      * The XYZ values of a color are often represented as relative to some
 277      * white point, so the actual meaning of the XYZ values cannot be known
 278      * without knowing the white point of those values.  This is known as
 279      * relative colorimetry.  The PCS uses a white point of D50, so the XYZ
 280      * values of the PCS are relative to D50.  For example, white in the PCS
 281      * will have the XYZ values of D50, which is defined to be X=.9642,
 282      * Y=1.000, and Z=0.8249.  This white point is commonly used for graphic
 283      * arts applications, but others are often used in other applications.
 284      * <p>
 285      * To quantify the color characteristics of a device such as a printer
 286      * or monitor, measurements of XYZ values for particular device colors
 287      * are typically made.  For purposes of this discussion, the term
 288      * device XYZ values is used to mean the XYZ values that would be
 289      * measured from device colors using current CIE recommended practices.
 290      * <p>
 291      * Converting between device XYZ values and the PCS XYZ values returned
 292      * by this method corresponds to converting between the device's color
 293      * space, as represented by CIE colorimetric values, and the PCS.  There
 294      * are many factors involved in this process, some of which are quite
 295      * subtle.  The most important, however, is the adjustment made to account
 296      * for differences between the device's white point and the white point of
 297      * the PCS.  There are many techniques for doing this and it is the
 298      * subject of much current research and controversy.  Some commonly used
 299      * methods are XYZ scaling, the von Kries transform, and the Bradford
 300      * transform.  The proper method to use depends upon each particular
 301      * application.
 302      * <p>
 303      * The simplest method is XYZ scaling.  In this method each device XYZ
 304      * value is  converted to a PCS XYZ value by multiplying it by the ratio
 305      * of the PCS white point (D50) to the device white point.
 306      * <pre>
 307      *
 308      * Xd, Yd, Zd are the device XYZ values
 309      * Xdw, Ydw, Zdw are the device XYZ white point values
 310      * Xp, Yp, Zp are the PCS XYZ values
 311      * Xd50, Yd50, Zd50 are the PCS XYZ white point values
 312      *
 313      * Xp = Xd * (Xd50 / Xdw)
 314      * Yp = Yd * (Yd50 / Ydw)
 315      * Zp = Zd * (Zd50 / Zdw)
 316      *
 317      * </pre>
 318      * <p>
 319      * Conversion from the PCS to the device would be done by inverting these
 320      * equations:
 321      * <pre>
 322      *
 323      * Xd = Xp * (Xdw / Xd50)
 324      * Yd = Yp * (Ydw / Yd50)
 325      * Zd = Zp * (Zdw / Zd50)
 326      *
 327      * </pre>
 328      * <p>
 329      * Note that the media white point tag in an ICC profile is not the same
 330      * as the device white point.  The media white point tag is expressed in
 331      * PCS values and is used to represent the difference between the XYZ of
 332      * device illuminant and the XYZ of the device media when measured under
 333      * that illuminant.  The device white point is expressed as the device
 334      * XYZ values corresponding to white displayed on the device.  For
 335      * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
 336      * will result in a measured device XYZ value of D65.  This will not
 337      * be the same as the media white point tag XYZ value in the ICC
 338      * profile for an sRGB device.
 339      *
 340      * @param colorvalue a float array with length of at least the number
 341      *        of components in this ColorSpace.
 342      * @return a float array of length 3.
 343      * @throws ArrayIndexOutOfBoundsException if array length is not
 344      * at least the number of components in this ColorSpace.
 345      */
 346     public float[]    toCIEXYZ(float[] colorvalue) {
 347 
 348         if (this2xyz == null) {
 349             ColorTransform[] transformList = new ColorTransform [2];
 350             ICC_ColorSpace xyzCS =
 351                 (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
 352             PCMM mdl = CMSManager.getModule();
 353             try {
 354                 transformList[0] = mdl.createTransform(
 355                     thisProfile, ICC_Profile.icRelativeColorimetric,
 356                     ColorTransform.In);
 357             } catch (CMMException e) {
 358                 transformList[0] = mdl.createTransform(
 359                     thisProfile, ColorTransform.Any, ColorTransform.In);
 360             }
 361             transformList[1] = mdl.createTransform(
 362                 xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
 363             this2xyz = mdl.createTransform (transformList);
 364             if (needScaleInit) {
 365                 setComponentScaling();
 366             }
 367         }
 368 
 369         int nc = this.getNumComponents();
 370         short tmp[] = new short[nc];
 371         for (int i = 0; i < nc; i++) {
 372             tmp[i] = (short)
 373                 ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
 374         }
 375         tmp = this2xyz.colorConvert(tmp, null);
 376         float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
 377         // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
 378         float[] result = new float [3];
 379         for (int i = 0; i < 3; i++) {
 380             result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) * ALMOST_TWO;
 381         }
 382         return result;
 383     }
 384 
 385 
 386     /**
 387      * Transforms a color value assumed to be in the CS_CIEXYZ conversion
 388      * color space into this ColorSpace.
 389      * <p>
 390      * This method transforms color values using relative colorimetry,
 391      * as defined by the ICC Specification.  This
 392      * means that the XYZ argument values taken by this method are represented
 393      * relative to the D50 white point of the CS_CIEXYZ color space.
 394      * This representation is useful in a two-step color conversion
 395      * process in which colors are transformed from an input color
 396      * space to CS_CIEXYZ and then to an output color space.  The color
 397      * values returned by this method are not those that would produce
 398      * the XYZ value passed to the method when measured by a colorimeter.
 399      * If you have XYZ values corresponding to measurements made using
 400      * current CIE recommended practices, they must be converted to D50
 401      * relative values before being passed to this method.
 402      * The paragraphs below explain this in more detail.
 403      * <p>
 404      * The ICC standard uses a device independent color space (DICS) as the
 405      * mechanism for converting color from one device to another device.  In
 406      * this architecture, colors are converted from the source device's color
 407      * space to the ICC DICS and then from the ICC DICS to the destination
 408      * device's color space.  The ICC standard defines device profiles which
 409      * contain transforms which will convert between a device's color space
 410      * and the ICC DICS.  The overall conversion of colors from a source
 411      * device to colors of a destination device is done by connecting the
 412      * device-to-DICS transform of the profile for the source device to the
 413      * DICS-to-device transform of the profile for the destination device.
 414      * For this reason, the ICC DICS is commonly referred to as the profile
 415      * connection space (PCS).  The color space used in the methods
 416      * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
 417      * Specification.  This is also the color space represented by
 418      * ColorSpace.CS_CIEXYZ.
 419      * <p>
 420      * The XYZ values of a color are often represented as relative to some
 421      * white point, so the actual meaning of the XYZ values cannot be known
 422      * without knowing the white point of those values.  This is known as
 423      * relative colorimetry.  The PCS uses a white point of D50, so the XYZ
 424      * values of the PCS are relative to D50.  For example, white in the PCS
 425      * will have the XYZ values of D50, which is defined to be X=.9642,
 426      * Y=1.000, and Z=0.8249.  This white point is commonly used for graphic
 427      * arts applications, but others are often used in other applications.
 428      * <p>
 429      * To quantify the color characteristics of a device such as a printer
 430      * or monitor, measurements of XYZ values for particular device colors
 431      * are typically made.  For purposes of this discussion, the term
 432      * device XYZ values is used to mean the XYZ values that would be
 433      * measured from device colors using current CIE recommended practices.
 434      * <p>
 435      * Converting between device XYZ values and the PCS XYZ values taken as
 436      * arguments by this method corresponds to converting between the device's
 437      * color space, as represented by CIE colorimetric values, and the PCS.
 438      * There are many factors involved in this process, some of which are quite
 439      * subtle.  The most important, however, is the adjustment made to account
 440      * for differences between the device's white point and the white point of
 441      * the PCS.  There are many techniques for doing this and it is the
 442      * subject of much current research and controversy.  Some commonly used
 443      * methods are XYZ scaling, the von Kries transform, and the Bradford
 444      * transform.  The proper method to use depends upon each particular
 445      * application.
 446      * <p>
 447      * The simplest method is XYZ scaling.  In this method each device XYZ
 448      * value is  converted to a PCS XYZ value by multiplying it by the ratio
 449      * of the PCS white point (D50) to the device white point.
 450      * <pre>
 451      *
 452      * Xd, Yd, Zd are the device XYZ values
 453      * Xdw, Ydw, Zdw are the device XYZ white point values
 454      * Xp, Yp, Zp are the PCS XYZ values
 455      * Xd50, Yd50, Zd50 are the PCS XYZ white point values
 456      *
 457      * Xp = Xd * (Xd50 / Xdw)
 458      * Yp = Yd * (Yd50 / Ydw)
 459      * Zp = Zd * (Zd50 / Zdw)
 460      *
 461      * </pre>
 462      * <p>
 463      * Conversion from the PCS to the device would be done by inverting these
 464      * equations:
 465      * <pre>
 466      *
 467      * Xd = Xp * (Xdw / Xd50)
 468      * Yd = Yp * (Ydw / Yd50)
 469      * Zd = Zp * (Zdw / Zd50)
 470      *
 471      * </pre>
 472      * <p>
 473      * Note that the media white point tag in an ICC profile is not the same
 474      * as the device white point.  The media white point tag is expressed in
 475      * PCS values and is used to represent the difference between the XYZ of
 476      * device illuminant and the XYZ of the device media when measured under
 477      * that illuminant.  The device white point is expressed as the device
 478      * XYZ values corresponding to white displayed on the device.  For
 479      * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
 480      * will result in a measured device XYZ value of D65.  This will not
 481      * be the same as the media white point tag XYZ value in the ICC
 482      * profile for an sRGB device.
 483      *
 484      * @param colorvalue a float array with length of at least 3.
 485      * @return a float array with length equal to the number of
 486      *         components in this ColorSpace.
 487      * @throws ArrayIndexOutOfBoundsException if array length is not
 488      * at least 3.
 489      */
 490     public float[]    fromCIEXYZ(float[] colorvalue) {
 491 
 492         if (xyz2this == null) {
 493             ColorTransform[] transformList = new ColorTransform [2];
 494             ICC_ColorSpace xyzCS =
 495                 (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
 496             PCMM mdl = CMSManager.getModule();
 497             transformList[0] = mdl.createTransform (
 498                 xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In);
 499             try {
 500                 transformList[1] = mdl.createTransform(
 501                     thisProfile, ICC_Profile.icRelativeColorimetric,
 502                     ColorTransform.Out);
 503             } catch (CMMException e) {
 504                 transformList[1] = CMSManager.getModule().createTransform(
 505                 thisProfile, ColorTransform.Any, ColorTransform.Out);
 506             }
 507             xyz2this = mdl.createTransform(transformList);
 508             if (needScaleInit) {
 509                 setComponentScaling();
 510             }
 511         }
 512 
 513         short tmp[] = new short[3];
 514         float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
 515         float factor = 65535.0f / ALMOST_TWO;
 516         // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
 517         for (int i = 0; i < 3; i++) {
 518             tmp[i] = (short) ((colorvalue[i] * factor) + 0.5f);
 519         }
 520         tmp = xyz2this.colorConvert(tmp, null);
 521         int nc = this.getNumComponents();
 522         float[] result = new float [nc];
 523         for (int i = 0; i < nc; i++) {
 524             result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
 525                         diffMinMax[i] + minVal[i];
 526         }
 527         return result;
 528     }
 529 
 530     /**
 531      * Returns the minimum normalized color component value for the
 532      * specified component.  For TYPE_XYZ spaces, this method returns
 533      * minimum values of 0.0 for all components.  For TYPE_Lab spaces,
 534      * this method returns 0.0 for L and -128.0 for a and b components.
 535      * This is consistent with the encoding of the XYZ and Lab Profile
 536      * Connection Spaces in the ICC specification.  For all other types, this
 537      * method returns 0.0 for all components.  When using an ICC_ColorSpace
 538      * with a profile that requires different minimum component values,
 539      * it is necessary to subclass this class and override this method.
 540      * @param component The component index.
 541      * @return The minimum normalized component value.
 542      * @throws IllegalArgumentException if component is less than 0 or
 543      *         greater than numComponents - 1.
 544      * @since 1.4
 545      */
 546     public float getMinValue(int component) {
 547         if ((component < 0) || (component > this.getNumComponents() - 1)) {
 548             throw new IllegalArgumentException(
 549                 "Component index out of range: + component");
 550         }
 551         return minVal[component];
 552     }
 553 
 554     /**
 555      * Returns the maximum normalized color component value for the
 556      * specified component.  For TYPE_XYZ spaces, this method returns
 557      * maximum values of 1.0 + (32767.0 / 32768.0) for all components.
 558      * For TYPE_Lab spaces,
 559      * this method returns 100.0 for L and 127.0 for a and b components.
 560      * This is consistent with the encoding of the XYZ and Lab Profile
 561      * Connection Spaces in the ICC specification.  For all other types, this
 562      * method returns 1.0 for all components.  When using an ICC_ColorSpace
 563      * with a profile that requires different maximum component values,
 564      * it is necessary to subclass this class and override this method.
 565      * @param component The component index.
 566      * @return The maximum normalized component value.
 567      * @throws IllegalArgumentException if component is less than 0 or
 568      *         greater than numComponents - 1.
 569      * @since 1.4
 570      */
 571     public float getMaxValue(int component) {
 572         if ((component < 0) || (component > this.getNumComponents() - 1)) {
 573             throw new IllegalArgumentException(
 574                 "Component index out of range: + component");
 575         }
 576         return maxVal[component];
 577     }
 578 
 579     private void setMinMax() {
 580         int nc = this.getNumComponents();
 581         int type = this.getType();
 582         minVal = new float[nc];
 583         maxVal = new float[nc];
 584         if (type == ColorSpace.TYPE_Lab) {
 585             minVal[0] = 0.0f;    // L
 586             maxVal[0] = 100.0f;
 587             minVal[1] = -128.0f; // a
 588             maxVal[1] = 127.0f;
 589             minVal[2] = -128.0f; // b
 590             maxVal[2] = 127.0f;
 591         } else if (type == ColorSpace.TYPE_XYZ) {
 592             minVal[0] = minVal[1] = minVal[2] = 0.0f; // X, Y, Z
 593             maxVal[0] = maxVal[1] = maxVal[2] = 1.0f + (32767.0f/ 32768.0f);
 594         } else {
 595             for (int i = 0; i < nc; i++) {
 596                 minVal[i] = 0.0f;
 597                 maxVal[i] = 1.0f;
 598             }
 599         }
 600     }
 601 
 602     private void setComponentScaling() {
 603         int nc = this.getNumComponents();
 604         diffMinMax = new float[nc];
 605         invDiffMinMax = new float[nc];
 606         for (int i = 0; i < nc; i++) {
 607             minVal[i] = this.getMinValue(i); // in case getMinVal is overridden
 608             maxVal[i] = this.getMaxValue(i); // in case getMaxVal is overridden
 609             diffMinMax[i] = maxVal[i] - minVal[i];
 610             invDiffMinMax[i] = 65535.0f / diffMinMax[i];
 611         }
 612         needScaleInit = false;
 613     }
 614 
 615 }