/* * Copyright (c) 2022, 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.
*/
/** * @test * @bug 8275345 * @summary RasterFormatException when drawing a tiled image made of non-writable rasters. * * Test drawing a tiled image made of non-writable {@link Raster} tiles. * Drawing works when tiles are instances of {@link WritableRaster}. * But if tiles are instances of {@link Raster} only, then the following * exception is thrown: * * Exception in thread "main" java.awt.image.RasterFormatException: (parentX + width) is outside raster * at java.desktop/java.awt.image.WritableRaster.createWritableChild(WritableRaster.java:228) * at java.desktop/sun.java2d.SunGraphics2D.drawTranslatedRenderedImage(SunGraphics2D.java:2852) * at java.desktop/sun.java2d.SunGraphics2D.drawRenderedImage(SunGraphics2D.java:2711) * * The bug is demonstrated by drawing the same image twice: * once with {@link WritableRaster} tiles (which succeed), * then the same operation but with {@link Raster} tiles. * * The bug is caused by the following code in {@code SunGraphics2D}: * * // Create a WritableRaster containing the tile * WritableRaster wRaster = null; * if (raster instanceof WritableRaster) { * wRaster = (WritableRaster)raster; * } else { * // Create a WritableRaster in the same coordinate system * // as the original raster. * wRaster = * Raster.createWritableRaster(raster.getSampleModel(), * raster.getDataBuffer(), * null); * } * // Translate wRaster to start at (0, 0) and to contain * // only the relevant portion of the tile * wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, * tileRect.width, * tileRect.height, * 0, 0, * null); * * If {@code raster} is not an instance of {@link WritableRaster}, * then a new {@link WritableRaster} is created wrapping the same * buffer <strong>but with a location of (0,0)</strong>, because * the {@code location} argument of {@code createWritableRaster} * is null. Consequently the call to {@code createWritableChild} * shall not be done in that case, because the raster is already * translated. The current code applies translation twice. * * This bug is largely unnoticed because most {@code Raster.create} * methods actually create {@link WritableRaster} instances, even * when the user did not asked for writable raster. To make this * bug apparent, we need to invoke {@code Raster.createRaster(…)} * with a sample model for which no optimization is provided.
*/ publicclass TiledImage implements RenderedImage { /** * Run the test using writable tiles first, then read-only tiles.
*/ publicstaticvoid main(String[] args) {
draw(true); // Pass.
draw(false); // Fail if 8275345 is not fixed.
}
/** * Tests rendering a tiled image. * * @param writable whether the image shall use writable raster.
*/ privatestaticvoid draw(finalboolean writable) { final BufferedImage target = new BufferedImage(
TILE_WIDTH * NUM_X_TILES,
TILE_HEIGHT * NUM_Y_TILES,
BufferedImage.TYPE_BYTE_GRAY);
final RenderedImage source = new TiledImage(writable,
target.getColorModel());
Graphics2D g = target.createGraphics();
g.drawRenderedImage(source, new AffineTransform());
g.dispose();
}
privatefinal ColorModel colorModel;
privatefinal Raster[] tiles;
/** * Creates a tiled image. The image is empty, * but pixel values are not the purpose of this test. * * @param writable whether the image shall use writable raster.
*/ private TiledImage(boolean writable, ColorModel cm) { /* * We need a sample model class for which Raster.createRaster * do not provide a special case. That method has optimizations * for most SampleModel sub-types, except BandedSampleModel.
*/
SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, TILE_WIDTH, TILE_HEIGHT, 1);
tiles = new Raster[NUM_X_TILES * NUM_Y_TILES]; final Point location = new Point(); for (int tileY = 0; tileY < NUM_Y_TILES; tileY++) { for (int tileX = 0; tileX < NUM_X_TILES; tileX++) {
location.x = tileX * TILE_WIDTH;
location.y = tileY * TILE_HEIGHT;
DataBufferByte db = new DataBufferByte(TILE_WIDTH * TILE_HEIGHT);
Raster r; if (writable) {
r = Raster.createWritableRaster(sm, db, location);
} else { // Case causing RasterFormatException later.
r = Raster.createRaster(sm, db, location);
}
tiles[tileX + tileY * NUM_X_TILES] = r;
}
}
colorModel = cm;
}
@Override public ColorModel getColorModel() { return colorModel;
}
@Override public SampleModel getSampleModel() { return tiles[0].getSampleModel();
}
@Override public Vector<RenderedImage> getSources() { returnnew Vector<>();
}
@Override public Object getProperty(String key) { return Image.UndefinedProperty;
}
@Override public String[] getPropertyNames() { returnnull;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.