/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* ********************************************************************
**********************************************************************
**********************************************************************
*** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
*** As an unpublished work pursuant to Title 17 of the United ***
*** States Code. All rights reserved. ***
**********************************************************************
**********************************************************************
**********************************************************************/
package java.awt.color;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.ColorTransform;
import sun.java2d.cmm.PCMM;
/**
* The {@code ICC_ColorSpace} class is an implementation of the abstract
* {@code ColorSpace} class. This representation of device independent and
* device dependent color spaces is based on the International Color Consortium
* Specification ICC.1:2001-12, File Format for Color Profiles (see
* <a href="http://www.color.org">http://www.color.org</a>).
* <p>
* Typically, a {@code Color} or {@code ColorModel} would be associated with an
* ICC Profile which is either an input, display, or output profile (see the ICC
* specification). There are other types of ICC Profiles, e.g. abstract
* profiles, device link profiles, and named color profiles, which do not
* contain information appropriate for representing the color space of a color,
* image, or device (see {@code ICC_Profile}). Attempting to create an
* {@code ICC_ColorSpace} object from an inappropriate ICC Profile is an error.
* <p>
* ICC Profiles represent transformations from the color space of the profile
* (e.g. a monitor) to a Profile Connection Space (PCS). Profiles of interest
* for tagging images or colors have a PCS which is one of the device
* independent spaces (one CIEXYZ space and two CIELab spaces) defined in the
* ICC Profile Format Specification. Most profiles of interest either have
* invertible transformations or explicitly specify transformations going both
* directions. Should an {@code ICC_ColorSpace} object be used in a way
* requiring a conversion from PCS to the profile's native space and there is
* inadequate data to correctly perform the conversion, the
* {@code ICC_ColorSpace} object will produce output in the specified type of
* color space (e.g. {@code TYPE_RGB}, {@code TYPE_CMYK}, etc.), but the
* specific color values of the output data will be undefined.
* <p>
* The details of this class are not important for simple applets, which draw in
* a default color space or manipulate and display imported images with a known
* color space. At most, such applets would need to get one of the default color
* spaces via {@link ColorSpace#getInstance}.
*
* @see ColorSpace
* @see ICC_Profile
*/
public class ICC_ColorSpace extends ColorSpace {
static final long serialVersionUID = 3455889114070431483L;
private ICC_Profile thisProfile;
private float[] minVal;
private float[] maxVal;
private float[] diffMinMax;
private float[] invDiffMinMax;
private boolean needScaleInit = true;
// {to,from}{RGB,CIEXYZ} methods create and cache these when needed
private transient ColorTransform this2srgb;
private transient ColorTransform srgb2this;
private transient ColorTransform this2xyz;
private transient ColorTransform xyz2this;
/**
* Constructs a new {@code ICC_ColorSpace} from an {@code ICC_Profile}
* object.
*
* @param profile the specified {@code ICC_Profile} object
* @throws IllegalArgumentException if profile is inappropriate for
* representing a {@code ColorSpace}
*/
public ICC_ColorSpace (ICC_Profile profile) {
super (profile.getColorSpaceType(), profile.getNumComponents());
int profileClass = profile.getProfileClass();
/* REMIND - is NAMEDCOLOR OK? */
if ((profileClass != ICC_Profile.CLASS_INPUT) &&
(profileClass != ICC_Profile.CLASS_DISPLAY) &&
(profileClass != ICC_Profile.CLASS_OUTPUT) &&
(profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) &&
(profileClass != ICC_Profile.CLASS_NAMEDCOLOR) &&
(profileClass != ICC_Profile.CLASS_ABSTRACT)) {
throw new IllegalArgumentException("Invalid profile type");
}
thisProfile = profile;
setMinMax();
}
/**
* Validate an ICC_ColorSpace read from an object input stream
*/
private void readObject(java.io.ObjectInputStream s)
throws ClassNotFoundException, java.io.IOException {
s.defaultReadObject();
if (thisProfile == null) {
thisProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
}
}
/**
* Returns the {@code ICC_Profile} for this {@code ICC_ColorSpace}.
*
* @return the {@code ICC_Profile} for this {@code ICC_ColorSpace}
*/
public ICC_Profile getProfile() {
return thisProfile;
}
/**
* Transforms a color value assumed to be in this {@code ColorSpace} into a
* value in the default {@code CS_sRGB} color space.
* <p>
* This method transforms color values using algorithms designed to produce
* the best perceptual match between input and output colors. In order to do
* colorimetric conversion of color values, you should use the
* {@code toCIEXYZ} method of this color space to first convert from the
* input color space to the {@code CS_CIEXYZ} color space, and then use the
* {@code fromCIEXYZ} method of the {@code CS_sRGB} color space to convert
* from {@code CS_CIEXYZ} to the output color space. See
* {@link #toCIEXYZ(float[]) toCIEXYZ} and
* {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
*
* @param colorvalue a float array with length of at least the number of
* components in this {@code ColorSpace}
* @return a float array of length 3
* @throws ArrayIndexOutOfBoundsException if array length is not at least
* the number of components in this {@code ColorSpace}
*/
public float[] toRGB (float[] colorvalue) {
if (this2srgb == null) {
ColorTransform[] transformList = new ColorTransform [2];
ICC_ColorSpace srgbCS =
(ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
PCMM mdl = CMSManager.getModule();
transformList[0] = mdl.createTransform(
thisProfile, ColorTransform.Any, ColorTransform.In);
transformList[1] = mdl.createTransform(
srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
this2srgb = mdl.createTransform(transformList);
if (needScaleInit) {
setComponentScaling();
}
}
int nc = this.getNumComponents();
short[] tmp = new short[nc];
for (int i = 0; i < nc; i++) {
tmp[i] = (short)
((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
}
tmp = this2srgb.colorConvert(tmp, null);
float[] result = new float [3];
for (int i = 0; i < 3; i++) {
result[i] = ((float) (tmp[i] & 0xffff)) / 65535.0f;
}
return result;
}
/**
* Transforms a color value assumed to be in the default {@code CS_sRGB}
* color space into this {@code ColorSpace}.
* <p>
* This method transforms color values using algorithms designed to produce
* the best perceptual match between input and output colors. In order to do
* colorimetric conversion of color values, you should use the
* {@code toCIEXYZ} method of the {@code CS_sRGB} color space to first
* convert from the input color space to the {@code CS_CIEXYZ} color space,
* and then use the {@code fromCIEXYZ} method of this color space to convert
* from {@code CS_CIEXYZ} to the output color space. See
* {@link #toCIEXYZ(float[]) toCIEXYZ} and
* {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
*
* @param rgbvalue a float array with length of at least 3
* @return a float array with length equal to the number of components in
* this {@code ColorSpace}
* @throws ArrayIndexOutOfBoundsException if array length is not at least 3
*/
public float[] fromRGB(float[] rgbvalue) {
if (srgb2this == null) {
ColorTransform[] transformList = new ColorTransform [2];
ICC_ColorSpace srgbCS =
(ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
PCMM mdl = CMSManager.getModule();
transformList[0] = mdl.createTransform(
srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In);
transformList[1] = mdl.createTransform(
thisProfile, ColorTransform.Any, ColorTransform.Out);
srgb2this = mdl.createTransform(transformList);
if (needScaleInit) {
setComponentScaling();
}
}
short[] tmp = new short[3];
for (int i = 0; i < 3; i++) {
tmp[i] = (short) ((rgbvalue[i] * 65535.0f) + 0.5f);
}
tmp = srgb2this.colorConvert(tmp, null);
int nc = this.getNumComponents();
float[] result = new float [nc];
for (int i = 0; i < nc; i++) {
result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
diffMinMax[i] + minVal[i];
}
return result;
}
/**
* Transforms a color value assumed to be in this {@code ColorSpace} into
* the {@code CS_CIEXYZ} conversion color space.
* <p>
* This method transforms color values using relative colorimetry, as
* defined by the ICC Specification. This means that the XYZ values returned
* by this method are represented relative to the D50 white point of the
* {@code CS_CIEXYZ} color space. This representation is useful in a
* two-step color conversion process in which colors are transformed from an
* input color space to {@code CS_CIEXYZ} and then to an output color space.
* This representation is not the same as the XYZ values that would be
* measured from the given color value by a colorimeter. A further
* transformation is necessary to compute the XYZ values that would be
* measured using current CIE recommended practices. The paragraphs below
* explain this in more detail.
* <p>
* The ICC standard uses a device independent color space (DICS) as the
* mechanism for converting color from one device to another device. In this
* architecture, colors are converted from the source device's color space
* to the ICC DICS and then from the ICC DICS to the destination device's
* color space. The ICC standard defines device profiles which contain
* transforms which will convert between a device's color space and the ICC
* DICS. The overall conversion of colors from a source device to colors of
* a destination device is done by connecting the device-to-DICS transform
* of the profile for the source device to the DICS-to-device transform of
* the profile for the destination device. For this reason, the ICC DICS is
* commonly referred to as the profile connection space (PCS). The color
* space used in the methods {@code toCIEXYZ} and {@code fromCIEXYZ} is the
* CIEXYZ PCS defined by the ICC Specification. This is also the color space
* represented by {@code ColorSpace.CS_CIEXYZ}.
* <p>
* The XYZ values of a color are often represented as relative to some white
* point, so the actual meaning of the XYZ values cannot be known without
* knowing the white point of those values. This is known as relative
* colorimetry. The PCS uses a white point of D50, so the XYZ values of the
* PCS are relative to D50. For example, white in the PCS will have the XYZ
* values of D50, which is defined to be X=.9642, Y=1.000, and Z=0.8249.
* This white point is commonly used for graphic arts applications, but
* others are often used in other applications.
* <p>
* To quantify the color characteristics of a device such as a printer or
* monitor, measurements of XYZ values for particular device colors are
* typically made. For purposes of this discussion, the term device XYZ
* values is used to mean the XYZ values that would be measured from device
* colors using current CIE recommended practices.
* <p>
* Converting between device XYZ values and the PCS XYZ values returned by
* this method corresponds to converting between the device's color space,
* as represented by CIE colorimetric values, and the PCS. There are many
* factors involved in this process, some of which are quite subtle. The
* most important, however, is the adjustment made to account for
* differences between the device's white point and the white point of the
* PCS. There are many techniques for doing this and it is the subject of
* much current research and controversy. Some commonly used methods are XYZ
* scaling, the von Kries transform, and the Bradford transform. The proper
* method to use depends upon each particular application.
* <p>
* The simplest method is XYZ scaling. In this method each device XYZ value
* is converted to a PCS XYZ value by multiplying it by the ratio of the PCS
* white point (D50) to the device white point.
* <pre>
*
* Xd, Yd, Zd are the device XYZ values
* Xdw, Ydw, Zdw are the device XYZ white point values
* Xp, Yp, Zp are the PCS XYZ values
* Xd50, Yd50, Zd50 are the PCS XYZ white point values
*
* Xp = Xd * (Xd50 / Xdw)
* Yp = Yd * (Yd50 / Ydw)
* Zp = Zd * (Zd50 / Zdw)
*
* </pre>
* <p>
* Conversion from the PCS to the device would be done by inverting these
* equations:
* <pre>
*
* Xd = Xp * (Xdw / Xd50)
* Yd = Yp * (Ydw / Yd50)
* Zd = Zp * (Zdw / Zd50)
*
* </pre>
* <p>
* Note that the media white point tag in an ICC profile is not the same as
* the device white point. The media white point tag is expressed in PCS
* values and is used to represent the difference between the XYZ of device
* illuminant and the XYZ of the device media when measured under that
* illuminant. The device white point is expressed as the device XYZ values
* corresponding to white displayed on the device. For example, displaying
* the RGB color (1.0, 1.0, 1.0) on an sRGB device will result in a measured
* device XYZ value of D65. This will not be the same as the media white
* point tag XYZ value in the ICC profile for an sRGB device.
*
* @param colorvalue a float array with length of at least the number of
* components in this {@code ColorSpace}
* @return a float array of length 3
* @throws ArrayIndexOutOfBoundsException if array length is not at least
* the number of components in this {@code ColorSpace}
*/
public float[] toCIEXYZ(float[] colorvalue) {
if (this2xyz == null) {
ColorTransform[] transformList = new ColorTransform [2];
ICC_ColorSpace xyzCS =
(ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
PCMM mdl = CMSManager.getModule();
try {
transformList[0] = mdl.createTransform(
thisProfile, ICC_Profile.icRelativeColorimetric,
ColorTransform.In);
} catch (CMMException e) {
transformList[0] = mdl.createTransform(
thisProfile, ColorTransform.Any, ColorTransform.In);
}
transformList[1] = mdl.createTransform(
xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
this2xyz = mdl.createTransform (transformList);
if (needScaleInit) {
setComponentScaling();
}
}
int nc = this.getNumComponents();
short[] tmp = new short[nc];
for (int i = 0; i < nc; i++) {
tmp[i] = (short)
((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
}
tmp = this2xyz.colorConvert(tmp, null);
float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
// For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
float[] result = new float [3];
for (int i = 0; i < 3; i++) {
result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) * ALMOST_TWO;
}
return result;
}
/**
* Transforms a color value assumed to be in the {@code CS_CIEXYZ}
* conversion color space into this ColorSpace.
* <p>
* This method transforms color values using relative colorimetry, as
* defined by the ICC Specification. This means that the XYZ argument values
* taken by this method are represented relative to the D50 white point of
* the {@code CS_CIEXYZ} color space. This representation is useful in a
* two-step color conversion process in which colors are transformed from an
* input color space to {@code CS_CIEXYZ} and then to an output color space.
* The color values returned by this method are not those that would produce
* the XYZ value passed to the method when measured by a colorimeter. If you
* have XYZ values corresponding to measurements made using current CIE
* recommended practices, they must be converted to D50 relative values
* before being passed to this method. The paragraphs below explain this in
* more detail.
* <p>
* The ICC standard uses a device independent color space (DICS) as the
* mechanism for converting color from one device to another device. In this
* architecture, colors are converted from the source device's color space
* to the ICC DICS and then from the ICC DICS to the destination device's
* color space. The ICC standard defines device profiles which contain
* transforms which will convert between a device's color space and the ICC
* DICS. The overall conversion of colors from a source device to colors of
* a destination device is done by connecting the device-to-DICS transform
* of the profile for the source device to the DICS-to-device transform of
* the profile for the destination device. For this reason, the ICC DICS is
* commonly referred to as the profile connection space (PCS). The color
* space used in the methods {@code toCIEXYZ} and {@code fromCIEXYZ} is the
* CIEXYZ PCS defined by the ICC Specification. This is also the color space
* represented by {@code ColorSpace.CS_CIEXYZ}.
* <p>
* The XYZ values of a color are often represented as relative to some white
* point, so the actual meaning of the XYZ values cannot be known without
* knowing the white point of those values. This is known as relative
* colorimetry. The PCS uses a white point of D50, so the XYZ values of the
* PCS are relative to D50. For example, white in the PCS will have the XYZ
* values of D50, which is defined to be X=.9642, Y=1.000, and Z=0.8249.
* This white point is commonly used for graphic arts applications, but
* others are often used in other applications.
* <p>
* To quantify the color characteristics of a device such as a printer or
* monitor, measurements of XYZ values for particular device colors are
* typically made. For purposes of this discussion, the term device XYZ
* values is used to mean the XYZ values that would be measured from device
* colors using current CIE recommended practices.
* <p>
* Converting between device XYZ values and the PCS XYZ values taken as
* arguments by this method corresponds to converting between the device's
* color space, as represented by CIE colorimetric values, and the PCS.
* There are many factors involved in this process, some of which are quite
* subtle. The most important, however, is the adjustment made to account
* for differences between the device's white point and the white point of
* the PCS. There are many techniques for doing this and it is the subject
* of much current research and controversy. Some commonly used methods are
* XYZ scaling, the von Kries transform, and the Bradford transform. The
* proper method to use depends upon each particular application.
* <p>
* The simplest method is XYZ scaling. In this method each device XYZ value
* is converted to a PCS XYZ value by multiplying it by the ratio of the PCS
* white point (D50) to the device white point.
* <pre>
*
* Xd, Yd, Zd are the device XYZ values
* Xdw, Ydw, Zdw are the device XYZ white point values
* Xp, Yp, Zp are the PCS XYZ values
* Xd50, Yd50, Zd50 are the PCS XYZ white point values
*
* Xp = Xd * (Xd50 / Xdw)
* Yp = Yd * (Yd50 / Ydw)
* Zp = Zd * (Zd50 / Zdw)
*
* </pre>
* <p>
* Conversion from the PCS to the device would be done by inverting these
* equations:
* <pre>
*
* Xd = Xp * (Xdw / Xd50)
* Yd = Yp * (Ydw / Yd50)
* Zd = Zp * (Zdw / Zd50)
*
* </pre>
* <p>
* Note that the media white point tag in an ICC profile is not the same as
* the device white point. The media white point tag is expressed in PCS
* values and is used to represent the difference between the XYZ of device
* illuminant and the XYZ of the device media when measured under that
* illuminant. The device white point is expressed as the device XYZ values
* corresponding to white displayed on the device. For example, displaying
* the RGB color (1.0, 1.0, 1.0) on an sRGB device will result in a measured
* device XYZ value of D65. This will not be the same as the media white
* point tag XYZ value in the ICC profile for an sRGB device.
*
* @param colorvalue a float array with length of at least 3
* @return a float array with length equal to the number of components in
* this {@code ColorSpace}
* @throws ArrayIndexOutOfBoundsException if array length is not at least 3
*/
public float[] fromCIEXYZ(float[] colorvalue) {
if (xyz2this == null) {
ColorTransform[] transformList = new ColorTransform [2];
ICC_ColorSpace xyzCS =
(ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
PCMM mdl = CMSManager.getModule();
transformList[0] = mdl.createTransform (
xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In);
try {
transformList[1] = mdl.createTransform(
thisProfile, ICC_Profile.icRelativeColorimetric,
ColorTransform.Out);
} catch (CMMException e) {
transformList[1] = CMSManager.getModule().createTransform(
thisProfile, ColorTransform.Any, ColorTransform.Out);
}
xyz2this = mdl.createTransform(transformList);
if (needScaleInit) {
setComponentScaling();
}
}
short[] tmp = new short[3];
float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
float factor = 65535.0f / ALMOST_TWO;
// For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
for (int i = 0; i < 3; i++) {
tmp[i] = (short) ((colorvalue[i] * factor) + 0.5f);
}
tmp = xyz2this.colorConvert(tmp, null);
int nc = this.getNumComponents();
float[] result = new float [nc];
for (int i = 0; i < nc; i++) {
result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
diffMinMax[i] + minVal[i];
}
return result;
}
/**
* Returns the minimum normalized color component value for the specified
* component. For {@code TYPE_XYZ} spaces, this method returns minimum
* values of 0.0 for all components. For {@code TYPE_Lab} spaces, this
* method returns 0.0 for L and -128.0 for a and b components. This is
* consistent with the encoding of the XYZ and Lab Profile Connection Spaces
* in the ICC specification. For all other types, this method returns 0.0
* for all components. When using an {@code ICC_ColorSpace} with a profile
* that requires different minimum component values, it is necessary to
* subclass this class and override this method.
*
* @param component the component index
* @return the minimum normalized component value
/**代码未完, 请加载全部代码(NowJava.com).**/