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 beda4a8939 Add a verification of the "untiled.tiff" image created for 
testing purposes in the previous commit.
beda4a8939 is described below

commit beda4a89390fcf1003e2c07ef4aa1100c5d81fef
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Feb 20 18:36:03 2026 +0100

    Add a verification of the "untiled.tiff" image created for testing purposes 
in the previous commit.
---
 .../sis/coverage/grid/GridCoverageBuilder.java     | 68 ++++++++++++++++++++--
 .../main/module-info.java                          |  2 +-
 .../sis/storage/geotiff/GeoTiffStoreTest.java      | 67 +++++++++++++++++++--
 .../org/apache/sis/storage/geotiff/ReaderTest.java |  9 +--
 .../org/apache/sis/storage/geotiff/WriterTest.java |  4 +-
 5 files changed, 132 insertions(+), 18 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageBuilder.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageBuilder.java
index be3de3d5bd..d1ccc8dd0d 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageBuilder.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCoverageBuilder.java
@@ -21,7 +21,8 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Hashtable;
-import static java.util.Objects.requireNonNull;
+import java.util.Objects;
+import java.util.function.IntBinaryOperator;
 import java.awt.Point;
 import java.awt.Dimension;
 import java.awt.Rectangle;
@@ -34,6 +35,7 @@ import java.awt.image.SampleModel;
 import java.awt.image.WritableRaster;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.image.DataType;
 import org.apache.sis.image.PlanarImage;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.image.internal.shared.ColorScaleBuilder;
@@ -92,7 +94,7 @@ import org.apache.sis.util.resources.Errors;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.7
  *
  * @see GridCoverage2D
  * @see SampleDimension.Builder
@@ -301,7 +303,7 @@ public class GridCoverageBuilder {
      * @see SampleDimension.Builder
      */
     public GridCoverageBuilder addRange(final SampleDimension band) {
-        requireNonNull(band);
+        Objects.requireNonNull(band);
         if (!(ranges instanceof ArrayList<?>)) {
             ranges = (ranges != null) ? new ArrayList<>(ranges) : new 
ArrayList<>();
         }
@@ -325,7 +327,7 @@ public class GridCoverageBuilder {
      * @see BufferedImage
      */
     public GridCoverageBuilder setValues(final RenderedImage data) {
-        image  = requireNonNull(data);
+        image  = Objects.requireNonNull(data);
         raster = null;
         buffer = null;
         size   = null;
@@ -348,7 +350,7 @@ public class GridCoverageBuilder {
      * @see Raster#createBandedRaster(int, int, int, int, Point)
      */
     public GridCoverageBuilder setValues(final Raster data) {
-        raster = requireNonNull(data);
+        raster = Objects.requireNonNull(data);
         image  = null;
         buffer = null;
         size   = null;
@@ -386,6 +388,60 @@ public class GridCoverageBuilder {
         return this;
     }
 
+    /**
+     * Sets a two-dimensional slice to the values computed by the given 
functions.
+     * The number of bands is the number of functions and the color model 
defaults to gray scale.
+     * The tiling is unspecified and may change in future versions of Apache 
<abbr>SIS</abbr>.
+     *
+     * <p>Each functions will receive pixel coordinates (<var>x</var>, 
<var>y</var>)
+     * and shall return the sample value to store in one band of the image at 
that pixel position.
+     * The <var>x</var> values will be between 0 inclusive and {@link 
Dimension#width} exclusive.
+     * The <var>y</var> values will be between 0 inclusive and {@link 
Dimension#height} exclusive.
+     * The functions may be invoked with pixel coordinates in any order.</p>
+     *
+     * @param  type   the type of values to store in the image.
+     * @param  size   the image size in pixels.
+     * @param  bands  functions providing sample values in each band, in order.
+     * @return {@code this} for method invocation chaining.
+     * @throws IllegalArgumentException if {@code width} or {@code height} is 
negative or equals to zero.
+     *
+     * @since 1.7
+     */
+    public GridCoverageBuilder setValues(final DataType type, final Dimension 
size, IntBinaryOperator... bands) {
+        final int width, height;
+        ArgumentChecks.ensureStrictlyPositive("width",  width  = size.width);
+        ArgumentChecks.ensureStrictlyPositive("height", height = size.height);
+        ArgumentChecks.ensureNonEmpty("bands", bands);
+        bands = bands.clone();
+        for (int b=0; b<bands.length; b++) {
+            ArgumentChecks.ensureNonNullElement("bands", b, bands[b]);
+        }
+        final WritableRaster data = 
Raster.createBandedRaster(type.toDataBufferType(), width, height, bands.length, 
null);
+        if (bands.length == 1) {
+            /*
+             * This block is not strictly necessary, as the following block is 
general.
+             * But it is a slight optimization for a common case.
+             */
+            final IntBinaryOperator band = bands[0];
+            for (int y=0; y<height; y++) {
+                for (int x=0; x<width; x++) {
+                    data.setSample(x, y, 0, band.applyAsInt(x, y));
+                }
+            }
+        } else {
+            final int[] samples = new int[bands.length];
+            for (int y=0; y<height; y++) {
+                for (int x=0; x<width; x++) {
+                    for (int b=0; b<bands.length; b++) {
+                        samples[b] = bands[b].applyAsInt(x, y);
+                    }
+                    data.setPixel(x, y, samples);
+                }
+            }
+        }
+        return setValues(data);
+    }
+
     /**
      * Reverses axis direction in the specified grid dimension.
      * For example if grid indices are (<var>column</var>, <var>row</var>),
@@ -426,7 +482,7 @@ public class GridCoverageBuilder {
      */
     @SuppressWarnings("UseOfObsoleteCollectionType")
     public GridCoverageBuilder addImageProperty(final String key, final Object 
value) {
-        if (properties.putIfAbsent(requireNonNull(key, "key"), 
requireNonNull(value, "value")) != null) {
+        if (properties.putIfAbsent(Objects.requireNonNull(key, "key"), 
Objects.requireNonNull(value, "value")) != null) {
             throw new 
IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, 
key));
         }
         return this;
diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java 
b/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
index 3e4d1b77c9..e6e3125b05 100644
--- a/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
+++ b/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
@@ -22,7 +22,7 @@
  * @author  Thi Phuong Hao Nguyen (VNSC)
  * @author  Minh Chinh Vu (VNSC)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
  * @since   0.8
  */
 module org.apache.sis.storage.geotiff {
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
index 842426f4b8..61c02871cf 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
@@ -16,14 +16,23 @@
  */
 package org.apache.sis.storage.geotiff;
 
+import java.util.Arrays;
 import java.nio.file.Path;
 import java.nio.file.Files;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.awt.Dimension;
 import java.awt.image.BufferedImage;
 import java.awt.image.RenderedImage;
 import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.geometry.Envelopes;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.image.DataType;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStores;
-import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
@@ -31,6 +40,7 @@ import org.apache.sis.coverage.grid.PixelInCell;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridCoverageBuilder;
 import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.matrix.Matrix4;
 
@@ -48,11 +58,17 @@ import static 
org.opengis.test.Assertions.assertAxisDirectionsEqual;
 
 /**
  * integration tests for {@link GeoTiffStore}.
+ * This class tests indirectly (via {@link GeoTiffStore}) the {@link Reader} 
and {@link Writer} classes.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
 @SuppressWarnings("exports")
 public final class GeoTiffStoreTest extends TestCase {
+    /**
+     * Name of a test file for an untiled image with a single band in 
gray-scale.
+     */
+    static final String UNTILED = "untiled.tiff";
+
     /**
      * Creates a new test case.
      */
@@ -62,7 +78,7 @@ public final class GeoTiffStoreTest extends TestCase {
     /**
      * Tests writing an image with a non-linear vertical component in the 
"grid to CRS" transform.
      * This method merely tests that no exception is thrown during the 
execution, and that reading
-     * the image back can give back the three-dimensional <abbr>CRS</abbr>.
+     * the image gives back the three-dimensional <abbr>CRS</abbr>.
      *
      * @throws Exception if an error occurred while preparing or running the 
test.
      */
@@ -81,14 +97,14 @@ public final class GeoTiffStoreTest extends TestCase {
         final GridCoverage coverage = builder.build();
         final Path file = Files.createTempFile("sis-test-", ".tiff");
         try {
-            try (DataStore store = DataStores.openWritable(new 
StorageConnector(file), "GeoTIFF")) {
+            try (DataStore store = DataStores.openWritable(file, "GeoTIFF")) {
                 assertInstanceOf(GeoTiffStore.class, store).append(coverage, 
null);
             }
             /*
              * Read the image that we wrote in above block. This block merely 
tests that no exception is thrown,
              * and that the result has the expected number of dimensions, axis 
order and scale factors.
              */
-            try (DataStore store = DataStores.open(new StorageConnector(file), 
"GeoTIFF")) {
+            try (DataStore store = DataStores.open(file, "GeoTIFF")) {
                 GridCoverageResource r = 
assertSingleton(assertInstanceOf(GeoTiffStore.class, store).components());
                 GridGeometry gg = r.getGridGeometry();
                 assertEquals(3, gg.getDimension());
@@ -109,4 +125,47 @@ public final class GeoTiffStoreTest extends TestCase {
             Files.delete(file);
         }
     }
+
+    /**
+     * Writes an image and compare with the {@code "untiled.tiff"} file.
+     * This is an anti-regression test, as this test does not inspect the
+     * content of the file.
+     *
+     * @throws TransformException if an error occurred while computing the 
domain of the image.
+     * @throws DataStoreException if an error occurred while writing the 
GeoTIFF file.
+     * @throws IOException if an error occurred while reading the file of 
expected content.
+     */
+    @Test
+    public void testWriteUntiled() throws TransformException, 
DataStoreException, IOException {
+        var geographicArea = new GeneralEnvelope(CommonCRS.WGS84.geographic());
+        geographicArea.setRange(0,  32,  40);   // Range of latitude values.
+        geographicArea.setRange(1, 137, 140);   // Range of longitude values.
+        final GridCoverage coverage = new GridCoverageBuilder()
+                .setDomain(Envelopes.transform(geographicArea, 
CommonCRS.WGS84.universal(35, 139)))
+                .setValues(DataType.BYTE, new Dimension(32, 16), (x, y) -> 100 
* y + x)
+                .flipGridAxis(1)
+                .build();
+
+        final var buffer = new ByteArrayOutputStream(2284);
+        try (DataStore ds = DataStores.openWritable(buffer, "geotiff")) {
+            assertInstanceOf(GeoTiffStore.class, ds).append(coverage, null);
+        }
+        final byte[] actual = buffer.toByteArray();
+        final byte[] expected;
+        try (InputStream in = 
GeoTiffStoreTest.class.getResourceAsStream(UNTILED)) {
+            assertNotNull(in, UNTILED);
+            expected = in.readAllBytes();
+        }
+        /*
+         * We tolerance mismatch far enough in the file, because they may be 
caused
+         * by differences in the way that the CRS is encoded. So we verify 
that at
+         * least the beginning of the header matches.
+         */
+        final int i = Arrays.mismatch(expected, actual);
+        if (i >= 0 && i < 1000) {
+            assertArrayEquals(expected, actual);
+        } else {
+            assertEquals(expected.length, actual.length);
+        }
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/ReaderTest.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/ReaderTest.java
index 360d928fa8..fd9afada3a 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/ReaderTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/ReaderTest.java
@@ -41,6 +41,8 @@ import org.apache.sis.test.TestCase;
 
 /**
  * Tests a few read operations.
+ * Despite the name of this test class, the {@link Reader} class is not tested 
directly
+ * but indirectly via {@link GeoTiffStore}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  *
@@ -48,11 +50,6 @@ import org.apache.sis.test.TestCase;
  */
 @SuppressWarnings("exports")
 public class ReaderTest extends TestCase {
-    /**
-     * Name of the test file.
-     */
-    private static final String FILENAME = "untiled.tiff";
-
     /**
      * Creates a new test case.
      */
@@ -66,7 +63,7 @@ public class ReaderTest extends TestCase {
      * @throws DataStoreException if an error occurred while creating the data 
store.
      */
     private static GeoTiffStore createStore() throws DataStoreException {
-        return new GeoTiffStore(null, new 
StorageConnector(ReaderTest.class.getResource(FILENAME)));
+        return new GeoTiffStore(null, new 
StorageConnector(ReaderTest.class.getResource(GeoTiffStoreTest.UNTILED)));
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java
index 71f318e57c..2c11154faa 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/WriterTest.java
@@ -57,6 +57,8 @@ import 
org.apache.sis.referencing.operation.HardCodedConversions;
 
 /**
  * Tests {@link Writer}.
+ * Despite the name of this test class, the {@link Writer} class is not tested 
directly
+ * but indirectly via {@link GeoTiffStore}.
  *
  * @author  Erwan Roussel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -88,7 +90,7 @@ public final class WriterTest extends TestCase {
 
     /**
      * The channel where the image is written.
-     * The data can be obtained by a call to {@link 
ByteArrayChannel#toBuffer()}.
+     * The data can be obtained by a call to {@lingk 
ByteArrayChannel#toBuffer()}.
      */
     private ByteArrayChannel output;
 

Reply via email to