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

Reply via email to