RasterFormatException thrown when drawing a tiled image made of non-writable rasters
Martin Desruisseaux
martin.desruisseaux at geomatys.com
Fri Oct 15 15:10:49 UTC 2021
Hello all
Call to Graphics2D.drawRenderedImage(RenderedImage, AffineTransform)
fails if the image contains more than one tile (or a single tile not
located at 0,0) and the tiles are not instances of WritableRaster (i.e.
are instances of the read-only Raster parent class). A test case [1]
reproduces this issue. The bug is demonstrated by drawing the same image
twice: once with WritableRaster tiles (which succeed), then the same
operation where the only change is the use of Raster tiles. The
exception is:
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 cause is in the following code in 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 relevent portion of the tile
wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y,
tileRect.width,
tileRect.height,
0, 0,
null);
If the tile is not an instance of WritableRaster, then the code wraps
the tile DataBuffer in a new WritableRaster*but with a location set to
(0,0)*, because the location argument in createWritableRaster(…) call is
null. Then the call to createWritableChild(…) applies a translation for
bringing the tile location to (0,0). But in the case where the raster
has been converted from Raster to WritableRaster, that translation has
already been applied, and the effect of current code is to apply the
translation twice.
I think that this bug has been largely unnoticed because most users use
BufferedImage, which has a single tile always located at (0,0), and the
minority of developers using their own RenderedImage implementation uses
WritableRaster instances, because Raster.create(…) methods provide
optimizations for common cases which result in WritableRaster instances
created even when the user asked only for a Raster. To make this bug
apparent, it is necessary to invoke Raster.createRaster(…) with a sample
model for which no optimization is provided.
The commit at [1] provides a test case and a suggested fix. From that
point, I'm not sure how to proceed (I'm sure there is many steps, that
the proposed commit needs to be modified, etc.). Can anyone can give me
some hints?
Regards,
Martin
[1]https://github.com/Geomatys/jdk/commit/94242a05ff8b9c1af603a11133af7c6016c9e833
More information about the client-libs-dev
mailing list