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 67a64fdf85a73ec1dd182b1bf301f9e024d97700
Merge: f87196f 7b1ee54
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Nov 8 17:12:45 2021 +0100

    Merge branch 'fix/mask-image' into geoapi-4.0

 .../java/org/apache/sis/image/MaskedImageTest.java | 255 +++++++++++++++++++++
 .../apache/sis/test/suite/FeatureTestSuite.java    |   3 +-
 2 files changed, 257 insertions(+), 1 deletion(-)

diff --cc 
core/sis-feature/src/test/java/org/apache/sis/image/MaskedImageTest.java
index 0000000,dc9e8ec..441574c
mode 000000,100644..100644
--- a/core/sis-feature/src/test/java/org/apache/sis/image/MaskedImageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/MaskedImageTest.java
@@@ -1,0 -1,237 +1,255 @@@
++/*
++ * 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.image;
+ 
+ import java.awt.Color;
+ import java.awt.Graphics;
++import java.awt.Point;
+ import java.awt.Polygon;
+ import java.awt.Rectangle;
+ import java.awt.image.BufferedImage;
+ import java.awt.image.DataBuffer;
+ import java.awt.image.IndexColorModel;
+ import java.awt.image.Raster;
+ import java.awt.image.RenderedImage;
+ import java.awt.image.WritableRaster;
+ import org.apache.sis.internal.coverage.j2d.WritableTiledImage;
+ import org.apache.sis.test.FeatureAssert;
+ import org.apache.sis.util.ArgumentChecks;
++import org.apache.sis.test.TestCase;
+ import org.junit.Test;
+ 
+ /**
+  * TODO: test with big images
+  * TODO: when upgrading to Junit 5 use parameterized tests to avoid 
duplication of test methods
+  */
 -public class MaskedImageTest {
++public final strictfp class MaskedImageTest extends TestCase {
+ 
+     private static final Polygon CONVEX_POLYGON = new Polygon(
+             new int[] {3, 8, 8, 3, 3},
+             new int[] {3, 3, 6, 6, 3},
+             5);
+ 
+     private static final Polygon CONCAVE_POLYGON = new Polygon(
+             new int[] { 1, 1, 7, 7, 5, 5, 2, 2 },
+             new int[] { 1, 6, 6, 3, 3, 4, 4, 1 },
+             8);
+ 
+     private static final int[] BASE_CANVAS = {
+             0, 0, 0, 0, 1, 1, 1, 1,
+             0, 0, 0, 0, 1, 1, 1, 1,
+             0, 0, 0, 0, 1, 1, 1, 1,
+             0, 0, 0, 0, 1, 1, 1, 1,
+             3, 3, 3, 3, 2, 2, 2, 2,
+             3, 3, 3, 3, 2, 2, 2, 2,
+             3, 3, 3, 3, 2, 2, 2, 2,
+             3, 3, 3, 3, 2, 2, 2, 2
+     };
+ 
+     @Test
+     public void noErrorOnEmptyMasks() {
+         final BufferedImage source = monoTile();
+         final RenderedImage masked = new MaskedImage(source, new Polygon(), 
true, new Number[]{ 127 });
+         FeatureAssert.assertPixelsEqual(source, null, masked, null);
+     }
+ 
+     @Test
+     public void fill_MONO_tile_INside_conVEX_polygon() {
+         maskInsideConvexPolygon(monoTile());
+     }
+ 
+     @Test
+     public void fill_MONO_tile_OUTside_conVEX_polygon() {
+         maskOutsideConvexPolygon(monoTile());
+     }
+ 
+     @Test
+     public void fill_MULTI_tile_INside_conVEX_polygon() {
+         maskInsideConvexPolygon(multiTile());
+     }
+ 
+     @Test
+     public void fill_MULTI_tile_OUTside_conVEX_polygon() {
+         maskOutsideConvexPolygon(multiTile());
+     }
+ 
+     @Test
+     public void fill_MONO_tile_INside_conCAVE_polygon() {
+         fillInsideConcavePolygon(monoTile());
+     }
+ 
+     @Test
+     public void fill_MONO_tile_OUTside_conCAVE_polygon() {
+         fillOutsideConcavePolygon(monoTile());
+     }
+ 
+     @Test
+     public void fill_MULTI_tile_INside_conCAVE_polygon() {
+         fillInsideConcavePolygon(multiTile());
+     }
+ 
+     @Test
+     public void fill_MULTI_tile_OUTside_conCAVE_polygon() {
+         fillOutsideConcavePolygon(multiTile());
+     }
+ 
+     private void maskInsideConvexPolygon(RenderedImage source) {
+         final RenderedImage masked = new MaskedImage(source, CONVEX_POLYGON, 
true, new Number[]{ 4 });
+         final RenderedImage expected = monoTile(new int[] {
+                 0, 0, 0, 0, 1, 1, 1, 1,
+                 0, 0, 0, 0, 1, 1, 1, 1,
+                 0, 0, 0, 0, 1, 1, 1, 1,
+                 0, 0, 0, 4, 4, 4, 4, 4,
+                 3, 3, 3, 4, 4, 4, 4, 4,
+                 3, 3, 3, 4, 4, 4, 4, 4,
+                 3, 3, 3, 3, 2, 2, 2, 2,
+                 3, 3, 3, 3, 2, 2, 2, 2
+         });
+         FeatureAssert.assertPixelsEqual(expected, null, masked, null);
+     }
+ 
+     private void maskOutsideConvexPolygon(final RenderedImage source) {
+         final RenderedImage masked = new MaskedImage(source, CONVEX_POLYGON, 
false, new Number[]{ 4 });
+         final RenderedImage expected = monoTile(new int[] {
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 4, 4, 0, 1, 1, 1, 1,
+                 4, 4, 4, 3, 2, 2, 2, 2,
+                 4, 4, 4, 3, 2, 2, 2, 2,
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 4, 4, 4, 4, 4, 4, 4
+         });
+         FeatureAssert.assertPixelsEqual(expected, null, masked, null);
+     }
+ 
+     private void fillInsideConcavePolygon(final RenderedImage source) {
+         final RenderedImage masked = new MaskedImage(source, CONCAVE_POLYGON, 
true, new Number[]{ 4 });
+         final RenderedImage expected = monoTile(new int[] {
+                 0, 0, 0, 0, 1, 1, 1, 1,
+                 0, 4, 0, 0, 1, 1, 1, 1,
+                 0, 4, 0, 0, 1, 1, 1, 1,
+                 0, 4, 0, 0, 1, 4, 4, 1,
+                 3, 4, 4, 4, 4, 4, 4, 2,
+                 3, 4, 4, 4, 4, 4, 4, 2,
+                 3, 3, 3, 3, 2, 2, 2, 2,
+                 3, 3, 3, 3, 2, 2, 2, 2
+         });
+         FeatureAssert.assertPixelsEqual(expected, null, masked, null);
+     }
+ 
+     private void fillOutsideConcavePolygon(final RenderedImage source) {
+         final RenderedImage masked = new MaskedImage(source, CONCAVE_POLYGON, 
false, new Number[]{ 4 });
+         final RenderedImage expected = monoTile(new int[] {
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 0, 4, 4, 4, 4, 4, 4,
+                 4, 0, 4, 4, 4, 4, 4, 4,
+                 4, 0, 4, 4, 4, 1, 1, 4,
+                 4, 3, 3, 3, 2, 2, 2, 4,
+                 4, 3, 3, 3, 2, 2, 2, 4,
+                 4, 4, 4, 4, 4, 4, 4, 4,
+                 4, 4, 4, 4, 4, 4, 4, 4
+         });
+         FeatureAssert.assertPixelsEqual(expected, null, masked, null);
+     }
+ 
+     private RenderedImage multiTile() {
+         return new WritableTiledImage(null, colorPalette(), 8, 8, 0, 0,
 -                tile(0), tile(1), tile(3), tile(2));
++                tile(0, 0), tile(1, 1), tile(2, 3), tile(3, 2));
+     }
+ 
 -    private WritableRaster tile(int fillValue) {
 -        final WritableRaster tile = 
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 4, 4, 1, null);
++    private static WritableRaster tile(final int n, final int fillValue) {
++        final WritableRaster tile = 
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 4, 4, 1, new Point((n % 
2)*4, (n / 2)*4));
+         final WritablePixelIterator it = new 
PixelIterator.Builder().createWritable(tile);
+         while (it.next()) it.setSample(0, fillValue);
+         return tile;
+     }
+ 
+     /**
+      * Base colors are shades of blue. The last (fifth) color used for masks 
is green.
+      * @return
+      */
+     private static IndexColorModel colorPalette() {
+         byte[] reds   = { 0,  0,  0,   0,   0 };
+         byte[] greens = { 0,  0,  0,   0, 127 };
+         byte[] blues  = { 0, 50, 95, 127,   0 };
+         return new IndexColorModel(Byte.SIZE, 5, reds, greens, blues);
+     }
+ 
+     /**
+      *
+      * @return Base test image, based on {@link #colorPalette() indexed color 
model}.
+      */
+     private static BufferedImage monoTile() {
+         return monoTile(BASE_CANVAS);
+     }
+ 
+     private static BufferedImage monoTile(int[] pixels) {
+         ArgumentChecks.ensureDimensionMatches("Input raster must be 8x8", 64, 
pixels);
+         final BufferedImage image = new BufferedImage(8, 8, 
BufferedImage.TYPE_BYTE_INDEXED, colorPalette());
+         final WritableRaster raster = image.getRaster();
+         raster.setPixels(0, 0, 8, 8, pixels);
+         return image;
+     }
+ 
+     /**
+      * Draw given polygon into source image, to display expected result in 
debugger.
+      */
+     private static BufferedImage debugGeometryImage(final Polygon geometry) {
+         final BufferedImage source = monoTile();
+         final BufferedImage debugImg = new BufferedImage(source.getWidth(), 
source.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
+         final Graphics painter = debugImg.getGraphics();
+         painter.drawImage(source, 0, 0, null);
+ 
+         final Rectangle bounds = geometry.getBounds();
+         final Rectangle enlargedBounds = new Rectangle(bounds.x - 1, bounds.y 
- 1, bounds.width + 2, bounds.height + 2);
+         final Rectangle intersection = 
enlargedBounds.intersection(debugImg.getRaster().getBounds());
+         painter.setColor(Color.RED);
+         painter.fillRect(intersection.x, intersection.y, intersection.width, 
intersection.height);
+         painter.setColor(Color.GREEN);
+         painter.fillPolygon(geometry);
+         painter.dispose();
+ 
+         return debugImg;
+     }
+ 
+ 
+     /**
+      * Useful in IntelliJ: allow to display input image in debugger: Add a 
new watch calling this method on wanted image.
+      * <em>WARNINGS:</em> works only for current test case:
+      * <ul>
+      *     <li> it assume input image is compatible with test {@link 
#colorPalette() color palette}.</li>
+      *     <li>Work only on single tile images.</li>
+      * </ul>
+      *
+      * @param source The image to display.
+      * @return The image directly displayable through debugger.
+      */
+     private static BufferedImage debug(final RenderedImage source) {
+         Raster tile = source.getTile(source.getMinTileX(), 
source.getMinTileY());
+         final int width, height;
+ 
+         tile = tile.createTranslatedChild(0, 0);
+         width = tile.getWidth();
+         height = tile.getHeight();
+ 
+         final BufferedImage view = new BufferedImage(width, height, 
BufferedImage.TYPE_BYTE_INDEXED, colorPalette());
+         view.getRaster().setRect(tile);
+ 
+         return view;
+     }
+ }
diff --cc 
core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
index 32834e5,32834e5..9f2cf45
--- 
a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
+++ 
b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
@@@ -26,7 -26,7 +26,7 @@@ import org.junit.runners.Suite
   *
   * @author  Martin Desruisseaux (Geomatys)
   * @author  Johann Sorel (Geomatys)
-- * @version 1.1
++ * @version 1.2
   * @since   0.5
   * @module
   */
@@@ -97,6 -97,6 +97,7 @@@
      org.apache.sis.image.InterpolationTest.class,
      org.apache.sis.image.ResamplingGridTest.class,
      org.apache.sis.image.ResampledImageTest.class,
++    org.apache.sis.image.MaskedImageTest.class,
      org.apache.sis.image.BandedSampleConverterTest.class,
      org.apache.sis.image.ImageCombinerTest.class,
      org.apache.sis.image.ImageProcessorTest.class,

Reply via email to