This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits 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 38bc219527 Build a gray scale instead of index color model when 
possible. The use of gray scale allows interpolations, contrarily to index 
color model.
38bc219527 is described below

commit 38bc2195273df13aad446f0512939d6632ab5c3e
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Apr 22 18:59:41 2026 +0200

    Build a gray scale instead of index color model when possible.
    The use of gray scale allows interpolations, contrarily to index color 
model.
---
 .../image/internal/shared/ColorModelFactory.java   |  53 ++++++++++++++-------
 .../sis/storage/geotiff/GeoTiffStoreTest.java      |   4 +-
 .../test/org/apache/sis/storage/geotiff/tiled.tiff | Bin 3882 -> 2334 bytes
 .../org/apache/sis/storage/geotiff/untiled.tiff    | Bin 2602 -> 1054 bytes
 4 files changed, 39 insertions(+), 18 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/ColorModelFactory.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/ColorModelFactory.java
index 5bc95fb109..3618a131b6 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/ColorModelFactory.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/ColorModelFactory.java
@@ -358,23 +358,24 @@ public final class ColorModelFactory {
         /*
          * If there are no categories, construct a gray scale palette.
          */
-        final int categoryCount = pieceStarts.length - 1;
-        if (numBands == 1 && categoryCount <= 0) {
-            final ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
-            final int[] numBits = {
-                DataBuffer.getDataTypeSize(dataType)
-            };
-            return unique(new ComponentColorModel(cs, numBits, false, true, 
Transparency.OPAQUE, dataType));
-        }
-        /*
-         * Interpolates the colors in the color palette. Colors that do not 
fall
-         * in the range of a category will be set to a transparent color.
-         */
         final int[] colorMap;
         int transparent = -1;
-        if (categoryCount <= 0) {
-            colorMap = ArraysExt.range(0, 256);
+        if (isGrayScale()) {
+            if (numBands == 1) {
+                final ColorSpace cs = 
ColorSpace.getInstance(ColorSpace.CS_GRAY);
+                final int[] numBits = {
+                    DataBuffer.getDataTypeSize(dataType)
+                };
+                return unique(new ComponentColorModel(cs, numBits, false, 
true, Transparency.OPAQUE, dataType));
+            }
+            colorMap = new int[256];
+            Arrays.setAll(colorMap, (i) -> 0xFF000000 | (i << 24) | (i << 16) 
| (i << 8) | i);
         } else {
+            /*
+             * Interpolates the colors in the color palette. Colors that do 
not fall
+             * in the range of a category will be set to a transparent color.
+             */
+            final int categoryCount = pieceStarts.length - 1;
             colorMap = new int[pieceStarts[categoryCount]];
             for (int i=0; i<categoryCount; i++) {
                 final int[] colors = ARGB[i];
@@ -435,8 +436,8 @@ public final class ColorModelFactory {
             final boolean hasAlpha, final int transparent)
     {
         /*
-         * No need to scan the ARGB values in search of a transparent pixel;
-         * the IndexColorModel constructor does that for us.
+         * No need to scan the ARGB values in search of a transparent pixel
+         * since the `IndexColorModel` constructor does that for us.
          */
         final int length = ARGB.length;
         if (numBits == 0) {
@@ -567,6 +568,26 @@ public final class ColorModelFactory {
         return Math.abs(minimum) < 1 && Math.abs(maximum - (upper - 0.5)) < 
1.5;
     }
 
+    /**
+     * Returns whether this factory is building a gray scale color model.
+     * A gray scale color model is preferred to an index color model because 
gray scale gives
+     * directly the intensity, while index color model is indirect (need to 
lookup in a table).
+     * Therefore, sample values associated to gray scale can be interpolated 
while sample values
+     * that are indexes cannot be interpolated easily.
+     */
+    private boolean isGrayScale() {
+        if (ARGB == null) {
+            return true;
+        }
+        switch (ARGB.length) {
+            default: return false;
+            case  0: return true;
+            case  1: break;
+        }
+        final int[] codes = ARGB[0];
+        return codes.length == 2 && codes[0] == 0xFF000000 && codes[1] == 
0xFFFFFFFF;
+    }
+
     /**
      * Creates a color model for opaque images storing pixels using the given 
sample model.
      * The color model can have an arbitrary number of bands, but in current 
implementation only one band is used.
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 fd5fe04b1e..5d495e9544 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
@@ -138,7 +138,7 @@ public final class GeoTiffStoreTest extends TestCase {
      */
     @Test
     public void testWriteUntiled() throws Exception {
-        testWrite(UNTILED, new Rectangle(32, 16), null, 2602);
+        testWrite(UNTILED, new Rectangle(32, 16), null, 1054);
     }
 
     /**
@@ -149,7 +149,7 @@ public final class GeoTiffStoreTest extends TestCase {
     @Test
     public void testWriteTiled() throws Exception {
         final var tileSize = new Dimension(16, 16);     // TIFF tile size must 
be multiple of 16.
-        testWrite(TILED, new Rectangle(tileSize.width * 3, tileSize.height * 
2), tileSize, 3882);
+        testWrite(TILED, new Rectangle(tileSize.width * 3, tileSize.height * 
2), tileSize, 2334);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/tiled.tiff
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/tiled.tiff
index 68195c9260..e767da887e 100644
Binary files 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/tiled.tiff
 and 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/tiled.tiff
 differ
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/untiled.tiff
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/untiled.tiff
index 451287f5cf..c3146ebafa 100644
Binary files 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/untiled.tiff
 and 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/untiled.tiff
 differ

Reply via email to