<TEMP> 8353542: No native raster data for common pixel-interleaved BufferedImages

This duplicates my OpenJDK PR, wait till it's resolved in upstream.
This commit is contained in:
Nikita Gubarkov
2025-04-03 16:16:51 +02:00
committed by Vitaly Provodin
parent 5e7e7ab7c0
commit 49402a700e
2 changed files with 228 additions and 72 deletions

View File

@@ -95,15 +95,15 @@ public class BufImgSurfaceData extends SurfaceData {
sData = createDataIC(bufImg, SurfaceType.IntArgbPre, scaleX, scaleY);
break;
case BufferedImage.TYPE_3BYTE_BGR:
sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2,
sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr,
scaleX, scaleY);
break;
case BufferedImage.TYPE_4BYTE_ABGR:
sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3,
sData = createDataBC(bufImg, SurfaceType.FourByteAbgr,
scaleX, scaleY);
break;
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3,
sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre,
scaleX, scaleY);
break;
case BufferedImage.TYPE_USHORT_565_RGB:
@@ -134,11 +134,11 @@ public class BufImgSurfaceData extends SurfaceData {
default:
throw new InternalError("Unrecognized transparency");
}
sData = createDataBC(bufImg, sType, 0, scaleX, scaleY);
sData = createDataBC(bufImg, sType, scaleX, scaleY);
}
break;
case BufferedImage.TYPE_BYTE_GRAY:
sData = createDataBC(bufImg, SurfaceType.ByteGray, 0,
sData = createDataBC(bufImg, SurfaceType.ByteGray,
scaleX, scaleY);
break;
case BufferedImage.TYPE_USHORT_GRAY:
@@ -170,13 +170,10 @@ public class BufImgSurfaceData extends SurfaceData {
{
Raster raster = bufImg.getRaster();
int numBands = raster.getNumBands();
if (raster instanceof IntegerComponentRaster &&
raster.getNumDataElements() == 1 &&
((IntegerComponentRaster)raster).getPixelStride() == 1)
{
if (raster instanceof IntegerComponentRaster icr) {
SurfaceType sType = SurfaceType.AnyInt;
if (cm instanceof DirectColorModel) {
DirectColorModel dcm = (DirectColorModel) cm;
if (cm instanceof DirectColorModel dcm &&
icr.getNumDataElements() == 1 && icr.getPixelStride() == 1) {
int aMask = dcm.getAlphaMask();
int rMask = dcm.getRedMask();
int gMask = dcm.getGreenMask();
@@ -201,48 +198,58 @@ public class BufImgSurfaceData extends SurfaceData {
}
sData = createDataIC(bufImg, sType, scaleX, scaleY);
break;
} else if (raster instanceof ShortComponentRaster &&
raster.getNumDataElements() == 1 &&
((ShortComponentRaster)raster).getPixelStride() == 1)
{
} else if (raster instanceof ShortComponentRaster scr) {
SurfaceType sType = SurfaceType.AnyShort;
IndexColorModel icm = null;
if (cm instanceof DirectColorModel) {
DirectColorModel dcm = (DirectColorModel) cm;
int aMask = dcm.getAlphaMask();
int rMask = dcm.getRedMask();
int gMask = dcm.getGreenMask();
int bMask = dcm.getBlueMask();
if (numBands == 3 &&
aMask == 0 &&
rMask == DCM_555X_RED_MASK &&
gMask == DCM_555X_GREEN_MASK &&
bMask == DCM_555X_BLUE_MASK)
{
sType = SurfaceType.Ushort555Rgbx;
} else
if (numBands == 4 &&
aMask == DCM_4444_ALPHA_MASK &&
rMask == DCM_4444_RED_MASK &&
gMask == DCM_4444_GREEN_MASK &&
bMask == DCM_4444_BLUE_MASK)
{
sType = SurfaceType.Ushort4444Argb;
}
} else if (cm instanceof IndexColorModel) {
icm = (IndexColorModel)cm;
if (icm.getPixelSize() == 12) {
if (isOpaqueGray(icm)) {
sType = SurfaceType.Index12Gray;
} else {
sType = SurfaceType.UshortIndexed;
if (scr.getNumDataElements() == 1 && scr.getPixelStride() == 1) {
if (cm instanceof DirectColorModel dcm) {
int aMask = dcm.getAlphaMask();
int rMask = dcm.getRedMask();
int gMask = dcm.getGreenMask();
int bMask = dcm.getBlueMask();
if (numBands == 3 &&
aMask == 0 &&
rMask == DCM_555X_RED_MASK &&
gMask == DCM_555X_GREEN_MASK &&
bMask == DCM_555X_BLUE_MASK)
{
sType = SurfaceType.Ushort555Rgbx;
} else
if (numBands == 4 &&
aMask == DCM_4444_ALPHA_MASK &&
rMask == DCM_4444_RED_MASK &&
gMask == DCM_4444_GREEN_MASK &&
bMask == DCM_4444_BLUE_MASK)
{
sType = SurfaceType.Ushort4444Argb;
}
} else if (cm instanceof IndexColorModel) {
icm = (IndexColorModel)cm;
if (icm.getPixelSize() == 12) {
if (isOpaqueGray(icm)) {
sType = SurfaceType.Index12Gray;
} else {
sType = SurfaceType.UshortIndexed;
}
} else {
icm = null;
}
} else {
icm = null;
}
}
sData = createDataSC(bufImg, sType, icm, scaleX, scaleY);
break;
} else if (raster instanceof ByteComponentRaster bcr) {
SurfaceType sType = SurfaceType.AnyByte;
if (bcr.getPixelStride() == 4) {
sType = SurfaceType.Any4Byte;
} else if (bcr.getPixelStride() == 3) {
sType = SurfaceType.Any3Byte;
}
sData = createDataBC(bufImg, sType, scaleX, scaleY);
break;
} else if (raster instanceof BytePackedRaster) {
sData = createDataBP(bufImg, SurfaceType.AnyByteBinary, scaleX, scaleY);
break;
}
sData = new BufImgSurfaceData(raster.getDataBuffer(), bufImg,
SurfaceType.Custom,
@@ -258,6 +265,23 @@ public class BufImgSurfaceData extends SurfaceData {
throw new InternalError("SurfaceData not implemented for Raster/CM");
}
/**
* Calculate pixel-aligned data offset for interleaved raster
* from the array of data offsets for each band and pixel stride.
* Returns -1 for non-pixel interleaved configurations.
*/
private static int getPixelDataOffset(int[] dataOffsets, int pixelStride) {
int min = dataOffsets[0], max = min;
for (int i = 1; i < dataOffsets.length; i++) {
int offset = dataOffsets[i];
if (offset < min) min = offset;
else if (offset > max) max = offset;
}
min = (min / pixelStride) * pixelStride;
if (max - min >= pixelStride) return -1;
return min;
}
public static SurfaceData createDataIC(BufferedImage bImg,
SurfaceType sType,
double scaleX,
@@ -268,13 +292,16 @@ public class BufImgSurfaceData extends SurfaceData {
BufImgSurfaceData bisd =
new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType,
scaleX, scaleY);
bisd.initRaster(icRaster.getDataStorage(),
icRaster.getDataOffset(0) * 4, 0,
icRaster.getWidth(),
icRaster.getHeight(),
icRaster.getPixelStride() * 4,
icRaster.getScanlineStride() * 4,
null);
int offset = getPixelDataOffset(icRaster.getDataOffsets(), icRaster.getPixelStride());
if (offset != -1) {
bisd.initRaster(icRaster.getDataStorage(),
offset * 4, 0,
icRaster.getWidth(),
icRaster.getHeight(),
icRaster.getPixelStride() * 4,
icRaster.getScanlineStride() * 4,
null);
}
return bisd;
}
@@ -288,19 +315,21 @@ public class BufImgSurfaceData extends SurfaceData {
BufImgSurfaceData bisd =
new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType,
scaleX, scaleY);
bisd.initRaster(scRaster.getDataStorage(),
scRaster.getDataOffset(0) * 2, 0,
scRaster.getWidth(),
scRaster.getHeight(),
scRaster.getPixelStride() * 2,
scRaster.getScanlineStride() * 2,
icm);
int offset = getPixelDataOffset(scRaster.getDataOffsets(), scRaster.getPixelStride());
if (offset != -1) {
bisd.initRaster(scRaster.getDataStorage(),
offset * 2, 0,
scRaster.getWidth(),
scRaster.getHeight(),
scRaster.getPixelStride() * 2,
scRaster.getScanlineStride() * 2,
icm);
}
return bisd;
}
public static SurfaceData createDataBC(BufferedImage bImg,
SurfaceType sType,
int primaryBank,
double scaleX, double scaleY)
{
ByteComponentRaster bcRaster =
@@ -308,17 +337,20 @@ public class BufImgSurfaceData extends SurfaceData {
BufImgSurfaceData bisd =
new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType,
scaleX, scaleY);
ColorModel cm = bImg.getColorModel();
IndexColorModel icm = ((cm instanceof IndexColorModel)
? (IndexColorModel) cm
: null);
bisd.initRaster(bcRaster.getDataStorage(),
bcRaster.getDataOffset(primaryBank), 0,
bcRaster.getWidth(),
bcRaster.getHeight(),
bcRaster.getPixelStride(),
bcRaster.getScanlineStride(),
icm);
int offset = getPixelDataOffset(bcRaster.getDataOffsets(), bcRaster.getPixelStride());
if (offset != -1) {
ColorModel cm = bImg.getColorModel();
IndexColorModel icm = ((cm instanceof IndexColorModel)
? (IndexColorModel) cm
: null);
bisd.initRaster(bcRaster.getDataStorage(),
offset, 0,
bcRaster.getWidth(),
bcRaster.getHeight(),
bcRaster.getPixelStride(),
bcRaster.getScanlineStride(),
icm);
}
return bisd;
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2016, 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 sun.awt.image.SurfaceManager;
import sun.java2d.SurfaceData;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.util.Objects;
import static java.awt.image.BufferedImage.*;
import static java.awt.image.DataBuffer.*;
/*
* @test
* @bug 8353542
* @modules java.desktop/sun.java2d java.desktop/sun.awt.image
* @summary Test initialization of native raster data.
*/
public class NativeRasterDataTest {
public static void main(String[] args) {
// Test built-in types.
check(TYPE_INT_RGB);
check(TYPE_INT_ARGB);
check(TYPE_INT_ARGB_PRE);
check(TYPE_INT_BGR);
check(TYPE_3BYTE_BGR);
check(TYPE_4BYTE_ABGR);
check(TYPE_4BYTE_ABGR_PRE);
check(TYPE_USHORT_565_RGB);
check(TYPE_USHORT_555_RGB);
check(TYPE_BYTE_GRAY);
check(TYPE_USHORT_GRAY);
// Test INT_DCM.
ColorSpace srgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
check(new DirectColorModel(srgb, 32, 0xff0000, 0xff00, 0xff, 0xff000000, true, TYPE_INT), null);
check(new DirectColorModel(srgb, 32, 0xff, 0xff00, 0xff0000, 0xff000000, true, TYPE_INT), null);
check(new DirectColorModel(srgb, 32, 0xff000000, 0xff0000, 0xff00, 0xff, true, TYPE_INT), null);
check(new DirectColorModel(srgb, 32, 0xff00, 0xff0000, 0xff000000, 0xff, true, TYPE_INT), null);
check(new DirectColorModel(srgb, 24, 0xff0000, 0xff00, 0xff, 0, false, TYPE_INT), null);
check(new DirectColorModel(srgb, 24, 0xff, 0xff00, 0xff0000, 0, false, TYPE_INT), null);
check(new DirectColorModel(srgb, 32, 0xff000000, 0xff0000, 0xff00, 0, false, TYPE_INT), null);
check(new DirectColorModel(srgb, 32, 0xff00, 0xff0000, 0xff000000, 0, false, TYPE_INT), null);
// Test pixel-interleaved models.
int[] RGBA = {0, 1, 2, 3};
int[] BGRA = {2, 1, 0, 3};
int[] ARGB = {1, 2, 3, 0};
int[] ABGR = {3, 2, 1, 0};
int[] RGB = {0, 1, 2};
int[] BGR = {2, 1, 0};
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, RGBA, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, BGRA, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, ARGB, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, ABGR, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, RGB, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 40, 4, BGR, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 30, 3, RGB, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_USHORT),
Raster.createInterleavedRaster(TYPE_USHORT, 10, 10, 30, 3, BGR, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, RGBA, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, BGRA, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, ARGB, null));
check(new ComponentColorModel(srgb, true, true, TRANSLUCENT, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, ABGR, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, RGB, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 40, 4, BGR, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 30, 3, RGB, null));
check(new ComponentColorModel(srgb, false, false, OPAQUE, TYPE_BYTE),
Raster.createInterleavedRaster(TYPE_BYTE, 10, 10, 30, 3, BGR, null));
}
private static void check(ColorModel colorModel, WritableRaster raster) {
check(new BufferedImage(colorModel, raster != null ? raster : colorModel.createCompatibleWritableRaster(10, 10),
colorModel.isAlphaPremultiplied(), null));
}
private static void check(int imageType) {
check(new BufferedImage(10, 10, imageType));
}
private static void check(BufferedImage image) {
SurfaceData sd = Objects.requireNonNull(SurfaceManager.getManager(image).getPrimarySurfaceData());
if (sd.getNativeOps() == 0) throw new Error("getNativeOps() == 0");
}
}