This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 8cf914d6364bc4f96b8cce8f22d1305e4cd6ff8e Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Feb 3 12:43:51 2022 +0100 Add a "last resort" workaround for JDK-8166038 for handling the cases where the `Raster` instance has not been created by ourselves. --- .../apache/sis/gui/coverage/CoverageCanvas.java | 5 +- .../apache/sis/internal/gui/ImageConverter.java | 5 +- .../internal/map/coverage/RenderingWorkaround.java | 104 +++++++++++++++++++++ 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java index 6f5dfa2..4374550 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageCanvas.java @@ -68,6 +68,7 @@ import org.apache.sis.gui.map.MapCanvas; import org.apache.sis.gui.map.MapCanvasAWT; import org.apache.sis.gui.map.StatusBar; import org.apache.sis.portrayal.RenderException; +import org.apache.sis.internal.map.coverage.RenderingWorkaround; import org.apache.sis.internal.coverage.j2d.TileErrorHandler; import org.apache.sis.internal.processing.image.Isolines; import org.apache.sis.internal.gui.BackgroundThreads; @@ -873,10 +874,10 @@ public class CoverageCanvas extends MapCanvasAWT { gr.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); if (prefetchedImage instanceof TileErrorHandler.Executor) { ((TileErrorHandler.Executor) prefetchedImage).execute( - () -> gr.drawRenderedImage(prefetchedImage, resampledToDisplay), + () -> gr.drawRenderedImage(RenderingWorkaround.wrap(prefetchedImage), resampledToDisplay), new TileErrorHandler(data.processor.getErrorHandler(), CoverageCanvas.class, "paint")); } else { - gr.drawRenderedImage(prefetchedImage, resampledToDisplay); + gr.drawRenderedImage(RenderingWorkaround.wrap(prefetchedImage), resampledToDisplay); } if (isolines != null) { final AffineTransform at = gr.getTransform(); diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ImageConverter.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ImageConverter.java index 5c96296..318c537 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ImageConverter.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ImageConverter.java @@ -34,6 +34,7 @@ import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import org.apache.sis.image.ImageProcessor; import org.apache.sis.image.PlanarImage; +import org.apache.sis.internal.map.coverage.RenderingWorkaround; import org.apache.sis.internal.coverage.j2d.ColorModelFactory; import org.apache.sis.internal.coverage.j2d.ImageUtilities; import org.apache.sis.internal.system.Loggers; @@ -189,9 +190,9 @@ final class ImageConverter extends Task<Statistics[]> { final BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); final Graphics2D graphics = buffer.createGraphics(); try { - graphics.drawRenderedImage(image, toCanvas); + graphics.drawRenderedImage(RenderingWorkaround.wrap(image), toCanvas); if (mask != null) { - graphics.drawRenderedImage(mask, toCanvas); + graphics.drawRenderedImage(RenderingWorkaround.wrap(mask), toCanvas); } } finally { graphics.dispose(); diff --git a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingWorkaround.java b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingWorkaround.java new file mode 100644 index 0000000..9c40568 --- /dev/null +++ b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingWorkaround.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.internal.map.coverage; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Vector; +import org.apache.sis.internal.coverage.j2d.TilePlaceholder; + + +/** + * Workaround for the bug in calls to {@code Graphics2D.drawRenderedImage(…)} + * when the image is tiled and some tiles are not writable. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * + * @see <a href="https://bugs.openjdk.java.net/browse/JDK-8275345">JDK-8275345</a> + * + * @since 1.2 + * @module + */ +public final class RenderingWorkaround implements RenderedImage { + /** + * Applies workaround for JDK-8275345 if needed. + * + * @param image the image on which to apply the workaround. + * @return image that can be used for rendering purpose. + */ + public static RenderedImage wrap(final RenderedImage image) { + if (TilePlaceholder.PENDING_JDK_FIX) { + if (!(image == null || image instanceof BufferedImage || image instanceof RenderingWorkaround)) { + return new RenderingWorkaround(image); + } + } + return image; + } + + /** + * The image to render. + */ + private final RenderedImage image; + + /** + * Creates a new wrapper for the given image. + */ + private RenderingWorkaround(final RenderedImage image) { + this.image = image; + } + + @Override public Vector<RenderedImage> getSources() {return image.getSources();} + @Override public Object getProperty(String name) {return image.getProperty(name);} + @Override public String[] getPropertyNames() {return image.getPropertyNames();} + @Override public ColorModel getColorModel() {return image.getColorModel();} + @Override public SampleModel getSampleModel() {return image.getSampleModel();} + @Override public int getWidth() {return image.getWidth();} + @Override public int getHeight() {return image.getHeight();} + @Override public int getMinX() {return image.getMinX();} + @Override public int getMinY() {return image.getMinY();} + @Override public int getNumXTiles() {return image.getNumXTiles();} + @Override public int getNumYTiles() {return image.getNumYTiles();} + @Override public int getMinTileX() {return image.getMinTileX();} + @Override public int getMinTileY() {return image.getMinTileY();} + @Override public int getTileWidth() {return image.getTileWidth();} + @Override public int getTileHeight() {return image.getTileHeight();} + @Override public int getTileGridXOffset() {return image.getTileGridXOffset();} + @Override public int getTileGridYOffset() {return image.getTileGridYOffset();} + @Override public Raster getTile(int tx, int ty) {return wrap(image.getTile(tx, ty));} + @Override public Raster getData() {return wrap(image.getData());} + @Override public Raster getData(Rectangle rect) {return wrap(image.getData(rect));} + @Override public WritableRaster copyData(WritableRaster r) {return image.copyData(r);} + + /** + * Returns the given raster as an instance of {@link WritableRaster}. + * The underlying data buffer is shared, not copied. + */ + private static Raster wrap(final Raster r) { + if (r instanceof WritableRaster) { + return r; + } else { + return Raster.createWritableRaster(r.getSampleModel(), r.getDataBuffer(), new Point(r.getMinX(), r.getMinY())); + } + } +}