8254370: Update the classes in the java.awt.color package

Reviewed-by: prr
This commit is contained in:
Sergey Bylokhov 2020-10-26 23:56:11 +00:00
parent 8ca59c9e2e
commit abdbbe3a79
6 changed files with 312 additions and 105 deletions

View file

@ -102,12 +102,12 @@ public abstract class ColorSpace implements Serializable {
/** /**
* One of the {@code ColorSpace} type constants. * One of the {@code ColorSpace} type constants.
*/ */
private int type; private final int type;
/** /**
* The number of components in the color space. * The number of components in the color space.
*/ */
private int numComponents; private final int numComponents;
private transient String [] compName = null; private transient String [] compName = null;
// Cache of singletons for the predefined color spaces. // Cache of singletons for the predefined color spaces.
@ -242,6 +242,7 @@ public abstract class ColorSpace implements Serializable {
*/ */
@Native public static final int TYPE_FCLR = 25; @Native public static final int TYPE_FCLR = 25;
/** /**
* The sRGB color space defined at * The sRGB color space defined at
* <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html"> * <a href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
@ -275,11 +276,11 @@ public abstract class ColorSpace implements Serializable {
* number of components. * number of components.
* *
* @param type one of the {@code ColorSpace} type constants * @param type one of the {@code ColorSpace} type constants
* @param numcomponents the number of components in the color space * @param numComponents the number of components in the color space
*/ */
protected ColorSpace(int type, int numcomponents) { protected ColorSpace(int type, int numComponents) {
this.type = type; this.type = type;
this.numComponents = numcomponents; this.numComponents = numComponents;
} }
/** /**
@ -508,11 +509,7 @@ public abstract class ColorSpace implements Serializable {
*/ */
public String getName (int idx) { public String getName (int idx) {
/* REMIND - handle common cases here */ /* REMIND - handle common cases here */
if ((idx < 0) || (idx > numComponents - 1)) { rangeCheck(idx);
throw new IllegalArgumentException(
"Component index out of range: " + idx);
}
if (compName == null) { if (compName == null) {
switch (type) { switch (type) {
case ColorSpace.TYPE_XYZ: case ColorSpace.TYPE_XYZ:
@ -573,10 +570,7 @@ public abstract class ColorSpace implements Serializable {
* @since 1.4 * @since 1.4
*/ */
public float getMinValue(int component) { public float getMinValue(int component) {
if ((component < 0) || (component > numComponents - 1)) { rangeCheck(component);
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return 0.0f; return 0.0f;
} }
@ -592,17 +586,21 @@ public abstract class ColorSpace implements Serializable {
* @since 1.4 * @since 1.4
*/ */
public float getMaxValue(int component) { public float getMaxValue(int component) {
if ((component < 0) || (component > numComponents - 1)) { rangeCheck(component);
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return 1.0f; return 1.0f;
} }
/* /**
* Returns {@code true} if {@code cspace} is the XYZspace. * Checks that {@code component} is in range of the number of components.
*
* @param component the component index
* @throws IllegalArgumentException if component is less than 0 or greater
* than {@code numComponents - 1}
*/ */
static boolean isCS_CIEXYZ(ColorSpace cspace) { final void rangeCheck(int component) {
return (cspace == XYZspace); if (component < 0 || component > getNumComponents() - 1) {
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
} }
} }

View file

@ -569,10 +569,7 @@ public class ICC_ColorSpace extends ColorSpace {
* @since 1.4 * @since 1.4
*/ */
public float getMinValue(int component) { public float getMinValue(int component) {
if ((component < 0) || (component > this.getNumComponents() - 1)) { rangeCheck(component);
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return minVal[component]; return minVal[component];
} }
@ -595,10 +592,7 @@ public class ICC_ColorSpace extends ColorSpace {
* @since 1.4 * @since 1.4
*/ */
public float getMaxValue(int component) { public float getMaxValue(int component) {
if ((component < 0) || (component > this.getNumComponents() - 1)) { rangeCheck(component);
throw new IllegalArgumentException(
"Component index out of range: " + component);
}
return maxVal[component]; return maxVal[component];
} }

View file

@ -115,10 +115,7 @@ public class ICC_ProfileGray extends ICC_Profile {
* single gamma value * single gamma value
*/ */
public float getGamma() { public float getGamma() {
float theGamma; return getGamma(ICC_Profile.icSigGrayTRCTag);
theGamma = super.getGamma(ICC_Profile.icSigGrayTRCTag);
return theGamma;
} }
/** /**
@ -140,10 +137,6 @@ public class ICC_ProfileGray extends ICC_Profile {
* table * table
*/ */
public short[] getTRC() { public short[] getTRC() {
short[] theTRC; return getTRC(ICC_Profile.icSigGrayTRCTag);
theTRC = super.getTRC(ICC_Profile.icSigGrayTRCTag);
return theTRC;
} }
} }

View file

@ -143,22 +143,12 @@ public class ICC_ProfileRGB extends ICC_Profile {
* {@code greenColorantTag}, and {@code blueColorantTag} * {@code greenColorantTag}, and {@code blueColorantTag}
*/ */
public float[][] getMatrix() { public float[][] getMatrix() {
float[][] theMatrix = new float[3][3]; float[] red = getXYZTag(ICC_Profile.icSigRedColorantTag);
float[] tmpMatrix; float[] green = getXYZTag(ICC_Profile.icSigGreenColorantTag);
float[] blue = getXYZTag(ICC_Profile.icSigBlueColorantTag);
tmpMatrix = getXYZTag(ICC_Profile.icSigRedColorantTag); return new float[][]{{red[0], green[0], blue[0]},
theMatrix[0][0] = tmpMatrix[0]; {red[1], green[1], blue[1]},
theMatrix[1][0] = tmpMatrix[1]; {red[2], green[2], blue[2]}};
theMatrix[2][0] = tmpMatrix[2];
tmpMatrix = getXYZTag(ICC_Profile.icSigGreenColorantTag);
theMatrix[0][1] = tmpMatrix[0];
theMatrix[1][1] = tmpMatrix[1];
theMatrix[2][1] = tmpMatrix[2];
tmpMatrix = getXYZTag(ICC_Profile.icSigBlueColorantTag);
theMatrix[0][2] = tmpMatrix[0];
theMatrix[1][2] = tmpMatrix[1];
theMatrix[2][2] = tmpMatrix[2];
return theMatrix;
} }
/** /**
@ -181,33 +171,14 @@ public class ICC_ProfileRGB extends ICC_Profile {
* @param component the {@code ICC_ProfileRGB} constant that represents the * @param component the {@code ICC_ProfileRGB} constant that represents the
* component whose TRC you want to retrieve * component whose TRC you want to retrieve
* @return the gamma value as a float * @return the gamma value as a float
* @throws IllegalArgumentException if the component is not
* {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or
* {@code BLUECOMPONENT}
* @throws ProfileDataException if the profile does not specify the * @throws ProfileDataException if the profile does not specify the
* corresponding TRC as a single gamma value * corresponding TRC as a single gamma value
*/ */
public float getGamma(int component) { public float getGamma(int component) {
float theGamma; return super.getGamma(toTag(component));
int theSignature;
switch (component) {
case REDCOMPONENT:
theSignature = ICC_Profile.icSigRedTRCTag;
break;
case GREENCOMPONENT:
theSignature = ICC_Profile.icSigGreenTRCTag;
break;
case BLUECOMPONENT:
theSignature = ICC_Profile.icSigBlueTRCTag;
break;
default:
throw new IllegalArgumentException("Must be Red, Green, or Blue");
}
theGamma = super.getGamma(theSignature);
return theGamma;
} }
/** /**
@ -232,33 +203,32 @@ public class ICC_ProfileRGB extends ICC_Profile {
* component whose TRC you want to retrieve: {@code REDCOMPONENT}, * component whose TRC you want to retrieve: {@code REDCOMPONENT},
* {@code GREENCOMPONENT}, or {@code BLUECOMPONENT} * {@code GREENCOMPONENT}, or {@code BLUECOMPONENT}
* @return a short array representing the TRC * @return a short array representing the TRC
* @throws IllegalArgumentException if the component is not
* {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or
* {@code BLUECOMPONENT}
* @throws ProfileDataException if the profile does not specify the * @throws ProfileDataException if the profile does not specify the
* corresponding TRC as a table * corresponding TRC as a table
*/ */
public short[] getTRC(int component) { public short[] getTRC(int component) {
short[] theTRC; return super.getTRC(toTag(component));
int theSignature;
switch (component) {
case REDCOMPONENT:
theSignature = ICC_Profile.icSigRedTRCTag;
break;
case GREENCOMPONENT:
theSignature = ICC_Profile.icSigGreenTRCTag;
break;
case BLUECOMPONENT:
theSignature = ICC_Profile.icSigBlueTRCTag;
break;
default:
throw new IllegalArgumentException("Must be Red, Green, or Blue");
} }
theTRC = super.getTRC(theSignature); /**
* Converts the {@code ICC_ProfileRGB} constant to the appropriate tag.
return theTRC; *
* @param component the {@code ICC_ProfileRGB} constant
* @return the tag signature
* @throws IllegalArgumentException if the component is not
* {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or
* {@code BLUECOMPONENT}
*/
private static int toTag(int component) {
return switch (component) {
case REDCOMPONENT -> ICC_Profile.icSigRedTRCTag;
case GREENCOMPONENT -> ICC_Profile.icSigGreenTRCTag;
case BLUECOMPONENT -> ICC_Profile.icSigBlueTRCTag;
default -> throw new IllegalArgumentException(
"Must be Red, Green, or Blue");
};
} }
} }

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2020, 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.
*
* 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.
*/
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.color.ICC_ProfileGray;
import java.awt.color.ProfileDataException;
/**
* @test
* @bug 8254370
* @summary Tests basic ICC_ProfileGray functionality
*/
public final class ICC_ProfileGrayTest {
public static void main(String[] args) throws Exception {
ICC_Profile csProfile = ICC_Profile.getInstance(ColorSpace.CS_GRAY);
ICC_Profile dataProfile = ICC_Profile.getInstance(csProfile.getData());
ICC_Profile stringProfile = ICC_Profile.getInstance("GRAY.pf");
test(csProfile);
test(dataProfile);
test(stringProfile);
}
private static void test(ICC_Profile profile) {
// Gray profile should be implemented as ICC_ProfileGray and includes
// the mediaWhitePointTag and grayTRCTag tags
if (!(profile instanceof ICC_ProfileGray)
|| profile.getData(ICC_Profile.icSigMediaWhitePointTag) == null
|| profile.getData(ICC_Profile.icSigGrayTRCTag) == null) {
throw new RuntimeException("Wrong profile: " + profile);
}
ICC_ProfileGray gray = (ICC_ProfileGray) profile;
int length = gray.getMediaWhitePoint().length;
if (length != 3) {
throw new RuntimeException("Wrong data length: " + length);
}
// if getTRC() throws an exception then getGamma() should work
boolean trc = false;
try {
gray.getTRC();
trc = true;
System.out.println("getTRC() works fine");
} catch (ProfileDataException ignore) {
gray.getGamma();
}
// if getGamma() throws an exception then getTRC() should work
boolean gamma = false;
try {
gray.getGamma();
gamma = true;
System.out.println("getGamma() works fine");
} catch (ProfileDataException ignore) {
gray.getTRC();
}
if (gamma == trc) {
// only one should work
throw new RuntimeException("Only one operation should work");
}
}
}

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2020, 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.
*
* 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.
*/
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.color.ICC_ProfileRGB;
import java.awt.color.ProfileDataException;
import java.util.Arrays;
/**
* @test
* @bug 8254370
* @summary Tests basic ICC_ProfileRGB functionality
*/
public final class ICC_ProfileRGBTest {
public static void main(String[] args) throws Exception {
ICC_Profile csProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
ICC_Profile dataProfile = ICC_Profile.getInstance(csProfile.getData());
ICC_Profile string2Profile = ICC_Profile.getInstance("sRGB.pf");
ICC_Profile string1Profile = ICC_Profile.getInstance("LINEAR_RGB.pf");
test(csProfile);
test(dataProfile);
test(string1Profile);
test(string2Profile);
}
private static void test(ICC_Profile profile) {
// RGB profile should be implemented as ICC_ProfileRGB and includes the
// redColorantTag, greenColorantTag, blueColorantTag, redTRCTag,
// greenTRCTag, blueTRCTag, mediaWhitePointTag tags
if (!(profile instanceof ICC_ProfileRGB)
|| profile.getData(ICC_Profile.icSigRedColorantTag) == null
|| profile.getData(ICC_Profile.icSigGreenColorantTag) == null
|| profile.getData(ICC_Profile.icSigBlueColorantTag) == null
|| profile.getData(ICC_Profile.icSigRedTRCTag) == null
|| profile.getData(ICC_Profile.icSigGreenTRCTag) == null
|| profile.getData(ICC_Profile.icSigBlueTRCTag) == null
|| profile.getData(ICC_Profile.icSigMediaWhitePointTag) == null)
{
throw new RuntimeException("Wrong profile: " + profile);
}
ICC_ProfileRGB rgb = (ICC_ProfileRGB) profile;
int length = rgb.getMediaWhitePoint().length;
if (length != 3) {
throw new RuntimeException("Wrong data length: " + length);
}
// if getTRC() throws an exception then getGamma() should work
boolean trc = false;
try {
rgb.getTRC(ICC_ProfileRGB.REDCOMPONENT);
rgb.getTRC(ICC_ProfileRGB.GREENCOMPONENT);
rgb.getTRC(ICC_ProfileRGB.BLUECOMPONENT);
trc = true;
System.out.println("getTRC() works fine");
} catch (ProfileDataException ignore) {
rgb.getGamma(ICC_ProfileRGB.REDCOMPONENT);
rgb.getGamma(ICC_ProfileRGB.GREENCOMPONENT);
rgb.getGamma(ICC_ProfileRGB.BLUECOMPONENT);
}
// if getGamma() throws an exception then getTRC() should work
boolean gamma = false;
try {
rgb.getGamma(ICC_ProfileRGB.REDCOMPONENT);
rgb.getGamma(ICC_ProfileRGB.GREENCOMPONENT);
rgb.getGamma(ICC_ProfileRGB.BLUECOMPONENT);
gamma = true;
System.out.println("getGamma() works fine");
} catch (ProfileDataException ignore) {
rgb.getTRC(ICC_ProfileRGB.REDCOMPONENT);
rgb.getTRC(ICC_ProfileRGB.GREENCOMPONENT);
rgb.getTRC(ICC_ProfileRGB.BLUECOMPONENT);
}
if (gamma == trc) {
// only one should work fine
throw new RuntimeException("Only one operation should work");
}
// IllegalArgumentException if the component is invalid
try {
rgb.getGamma(10);
throw new RuntimeException("IllegalArgumentException was expected");
} catch (IllegalArgumentException ignored) {}
try {
rgb.getGamma(-1);
throw new RuntimeException("IllegalArgumentException was expected");
} catch (IllegalArgumentException ignored) {}
try {
rgb.getTRC(10);
throw new RuntimeException("IllegalArgumentException was expected");
} catch (IllegalArgumentException ignored) {}
try {
rgb.getTRC(-1);
throw new RuntimeException("IllegalArgumentException was expected");
} catch (IllegalArgumentException ignored) {}
// Validates content of ICC_ProfileRGB.getMatrix()
float[][] matrix = rgb.getMatrix(); // current implementation
float[][] old = getMatrix(rgb); // old implementation
if (!Arrays.deepEquals(matrix, old)) {
System.err.println("Expected: " + Arrays.deepToString(old));
System.err.println("Actual: " + Arrays.deepToString(matrix));
throw new RuntimeException("Wrong matrix");
}
}
/**
* Old implementation of ICC_ProfileRGB.getMatrix().
*/
private static float[][] getMatrix(ICC_ProfileRGB profile) {
float[] tmpMatrix = getXYZTag(profile, ICC_Profile.icSigRedColorantTag);
float[][] theMatrix = new float[3][3];
theMatrix[0][0] = tmpMatrix[0];
theMatrix[1][0] = tmpMatrix[1];
theMatrix[2][0] = tmpMatrix[2];
tmpMatrix = getXYZTag(profile, ICC_Profile.icSigGreenColorantTag);
theMatrix[0][1] = tmpMatrix[0];
theMatrix[1][1] = tmpMatrix[1];
theMatrix[2][1] = tmpMatrix[2];
tmpMatrix = getXYZTag(profile, ICC_Profile.icSigBlueColorantTag);
theMatrix[0][2] = tmpMatrix[0];
theMatrix[1][2] = tmpMatrix[1];
theMatrix[2][2] = tmpMatrix[2];
return theMatrix;
}
private static float[] getXYZTag(ICC_ProfileRGB profile, int theTagSignature) {
byte[] theData = profile.getData(theTagSignature);
float[] theXYZNumber = new float[3];
for (int i1 = 0, i2 = profile.icXYZNumberX; i1 < 3; i1++, i2 += 4) {
int theS15Fixed16 = intFromBigEndian(theData, i2);
theXYZNumber [i1] = theS15Fixed16 / 65536.0f;
}
return theXYZNumber;
}
static int intFromBigEndian(byte[] array, int index) {
return (((array[index] & 0xff) << 24) |
((array[index+1] & 0xff) << 16) |
((array[index+2] & 0xff) << 8) |
(array[index+3] & 0xff));
}
}