sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Add integer overflow analysis in GridCoverage2D.render(…) method for BufferedImage case. Detect when existing BufferedImage can be returned as-is instead of invoking `getSubImage`. Add test case for https://issues.apache.org/jira/browse/SIS-495
Date Thu, 04 Jun 2020 12:11:45 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new e3a2732  Add integer overflow analysis in GridCoverage2D.render(…) method for BufferedImage
case. Detect when existing BufferedImage can be returned as-is instead of invoking `getSubImage`.
Add test case for https://issues.apache.org/jira/browse/SIS-495
e3a2732 is described below

commit e3a27327f3c9012df3cf05787a9ffd2e9c4b1ec1
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Thu Jun 4 14:08:01 2020 +0200

    Add integer overflow analysis in GridCoverage2D.render(…) method for BufferedImage case.
    Detect when existing BufferedImage can be returned as-is instead of invoking `getSubImage`.
    Add test case for https://issues.apache.org/jira/browse/SIS-495
---
 .../apache/sis/coverage/grid/GridCoverage2D.java   | 20 ++++++--
 .../sis/coverage/grid/ResampledGridCoverage.java   |  5 +-
 .../sis/coverage/grid/GridCoverage2DTest.java      | 57 ++++++++--------------
 .../coverage/grid/ResampledGridCoverageTest.java   | 33 ++++++++++++-
 4 files changed, 69 insertions(+), 46 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
index 5da66ab..42e6834 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
@@ -578,13 +578,25 @@ public class GridCoverage2D extends GridCoverage {
              * upper-left point is inside the image.
              */
             if (data instanceof BufferedImage) {
-                // BufferedImage origin should be (0, 0), but for consistency over image
API, we consider it variable
+                // BufferedImage origin should be (0, 0), but for consistency with image
API, we consider it variable.
                 final long ix = data.getMinX();
                 final long iy = data.getMinY();
                 if (xmin >= ix && ymin >= iy) {
-                    return ((BufferedImage) data).getSubimage(toIntExact(xmin), toIntExact(ymin),
-                            toIntExact(min(xmax + 1, ix + data.getWidth() ) - xmin),
-                            toIntExact(min(ymax + 1, iy + data.getHeight()) - ymin));
+                    final int width  = data.getWidth();
+                    final int height = data.getHeight();
+                    /*
+                     * Result of `ix + width` requires at most 33 bits for any `ix` value
(same for y axis).
+                     * Subtractions by `xmin` and `ymin` never overflow if `ix` and `iy`
are zero or positive,
+                     * which should always be the case with BufferedImage. The +1 is applied
after subtraction
+                     * instead than on `xmax` and `ymax` for avoiding overflow, since the
result of `min(…)`
+                     * uses at most 33 bits.
+                     */
+                    final int nx = toIntExact(min(xmax, ix + width  - 1) - xmin + 1);
+                    final int ny = toIntExact(min(ymax, iy + height - 1) - ymin + 1);
+                    if ((ix | iy) == 0 && nx == width && ny == height) {
+                        return data;
+                    }
+                    return ((BufferedImage) data).getSubimage(toIntExact(xmin), toIntExact(ymin),
nx, ny);
                 }
             }
             /*
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
index 9f8474d..898b2d8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ResampledGridCoverage.java
@@ -456,9 +456,8 @@ final class ResampledGridCoverage extends GridCoverage {
             bounds = new Rectangle(Math.toIntExact(sliceExtent.getSize(resampledDimensions[0])),
                                    Math.toIntExact(sliceExtent.getSize(resampledDimensions[1])));
             /*
-             * The transform needs to be two-dimensional. The `toSourceCenter` transform
does not met that condition,
-             * otherwise `specialize(…)` would have replaced this ResampledGridCoverage
by a GridCoverage2D instance.
-             * Try to extract a two-dimensional part operating only on the slice dimensions
having an extent larger
+             * The transform inputs must be two-dimensional (outputs may be more flexible).
If this is not the case,
+             * try to extract a two-dimensional part operating only on the slice dimensions
having an extent larger
              * than one cell. The choice of dimensions may vary between different calls to
this `render(…)` method,
              * depending on `sliceExtent` value.
              */
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
index b2ef925..ce621f9 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverage2DTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.sis.coverage.grid;
 
-import java.awt.image.RenderedImage;
 import java.util.List;
 import java.util.Collections;
+import java.awt.Rectangle;
 import java.awt.image.BufferedImage;
 import java.awt.image.DataBuffer;
 import java.awt.image.Raster;
@@ -38,7 +38,7 @@ import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.FeatureAssert.*;
 
 
 /**
@@ -201,43 +201,26 @@ public strictfp class GridCoverage2DTest extends TestCase {
     @Test
     public void render_of_subextent() {
         final GridCoverage coverage = createTestCoverage();
-        final Raster completeRendering = coverage.render(null).getTile(0, 0);
-
+        /*
+         * Row extraction:
+         *   - Expected size (2,1) is verified by `assertPixelsEqual(…)`.
+         *   - Bounds of expected values is Rectangle(translation, size).
+         *   - Pixel source(0, 1) → output(0, 0)
+         *   - Pixel source(1, 1) → output(1, 0)
+         */
         final GridExtent singleRow = new GridExtent(2, 1).translate(0, 1);
-        RenderedImage subset = coverage.render(singleRow);
-        assertEquals("Rendering width", 2, subset.getWidth());
-        assertEquals("Rendering height", 1, subset.getHeight());
-        Raster subsetTile = subset.getTile(0, 0);
-        assertArrayEquals(
-                "Row extraction, pixel source(0, 1) -> output(0, 0)",
-                completeRendering.getPixel(0, 1, (double[])null),
-                subsetTile.getPixel(0, 0, (double[])null),
-                1e-1
-        );
-        assertArrayEquals(
-                "Row extraction, pixel source(1, 1) -> output(1, 0)",
-                completeRendering.getPixel(1, 1, (double[])null),
-                subsetTile.getPixel(1, 0, (double[])null),
-                1e-1
-        );
-
+        assertPixelsEqual(coverage.render(null), new Rectangle(0, 1, 2, 1),     // Expected
values.
+                          coverage.render(singleRow), null);                    // Actual
values to test.
+        /*
+         * Column extraction:
+         *   - Expected size (1,2) is verified by `assertPixelsEqual(…)`.
+         *   - Bounds of expected values is Rectangle(translation, size).
+         *   - Pixel source(1, 0) → output(0, 0)
+         *   - Pixel source(1, 1) → output(0, 1)
+         */
         final GridExtent singleCol = new GridExtent(1, 2).translate(1, 0);
-        subset = coverage.render(singleCol);
-        assertEquals("Rendering width", 1, subset.getWidth());
-        assertEquals("Rendering height", 2, subset.getHeight());
-        subsetTile = subset.getTile(0, 0);
-        assertArrayEquals(
-                "Column extraction, pixel source(1, 0) -> output(0, 0)",
-                completeRendering.getPixel(1, 0, (double[])null),
-                subsetTile.getPixel(0, 0, (double[])null),
-                1e-1
-        );
-        assertArrayEquals(
-                "Column extraction, pixel source(1, 1) -> output(0, 1)",
-                completeRendering.getPixel(1, 1, (double[])null),
-                subsetTile.getPixel(0, 1, (double[])null),
-                1e-1
-        );
+        assertPixelsEqual(coverage.render(null), new Rectangle(1, 0, 1, 2),     // Expected
values.
+                          coverage.render(singleCol), null);                    // Actual
values to test.
     }
 
     /**
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
index c4a3156..53a78e2 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
@@ -36,6 +36,7 @@ import org.apache.sis.image.Interpolation;
 import org.apache.sis.image.TiledImageMock;
 import org.apache.sis.internal.coverage.j2d.TiledImage;
 import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.referencing.operation.HardCodedConversions;
@@ -61,6 +62,7 @@ import static org.apache.sis.test.FeatureAssert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @version 1.1
  * @since   1.1
  * @module
@@ -520,7 +522,7 @@ public final strictfp class ResampledGridCoverageTest extends TestCase
{
      * @throws TransformException if some coordinates can not be transformed to the target
grid geometry.
      */
     @Test
-    public void crs3D_to_crs4D() throws TransformException {
+    public void testDimensionalityIncrease() throws TransformException {
         final GridCoverage source3D = createCoverageND(false);
         final GridGeometry target4D = createGridGeometryND(HardCodedCRS.WGS84_4D, 0, 1, 2,
3, false);
         final GridCoverage result   = resample(source3D, target4D);
@@ -534,7 +536,7 @@ public final strictfp class ResampledGridCoverageTest extends TestCase
{
      * @throws TransformException if some coordinates can not be transformed to the target
grid geometry.
      */
     @Test
-    public void crs4D_to_crs3D() throws TransformException {
+    public void testDimensionalityReduction() throws TransformException {
         final GridGeometry target3D = createGridGeometryND(HardCodedCRS.WGS84_3D, 0, 1, 2,
3, false);
         final GridCoverage source4D = createCoverageND(true);
         final GridCoverage result   = resample(source4D, target3D);
@@ -543,6 +545,33 @@ public final strictfp class ResampledGridCoverageTest extends TestCase
{
     }
 
     /**
+     * Tests resampling with a target domain larger than the source domain.
+     * Pixel outside the source domain shall be set to fill value, which is 0.
+     *
+     * @throws TransformException if some coordinates can not be transformed to the target
grid geometry.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-495">SIS-495</a>
+     */
+    @Test
+    public void testDomainIncrease() throws TransformException {
+        final int size = 2;
+        final CoordinateReferenceSystem crs = HardCodedCRS.WGS84;
+        final BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_GRAY);
+        image.getRaster().setDataElements(0, 0, size, size, new byte[] {10, 12, 16, 14});
+        final AffineTransform2D gridToCRS = new AffineTransform2D(1, 0, 0, -1, 0, 0);
+        final GridGeometry sourceGrid = new GridGeometry(null, CELL_CENTER, gridToCRS, crs);
+        final GridGeometry targetGrid = new GridGeometry(new GridExtent(4, 4), CELL_CENTER,
gridToCRS, crs);
+        final GridCoverage source     = new GridCoverage2D(sourceGrid, null, image);
+        final GridCoverage target     = resample(source, targetGrid);
+        assertValuesEqual(target.render(null).getData(), 0, new int[][] {
+            {10, 12, 0, 0},
+            {16, 14, 0, 0},
+            { 0,  0, 0, 0},
+            { 0,  0, 0, 0}
+        });
+    }
+
+    /**
      * Returns an image with only the queries part of the given image.
      * This is an helper tools which can be invoked during debugging
      * session in IDE capable to display images.


Mime
View raw message