/*
* Copyright (c) 1997, 2014, 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.ColorTransform;
import sun.java2d.cmm.CMSManager;
import sun.java2d.cmm.PCMM;
The ICC_ColorSpace class is an implementation of the abstract
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 http://www.color.org).
Typically, a Color or 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 ICC_Profile).
Attempting to create an ICC_ColorSpace object from an inappropriate ICC
Profile is an error.
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 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 ICC_ColorSpace object will
produce output in the specified type of color space (e.g. TYPE_RGB,
TYPE_CMYK, etc.), but the specific color values of the output data
will be undefined.
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
ColorSpace.getInstance().
See Also: - ColorSpace
- ICC_Profile
/**
*
* The ICC_ColorSpace class is an implementation of the abstract
* 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 Color or 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 ICC_Profile).
* Attempting to create an 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 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 ICC_ColorSpace object will
* produce output in the specified type of color space (e.g. TYPE_RGB,
* 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
* 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 ICC_ColorSpace from an ICC_Profile object.
Params: - profile – the specified ICC_Profile object
Throws: - IllegalArgumentException – if profile is inappropriate for
representing a ColorSpace.
/**
* Constructs a new ICC_ColorSpace from an ICC_Profile object.
* @param profile the specified ICC_Profile object
* @exception IllegalArgumentException if profile is inappropriate for
* representing a 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
/**
* 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 ICC_Profile for this ICC_ColorSpace.
Returns: the ICC_Profile for this ICC_ColorSpace.
/**
* Returns the ICC_Profile for this ICC_ColorSpace.
* @return the ICC_Profile for this ICC_ColorSpace.
*/
public ICC_Profile getProfile() {
return thisProfile;
}
Transforms a color value assumed to be in this ColorSpace
into a value in the default CS_sRGB color space.
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 toCIEXYZ
method of this color space to first convert from the input color space to the CS_CIEXYZ color space, and then use the fromCIEXYZ
method of the CS_sRGB color space to convert from CS_CIEXYZ to the output color space. See toCIEXYZ
and fromCIEXYZ
for further information.
Params: - colorvalue – a float array with length of at least the number
of components in this ColorSpace.
Throws: - ArrayIndexOutOfBoundsException – if array length is not
at least the number of components in this ColorSpace.
Returns: a float array of length 3.
/**
* Transforms a color value assumed to be in this ColorSpace
* into a value in the default 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 CS_CIEXYZ color space, and then use the
* {@code fromCIEXYZ} method of the CS_sRGB color space to
* convert from 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 ColorSpace.
* @return a float array of length 3.
* @throws ArrayIndexOutOfBoundsException if array length is not
* at least the number of components in this 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 CS_sRGB
color space into this ColorSpace.
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 toCIEXYZ
method of the CS_sRGB color space to first convert from the input color space to the CS_CIEXYZ color space, and then use the fromCIEXYZ
method of this color space to convert from CS_CIEXYZ to the output color space. See toCIEXYZ
and fromCIEXYZ
for further information.
Params: - rgbvalue – a float array with length of at least 3.
Throws: - ArrayIndexOutOfBoundsException – if array length is not
at least 3.
Returns: a float array with length equal to the number of
components in this ColorSpace.
/**
* Transforms a color value assumed to be in the default CS_sRGB
* color space into this 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 CS_sRGB color space to first convert from the input
* color space to the CS_CIEXYZ color space, and then use the
* {@code fromCIEXYZ} method of this color space to
* convert from 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 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 ColorSpace
into the CS_CIEXYZ conversion color space.
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 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 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.
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
toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
Specification. This is also the color space represented by
ColorSpace.CS_CIEXYZ.
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.
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.
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.
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.
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)
Conversion from the PCS to the device would be done by inverting these
equations:
Xd = Xp * (Xdw / Xd50)
Yd = Yp * (Ydw / Yd50)
Zd = Zp * (Zdw / Zd50)
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.
Params: - colorvalue – a float array with length of at least the number
of components in this ColorSpace.
Throws: - ArrayIndexOutOfBoundsException – if array length is not
at least the number of components in this ColorSpace.
Returns: a float array of length 3.
/**
* Transforms a color value assumed to be in this ColorSpace
* into the 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 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 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
* toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
* Specification. This is also the color space represented by
* 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 ColorSpace.
* @return a float array of length 3.
* @throws ArrayIndexOutOfBoundsException if array length is not
* at least the number of components in this 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 CS_CIEXYZ conversion
color space into this ColorSpace.
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 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 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.
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
toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
Specification. This is also the color space represented by
ColorSpace.CS_CIEXYZ.
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.
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.
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.
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.
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)
Conversion from the PCS to the device would be done by inverting these
equations:
Xd = Xp * (Xdw / Xd50)
Yd = Yp * (Ydw / Yd50)
Zd = Zp * (Zdw / Zd50)
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.
Params: - colorvalue – a float array with length of at least 3.
Throws: - ArrayIndexOutOfBoundsException – if array length is not
at least 3.
Returns: a float array with length equal to the number of
components in this ColorSpace.
/**
* Transforms a color value assumed to be in the 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 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 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
* toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
* Specification. This is also the color space represented by
* 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 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 TYPE_XYZ spaces, this method returns
minimum values of 0.0 for all components. For 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 ICC_ColorSpace
with a profile that requires different minimum component values,
it is necessary to subclass this class and override this method.
Params: - component – The component index.
Throws: - IllegalArgumentException – if component is less than 0 or
greater than numComponents - 1.
Returns: The minimum normalized component value. Since: 1.4
/**
* Returns the minimum normalized color component value for the
* specified component. For TYPE_XYZ spaces, this method returns
* minimum values of 0.0 for all components. For 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 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.
* @throws IllegalArgumentException if component is less than 0 or
* greater than numComponents - 1.
* @since 1.4
*/
public float getMinValue(int component) {
if ((component < 0) || (component > this.getNumComponents() - 1)) {
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return minVal[component];
}
Returns the maximum normalized color component value for the
specified component. For TYPE_XYZ spaces, this method returns
maximum values of 1.0 + (32767.0 / 32768.0) for all components.
For TYPE_Lab spaces,
this method returns 100.0 for L and 127.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 1.0 for all components. When using an ICC_ColorSpace
with a profile that requires different maximum component values,
it is necessary to subclass this class and override this method.
Params: - component – The component index.
Throws: - IllegalArgumentException – if component is less than 0 or
greater than numComponents - 1.
Returns: The maximum normalized component value. Since: 1.4
/**
* Returns the maximum normalized color component value for the
* specified component. For TYPE_XYZ spaces, this method returns
* maximum values of 1.0 + (32767.0 / 32768.0) for all components.
* For TYPE_Lab spaces,
* this method returns 100.0 for L and 127.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 1.0 for all components. When using an ICC_ColorSpace
* with a profile that requires different maximum component values,
* it is necessary to subclass this class and override this method.
* @param component The component index.
* @return The maximum normalized component value.
* @throws IllegalArgumentException if component is less than 0 or
* greater than numComponents - 1.
* @since 1.4
*/
public float getMaxValue(int component) {
if ((component < 0) || (component > this.getNumComponents() - 1)) {
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return maxVal[component];
}
private void setMinMax() {
int nc = this.getNumComponents();
int type = this.getType();
minVal = new float[nc];
maxVal = new float[nc];
if (type == ColorSpace.TYPE_Lab) {
minVal[0] = 0.0f; // L
maxVal[0] = 100.0f;
minVal[1] = -128.0f; // a
maxVal[1] = 127.0f;
minVal[2] = -128.0f; // b
maxVal[2] = 127.0f;
} else if (type == ColorSpace.TYPE_XYZ) {
minVal[0] = minVal[1] = minVal[2] = 0.0f; // X, Y, Z
maxVal[0] = maxVal[1] = maxVal[2] = 1.0f + (32767.0f/ 32768.0f);
} else {
for (int i = 0; i < nc; i++) {
minVal[i] = 0.0f;
maxVal[i] = 1.0f;
}
}
}
private void setComponentScaling() {
int nc = this.getNumComponents();
diffMinMax = new float[nc];
invDiffMinMax = new float[nc];
for (int i = 0; i < nc; i++) {
minVal[i] = this.getMinValue(i); // in case getMinVal is overridden
maxVal[i] = this.getMaxValue(i); // in case getMaxVal is overridden
diffMinMax[i] = maxVal[i] - minVal[i];
invDiffMinMax[i] = 65535.0f / diffMinMax[i];
}
needScaleInit = false;
}
}