diff --git a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java index 023b376d73d..a32cb925e5c 100644 --- a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java +++ b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -811,7 +811,7 @@ private BufferedImage nonICCBIFilter(BufferedImage src, } float[] srcMinVal = new float[iccSrcNumComp]; float[] srcInvDiffMinMax = new float[iccSrcNumComp]; - for (int i = 0; i < srcNumComp; i++) { + for (int i = 0; i < iccSrcNumComp; i++) { srcMinVal[i] = cs.getMinValue(i); srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); } @@ -825,7 +825,7 @@ private BufferedImage nonICCBIFilter(BufferedImage src, } float[] dstMinVal = new float[iccDstNumComp]; float[] dstDiffMinMax = new float[iccDstNumComp]; - for (int i = 0; i < dstNumComp; i++) { + for (int i = 0; i < iccDstNumComp; i++) { dstMinVal[i] = cs.getMinValue(i); dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum; } @@ -878,7 +878,7 @@ private BufferedImage nonICCBIFilter(BufferedImage src, dstDiffMinMax[i] + dstMinVal[i]; } if (nonICCDst) { - color = srcColorSpace.fromCIEXYZ(dstColor); + color = dstColorSpace.fromCIEXYZ(dstColor); for (int i = 0; i < dstNumComp; i++) { dstColor[i] = color[i]; } diff --git a/test/jdk/java/awt/color/NonICCFilterTest.java b/test/jdk/java/awt/color/NonICCFilterTest.java new file mode 100644 index 00000000000..1c7b2f8d486 --- /dev/null +++ b/test/jdk/java/awt/color/NonICCFilterTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024, 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; +import java.awt.GradientPaint; +import java.awt.Graphics2D; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.WritableRaster; + +/* + * @test + * @bug 8316497 + * @summary Verifies Color filter on non-ICC profile + */ +public final class NonICCFilterTest { + private static final int WIDTH = 100; + private static final int HEIGHT = 100; + + private enum ColorSpaceSelector { + GRAY, + RGB, + PYCC, + WRAPPED_GRAY, + WRAPPED_RGB, + WRAPPED_PYCC + } + + private static final class TestColorSpace extends ColorSpace { + + private final ColorSpace cs; + + TestColorSpace(ColorSpace cs) { + super(cs.getType(), cs.getNumComponents()); + this.cs = cs; + } + + @Override + public float[] toRGB(float[] colorvalue) { + return cs.toRGB(colorvalue); + } + + @Override + public float[] fromRGB(float[] rgbvalue) { + return cs.fromRGB(rgbvalue); + } + + @Override + public float[] toCIEXYZ(float[] colorvalue) { + return cs.toCIEXYZ(colorvalue); + } + + @Override + public float[] fromCIEXYZ(float[] xyzvalue) { + return cs.fromCIEXYZ(xyzvalue); + } + } + + private static BufferedImage createTestImage(final ColorSpace cs) { + ComponentColorModel cm = new ComponentColorModel(cs, false, false, + Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + WritableRaster raster = cm.createCompatibleWritableRaster(WIDTH, HEIGHT); + BufferedImage img = new BufferedImage(cm, raster, false, null); + + Graphics2D g = img.createGraphics(); + GradientPaint gp = new GradientPaint(0, 0, Color.GREEN, + raster.getWidth(), raster.getHeight(), Color.BLUE); + g.setPaint(gp); + g.fillRect(0, 0, raster.getWidth(), raster.getHeight()); + g.dispose(); + + return img; + } + + private static ColorSpace createCS(ColorSpaceSelector selector) { + switch (selector) { + case GRAY: return ColorSpace.getInstance(ColorSpace.CS_GRAY); + case WRAPPED_GRAY: return new TestColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY)); + + case RGB: return ColorSpace.getInstance(ColorSpace.CS_sRGB); + case WRAPPED_RGB: return new TestColorSpace(ColorSpace.getInstance(ColorSpace.CS_sRGB)); + + case PYCC: return ColorSpace.getInstance(ColorSpace.CS_PYCC); + case WRAPPED_PYCC: return new TestColorSpace(ColorSpace.getInstance(ColorSpace.CS_PYCC)); + + default: throw new IllegalArgumentException(); + } + } + + private static boolean areImagesEqual(BufferedImage destTest, BufferedImage destGold) { + for (int x = 0; x < destTest.getWidth(); x++) { + for (int y = 0; y < destTest.getHeight(); y++) { + int rgb1 = destTest.getRGB(x, y); + int rgb2 = destGold.getRGB(x, y); + if (rgb1 != rgb2) { + System.err.println("x = " + x + ", y = " + y); + System.err.println("rgb1 = " + Integer.toHexString(rgb1)); + System.err.println("rgb2 = " + Integer.toHexString(rgb2)); + return false; + } + } + } + return true; + } + + public static void main(String[] args) { + BufferedImage srcTest = createTestImage(createCS(ColorSpaceSelector.WRAPPED_GRAY)); + BufferedImage destTest = createTestImage(createCS(ColorSpaceSelector.WRAPPED_RGB)); + + BufferedImage srcGold = createTestImage(createCS(ColorSpaceSelector.GRAY)); + BufferedImage destGold = createTestImage(createCS(ColorSpaceSelector.RGB)); + + ColorConvertOp gold = new ColorConvertOp(createCS(ColorSpaceSelector.PYCC), null); + gold.filter(srcTest, destTest); + gold.filter(srcGold, destGold); + + if (!areImagesEqual(destTest, destGold)) { + throw new RuntimeException("ICC test failed"); + } + + ColorConvertOp test = new ColorConvertOp(createCS(ColorSpaceSelector.WRAPPED_PYCC), null); + test.filter(srcTest, destTest); + test.filter(srcGold, destGold); + + if (!areImagesEqual(destTest, destGold)) { + throw new RuntimeException("Wrapper test failed"); + } + } +}