mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8295430: Use cmsDoTransformLineStride instead of cmsDoTransform in the loop
Reviewed-by: prr
This commit is contained in:
parent
f0a6e71e4d
commit
78a08a0f21
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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);
|
||||
|
||||
200
test/jdk/sun/java2d/cmm/ColorConvertOp/FilterImageLineGap.java
Normal file
200
test/jdk/sun/java2d/cmm/ColorConvertOp/FilterImageLineGap.java
Normal 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();
|
||||
}
|
||||
}
|
||||
140
test/jdk/sun/java2d/cmm/ColorConvertOp/ValidateNoopFilter.java
Normal file
140
test/jdk/sun/java2d/cmm/ColorConvertOp/ValidateNoopFilter.java
Normal 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();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user