8012229: [lcms] Improve performance of color conversion for images with alpha channel
Reviewed-by: azvegint
This commit is contained in:
parent
cb70ab0cb9
commit
16acfafb6b
src/java.desktop/share
test/jdk/sun/java2d/cmm/ColorConvertOp
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, 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
|
||||
@ -22,19 +22,20 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.cmm.lcms;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.ComponentSampleModel;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import sun.awt.image.ByteComponentRaster;
|
||||
import sun.awt.image.ShortComponentRaster;
|
||||
import sun.awt.image.IntegerComponentRaster;
|
||||
|
||||
class LCMSImageLayout {
|
||||
import sun.awt.image.ByteComponentRaster;
|
||||
import sun.awt.image.IntegerComponentRaster;
|
||||
import sun.awt.image.ShortComponentRaster;
|
||||
|
||||
final class LCMSImageLayout {
|
||||
|
||||
public static int BYTES_SH(int x) {
|
||||
return x;
|
||||
@ -195,7 +196,12 @@ class LCMSImageLayout {
|
||||
* has to be supported.
|
||||
*/
|
||||
ColorModel cm = image.getColorModel();
|
||||
if (cm instanceof ComponentColorModel) {
|
||||
/* todo
|
||||
* Our generic code for rasters does not support alpha channels,
|
||||
* but it would be good to improve it when it is used from here.
|
||||
* See "createImageLayout(image.getRaster())" below.
|
||||
*/
|
||||
if (!cm.hasAlpha() && cm instanceof ComponentColorModel) {
|
||||
ComponentColorModel ccm = (ComponentColorModel) cm;
|
||||
|
||||
// verify whether the component size is fine
|
||||
|
@ -49,7 +49,7 @@ import sun.java2d.cmm.ColorTransform;
|
||||
|
||||
import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
|
||||
|
||||
public class LCMSTransform implements ColorTransform {
|
||||
final class LCMSTransform implements ColorTransform {
|
||||
long ID;
|
||||
private int inFormatter = 0;
|
||||
private boolean isInIntPacked = false;
|
||||
@ -149,10 +149,26 @@ public class LCMSTransform implements ColorTransform {
|
||||
LCMS.colorConvert(this, in, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if lcms may supports this format directly.
|
||||
*/
|
||||
private static boolean isLCMSSupport(BufferedImage src, BufferedImage dst) {
|
||||
if (!dst.getColorModel().hasAlpha()) {
|
||||
return true;
|
||||
}
|
||||
// lcms as of now does not support pre-alpha
|
||||
if (src.isAlphaPremultiplied() || dst.isAlphaPremultiplied()) {
|
||||
return false;
|
||||
}
|
||||
// lcms does not set correct alpha for transparent dst if src is opaque
|
||||
// is it feature or bug?
|
||||
return dst.getColorModel().hasAlpha() == src.getColorModel().hasAlpha();
|
||||
}
|
||||
|
||||
public void colorConvert(BufferedImage src, BufferedImage dst) {
|
||||
LCMSImageLayout srcIL, dstIL;
|
||||
try {
|
||||
if (!dst.getColorModel().hasAlpha()) {
|
||||
if (isLCMSSupport(src, dst)) {
|
||||
dstIL = LCMSImageLayout.createImageLayout(dst);
|
||||
|
||||
if (dstIL != null) {
|
||||
|
@ -190,7 +190,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
|
||||
}
|
||||
|
||||
sTrans = cmsCreateMultiprofileTransform(iccArray, j,
|
||||
inFormatter, outFormatter, renderType, 0);
|
||||
inFormatter, outFormatter, renderType, cmsFLAGS_COPY_ALPHA);
|
||||
|
||||
(*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2021, 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
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4405224
|
||||
* @bug 4405224 8012229
|
||||
* @summary Test color conversion for images with alpha
|
||||
*/
|
||||
|
||||
@ -76,9 +76,10 @@ public class ColCvtAlpha {
|
||||
op.filter(src, dst);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (((dst.getRGB(0, i) >> 24) & 0xff) != 128) {
|
||||
int rgb = (dst.getRGB(0, i) >> 24) & 0xff;
|
||||
if (rgb != 128) {
|
||||
throw new RuntimeException(
|
||||
"Incorrect destination alpha value.");
|
||||
"Incorrect destination alpha value: " + rgb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.Graphics2D;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorConvertOp;
|
||||
|
||||
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 8012229
|
||||
* @summary one more test to check the alpha channel
|
||||
*/
|
||||
public final class ColCvtAlphaDifferentSrcDst {
|
||||
|
||||
private static final int WIDTH = 256;
|
||||
private static final int HEIGHT = 256;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
differentToOpaqueDst();
|
||||
differentToTransparentDst(TYPE_INT_ARGB);
|
||||
differentToTransparentDst(TYPE_4BYTE_ABGR);
|
||||
differentToTransparentDst(TYPE_INT_ARGB_PRE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Various types of source images transform to the opaque destination, the
|
||||
* result should be the same.
|
||||
*/
|
||||
private static void differentToOpaqueDst() {
|
||||
opaqueDst(TYPE_INT_ARGB, TYPE_INT_RGB);
|
||||
opaqueDst(TYPE_INT_ARGB, TYPE_INT_BGR);
|
||||
opaqueDst(TYPE_4BYTE_ABGR, TYPE_INT_BGR);
|
||||
|
||||
// It is unclear how to hangle pre colors in the opaque DST
|
||||
//opaqueDst(TYPE_INT_ARGB_PRE, TYPE_4BYTE_ABGR_PRE);
|
||||
//opaqueDst(TYPE_4BYTE_ABGR_PRE, TYPE_INT_BGR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transparent types of source images transform to the transparent
|
||||
* destination, the alpha channel should be the same in src/dst.
|
||||
*/
|
||||
private static void differentToTransparentDst(int typeDst) {
|
||||
transparentDst(TYPE_INT_RGB, typeDst);
|
||||
transparentDst(TYPE_INT_ARGB, typeDst);
|
||||
transparentDst(TYPE_INT_ARGB_PRE, typeDst);
|
||||
transparentDst(TYPE_INT_BGR, typeDst);
|
||||
transparentDst(TYPE_3BYTE_BGR, typeDst);
|
||||
transparentDst(TYPE_4BYTE_ABGR, typeDst);
|
||||
transparentDst(TYPE_4BYTE_ABGR_PRE, typeDst);
|
||||
transparentDst(TYPE_USHORT_565_RGB, typeDst);
|
||||
transparentDst(TYPE_USHORT_555_RGB, typeDst);
|
||||
transparentDst(TYPE_BYTE_GRAY, typeDst);
|
||||
transparentDst(TYPE_USHORT_GRAY, typeDst);
|
||||
transparentDst(TYPE_BYTE_BINARY, typeDst);
|
||||
transparentDst(TYPE_BYTE_INDEXED, typeDst);
|
||||
}
|
||||
|
||||
private static void opaqueDst(int transparent, int opaque) {
|
||||
ColorSpace to = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
|
||||
ColorSpace from = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
ColorConvertOp op = new ColorConvertOp(from, to, null);
|
||||
// Source data
|
||||
BufferedImage timgSrc = createSrc(transparent);
|
||||
BufferedImage oimgSrc = createSrc(opaque);
|
||||
|
||||
// Destination data
|
||||
BufferedImage timgDst = createDst(TYPE_INT_RGB);
|
||||
BufferedImage oimgDst = createDst(TYPE_INT_RGB);
|
||||
|
||||
op.filter(timgSrc, timgDst);
|
||||
op.filter(oimgSrc, oimgDst);
|
||||
|
||||
validate(timgDst, oimgDst, false);
|
||||
}
|
||||
|
||||
private static void transparentDst(int typeSrc, int typeDst) {
|
||||
ColorSpace to = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
|
||||
ColorSpace from = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
ColorConvertOp op = new ColorConvertOp(from, to, null);
|
||||
|
||||
BufferedImage src = createSrc(typeSrc);
|
||||
BufferedImage dst = createDst(typeDst);
|
||||
|
||||
op.filter(src, dst);
|
||||
|
||||
validate(src, dst, true);
|
||||
}
|
||||
|
||||
private static void validate(BufferedImage img1, BufferedImage img2,
|
||||
boolean alphaOnly) {
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
for (int j = 0; j < HEIGHT; j++) {
|
||||
int rgb1 = img1.getRGB(i, j);
|
||||
int rgb2 = img2.getRGB(i, j);
|
||||
if (alphaOnly) {
|
||||
rgb1 |= 0x00FFFFFF;
|
||||
rgb2 |= 0x00FFFFFF;
|
||||
}
|
||||
if (rgb1 != rgb2) {
|
||||
System.out.println("rgb1 = " + Integer.toHexString(rgb1));
|
||||
System.out.println("rgb2 = " + Integer.toHexString(rgb2));
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferedImage createSrc(int type) {
|
||||
BufferedImage img = new BufferedImage(WIDTH, HEIGHT, type);
|
||||
fill(img);
|
||||
return img;
|
||||
}
|
||||
|
||||
private static BufferedImage createDst(int type) {
|
||||
BufferedImage img = new BufferedImage(WIDTH, HEIGHT, type);
|
||||
|
||||
Graphics2D g = img.createGraphics();
|
||||
g.setComposite(AlphaComposite.Clear);
|
||||
g.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
g.dispose();
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
private static void fill(BufferedImage image) {
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
for (int j = 0; j < HEIGHT; j++) {
|
||||
image.setRGB(i, j,
|
||||
(i << 24) | (i << 16) | (j << 8) | ((i + j) >> 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user