8295430: Use cmsDoTransformLineStride instead of cmsDoTransform in the loop

Reviewed-by: prr
This commit is contained in:
Sergey Bylokhov 2022-11-10 06:18:03 +00:00
parent f0a6e71e4d
commit 78a08a0f21
6 changed files with 344 additions and 38 deletions

View File

@ -140,7 +140,6 @@ final class LCMS implements PCMM {
static native void colorConvert(long trans, int width, int height,
int srcOffset, int srcNextRowOffset,
int dstOffset, int dstNextRowOffset,
boolean srcAtOnce, boolean dstAtOnce,
Object srcData, Object dstData,
int srcType, int dstType);

View File

@ -79,11 +79,6 @@ final class LCMSImageLayout {
private int nextPixelOffset;
int offset;
/* This flag indicates whether the image can be processed
* at once by doTransfrom() native call. Otherwise, the
* image is processed scan by scan.
*/
boolean imageAtOnce = false;
Object dataArray;
private int dataArrayLength; /* in bytes */
@ -234,10 +229,6 @@ final class LCMSImageLayout {
l.dataArray = intRaster.getDataStorage();
l.dataArrayLength = 4 * intRaster.getDataStorage().length;
l.dataType = DT_INT;
if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
l.imageAtOnce = true;
}
} while (false);
break;
@ -254,9 +245,6 @@ final class LCMSImageLayout {
l.dataArray = byteRaster.getDataStorage();
l.dataArrayLength = byteRaster.getDataStorage().length;
l.dataType = DT_BYTE;
if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
l.imageAtOnce = true;
}
} while (false);
break;
@ -271,10 +259,6 @@ final class LCMSImageLayout {
l.offset = byteRaster.getDataOffset(0);
l.dataArray = byteRaster.getDataStorage();
l.dataType = DT_BYTE;
if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
l.imageAtOnce = true;
}
} while (false);
break;
@ -289,10 +273,6 @@ final class LCMSImageLayout {
l.dataArray = shortRaster.getDataStorage();
l.dataArrayLength = 2 * shortRaster.getDataStorage().length;
l.dataType = DT_SHORT;
if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
l.imageAtOnce = true;
}
} while (false);
break;
default:
@ -409,10 +389,6 @@ final class LCMSImageLayout {
l.width = br.getWidth();
l.height = br.getHeight();
if (l.nextRowOffset == l.width * br.getPixelStride()) {
l.imageAtOnce = true;
}
return l;
}
return null;

View File

@ -133,7 +133,6 @@ final class LCMSTransform implements ColorTransform {
}
LCMS.colorConvert(tfm.ID, in.width, in.height, in.offset,
in.nextRowOffset, out.offset, out.nextRowOffset,
in.imageAtOnce, out.imageAtOnce,
in.dataArray, out.dataArray,
in.dataType, out.dataType);
Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID"

View File

@ -522,7 +522,6 @@ static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data,
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
(JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset,
jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset,
jboolean srcAtOnce, jboolean dstAtOnce,
jobject srcData, jobject dstData, jint srcDType, jint dstDType)
{
cmsHTRANSFORM sTrans = jlong_to_ptr(ID);
@ -548,18 +547,11 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
return;
}
char *inputRow = (char *) inputBuffer + srcOffset;
char *outputRow = (char *) outputBuffer + dstOffset;
char *input = (char *) inputBuffer + srcOffset;
char *output = (char *) outputBuffer + dstOffset;
if (srcAtOnce && dstAtOnce) {
cmsDoTransform(sTrans, inputRow, outputRow, width * height);
} else {
for (int i = 0; i < height; i++) {
cmsDoTransform(sTrans, inputRow, outputRow, width);
inputRow += srcNextRowOffset;
outputRow += dstNextRowOffset;
}
}
cmsDoTransformLineStride(sTrans, input, output, width, height,
srcNextRowOffset, dstNextRowOffset, 0, 0);
releaseILData(env, inputBuffer, srcDType, srcData, JNI_ABORT);
releaseILData(env, outputBuffer, dstDType, dstData, 0);

View File

@ -0,0 +1,200 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2014, 2019, 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.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import javax.imageio.ImageIO;
import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY;
import static java.awt.image.BufferedImage.TYPE_BYTE_GRAY;
import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
import static java.awt.image.BufferedImage.TYPE_INT_BGR;
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_555_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_565_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY;
/**
* @test
* @bug 8295430
* @summary Tests various conversions from/to custom 3BYTE_BGR image
*/
public final class FilterImageLineGap {
private static final int[] TYPES = {
TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR,
TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE,
TYPE_USHORT_565_RGB, TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY,
TYPE_USHORT_GRAY, TYPE_BYTE_BINARY, TYPE_BYTE_INDEXED
};
private static final int[] CSS = {
ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB,
ColorSpace.CS_PYCC, ColorSpace.CS_sRGB
};
private static final int W = 511;
private static final int H = 255;
public static void main(String[] args) throws Exception {
for (int fromIndex : CSS) {
for (int toIndex : CSS) {
customToCustom(fromIndex, toIndex);
customToAny(fromIndex, toIndex);
anytoCustom(fromIndex, toIndex);
}
}
}
private static void customToCustom(int fromIndex, int toIndex)
throws Exception
{
ColorSpace toCS = ColorSpace.getInstance(fromIndex);
ColorSpace fromCS = ColorSpace.getInstance(toIndex);
ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null);
BufferedImage src = makeCustom3BYTE_BGR();
BufferedImage dst = makeCustom3BYTE_BGR();
BufferedImage srcGold = new BufferedImage(W, H, TYPE_3BYTE_BGR);
BufferedImage dstGold = new BufferedImage(W, H, TYPE_3BYTE_BGR);
fill(src);
fill(srcGold);
op.filter(src, dst);
op.filter(srcGold, dstGold);
// validate images
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) {
ImageIO.write(dst, "png", new File("custom.png"));
ImageIO.write(dstGold, "png", new File("gold.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
private static void customToAny(int fromIndex, int toIndex) throws Exception
{
ColorSpace toCS = ColorSpace.getInstance(fromIndex);
ColorSpace fromCS = ColorSpace.getInstance(toIndex);
ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null);
for (int type : TYPES) {
BufferedImage src = makeCustom3BYTE_BGR();
BufferedImage dst = new BufferedImage(W, H, type);
BufferedImage srcGold = new BufferedImage(W, H, TYPE_3BYTE_BGR);
BufferedImage dstGold = new BufferedImage(W, H, type);
fill(src);
fill(srcGold);
op.filter(src, dst);
op.filter(srcGold, dstGold);
// validate images
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) {
ImageIO.write(dst, "png", new File("custom.png"));
ImageIO.write(dstGold, "png", new File("gold.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
}
private static void anytoCustom(int fromIndex, int toIndex) throws Exception
{
ColorSpace toCS = ColorSpace.getInstance(fromIndex);
ColorSpace fromCS = ColorSpace.getInstance(toIndex);
ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null);
for (int type : TYPES) {
BufferedImage src = new BufferedImage(W, H, type);
BufferedImage dst = makeCustom3BYTE_BGR();
BufferedImage srcGold = new BufferedImage(W, H, type);
BufferedImage dstGold = new BufferedImage(W, H, TYPE_3BYTE_BGR);
fill(src);
fill(srcGold);
op.filter(src, dst);
op.filter(srcGold, dstGold);
// validate images
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) {
ImageIO.write(dst, "png", new File("custom.png"));
ImageIO.write(dstGold, "png", new File("gold.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
}
/**
* Returns the custom buffered image, which mostly identical to
* BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride.
* This means that the raster will have gaps, between the rows.
*/
private static BufferedImage makeCustom3BYTE_BGR() {
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8};
int[] bOffs = {2, 1, 0};
ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false,
Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(
DataBuffer.TYPE_BYTE, W, H, W * 3 + 2, 3, bOffs, null);
return new BufferedImage(colorModel, raster, true, null);
}
private static void fill(Image image) {
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setComposite(AlphaComposite.Src);
for (int i = 0; i < image.getHeight(null); ++i) {
graphics.setColor(new Color(i, 0, 255 - i));
graphics.fillRect(0, i, image.getWidth(null), 1);
}
graphics.dispose();
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2014, 2019, 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.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import javax.imageio.ImageIO;
import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY;
import static java.awt.image.BufferedImage.TYPE_BYTE_GRAY;
import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED;
import static java.awt.image.BufferedImage.TYPE_CUSTOM;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
import static java.awt.image.BufferedImage.TYPE_INT_BGR;
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_555_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_565_RGB;
import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY;
/**
* @test
* @bug 8295430
* @summary Compare the SRGB->SRGB and SRGB->CUSTOM conversions when CUSTOM=SRGB
*/
public final class ValidateNoopFilter {
private static final int[] TYPES = {
TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR,
TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE,
TYPE_USHORT_565_RGB, TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY,
TYPE_USHORT_GRAY, TYPE_BYTE_BINARY, TYPE_BYTE_INDEXED, TYPE_CUSTOM
};
private static final int W = 511;
private static final int H = 255;
public static void main(String[] args) throws Exception {
byte[] data = ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData();
ColorSpace custom = new ICC_ColorSpace(ICC_Profile.getInstance(data));
ColorSpace srgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorConvertOp opCustom = new ColorConvertOp(srgb, custom, null);
ColorConvertOp opGold = new ColorConvertOp(srgb, srgb, null);
for (int type : TYPES) {
BufferedImage src = makeBi(type);
BufferedImage dst = makeBi(type);
BufferedImage dstGold = makeBi(type);
fill(src);
opCustom.filter(src, dst);
opGold.filter(src, dstGold);
// validate images
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) {
ImageIO.write(dst, "png", new File("custom.png"));
ImageIO.write(dstGold, "png", new File("gold.png"));
throw new RuntimeException("Test failed.");
}
}
}
}
}
private static BufferedImage makeBi(int type) {
if (type == TYPE_CUSTOM) {
return makeCustom3BYTE_BGR();
} else {
return new BufferedImage(W, H, type);
}
}
/**
* Returns the custom buffered image, which mostly identical to
* BufferedImage.(w,h,TYPE_3BYTE_BGR), but uses the bigger scanlineStride.
* This means that the raster will have gaps, between the rows.
*/
private static BufferedImage makeCustom3BYTE_BGR() {
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8};
int[] bOffs = {2, 1, 0};
ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false,
Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(
DataBuffer.TYPE_BYTE, W, H, W * 3 + 2, 3, bOffs, null);
return new BufferedImage(colorModel, raster, true, null);
}
private static void fill(Image image) {
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setComposite(AlphaComposite.Src);
for (int i = 0; i < image.getHeight(null); ++i) {
graphics.setColor(new Color(i, 0, 255 - i));
graphics.fillRect(0, i, image.getWidth(null), 1);
}
graphics.dispose();
}
}