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 09ee4ee  Make easier to build a sample dimension with a background 
value but no category. This is necessary for keeping RGB images as "for 
visualization only" images.
09ee4ee is described below

commit 09ee4ee7d4cb84ecd52988d6a1bc64b1e213f638
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Thu Dec 30 16:51:28 2021 +0100

    Make easier to build a sample dimension with a background value but no 
category.
    This is necessary for keeping RGB images as "for visualization only" images.
---
 .../org/apache/sis/coverage/SampleDimension.java   | 75 ++++++++++++++--------
 .../sis/internal/coverage/SampleDimensions.java    | 41 ------------
 .../sis/internal/coverage/j2d/Colorizer.java       | 20 +++---
 .../sis/internal/map/coverage/RenderingData.java   |  2 +-
 .../java/org/apache/sis/storage/landsat/Band.java  |  2 +-
 .../sis/internal/geotiff/SchemaModifier.java       | 16 ++---
 .../sis/storage/geotiff/ImageFileDirectory.java    |  6 +-
 .../sis/internal/sql/postgis/RasterReader.java     |  6 +-
 8 files changed, 71 insertions(+), 97 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
index 819634f..3d0af60 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/coverage/SampleDimension.java
@@ -77,7 +77,7 @@ import org.apache.sis.util.Debug;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.1
+ * @version 1.2
  *
  * @see org.opengis.metadata.content.SampleDimension
  *
@@ -591,6 +591,22 @@ public class SampleDimension implements Serializable {
         }
 
         /**
+         * Returns the name specified by the last call to a {@code setName(…)} 
method.
+         * If {@code setName(…)} has not been invoked or if {@link #clear()} 
has been invoked after,
+         * then this method returns {@code null}. In that case the {@link 
#build()} method will default
+         * to the name of the first quantitative category if present, or 
"Untitled" (localized) otherwise.
+         *
+         * @return the name explicitly set by last call to {@code setName(…)}, 
or {@code null} if none or cleared.
+         *
+         * @see SampleDimension#getName()
+         *
+         * @since 1.2
+         */
+        public GenericName getName() {
+            return dimensionName;
+        }
+
+        /**
          * Sets an identification of the sample dimension.
          * This is the value to be returned by {@link 
SampleDimension#getName()}.
          * If this method is invoked more than once, then the last specified 
name prevails
@@ -680,22 +696,35 @@ public class SampleDimension implements Serializable {
         }
 
         /**
-         * Returns the background value to use by default if none were 
explicitly defined.
-         * This method is invoked at {@linkplain #build() build} time
-         * if the {@link #setBackground(CharSequence, Number)} method has 
never been invoked
-         * since {@code Builder} construction or since the last call to {@link 
#clear()}.
-         * The background value returned by this method is not associated to 
any category.
+         * Returns the value specified by the last call to a {@code 
setBackground(…)} method.
+         * If {@code setBackground(…)} has not been invoked or if {@link 
#clear()} has been invoked after,
+         * then this method returns {@code null}.
+         *
+         * @return the value set by last call to {@code setBackground(…)}, or 
{@code null} if none or cleared.
+         *
+         * @see SampleDimension#getBackground()
          *
-         * <p>The default implementation returns {@code null}.
-         * Subclasses can override this method and compute a background value
-         * for example by analyzing the content of {@link #categories()} 
list.</p>
+         * @since 1.2
+         */
+        public Number getBackground() {
+            return toNaN.background;
+        }
+
+        /**
+         * Sets the background value without creating a category (typically 
for RGB images).
+         * An image without category is interpreted as an image for 
visualization purposes only,
+         * without values that we can associate to a unit of measurement or a 
qualitative meaning.
+         * This {@code setBackground(Number)} method can be invoked when the 
caller nevertheless
+         * wants to declare a background value used for filling empty spaces 
(e.g. in image corners).
          *
-         * @return the default background value, or {@code null} if none.
+         * @param  sample  the background value, or {@code null} if none.
+         * @return {@code this}, for method call chaining.
          *
          * @since 1.2
          */
-        protected Number defaultBackground() {
-            return null;
+        public Builder setBackground(final Number sample) {
+            toNaN.background = sample;
+            return this;
         }
 
         /**
@@ -705,7 +734,7 @@ public class SampleDimension implements Serializable {
          * (previous values become ordinary qualitative categories).
          *
          * @param  name    the category name as a {@link String} or {@link 
InternationalString} object,
-         *                 or {@code null} for a default "fill value" name.
+         *                 or {@code null} for a default "fill value" 
(localized) name.
          * @param  sample  the background value.
          * @return {@code this}, for method call chaining.
          */
@@ -998,19 +1027,12 @@ public class SampleDimension implements Serializable {
             ArgumentChecks.ensureNonNull("samples", samples);
             ArgumentChecks.ensureNonNull("converted", converted);
             /*
-             * We need to perform calculation using the same "included versus 
excluded" characteristics for sample and converted
-             * values. We pickup the characteristics of the range using 
floating point values because it is easier to adjust the
-             * bounds of the range using integer values (we just add or 
subtract 1 for integers, while the amount to add to real
-             * numbers is not so clear). If both ranges use floating point 
values, arbitrarily adjust the converted values.
+             * We need to perform calculation using the same "included versus 
excluded" characteristics for sample
+             * and converted values. We pickup the characteristics of the 
sample values range (except for avoiding
+             * a division by zero) because it is the range that describes the 
source data.
              */
-            final boolean isMinIncluded, isMaxIncluded;
-            if (Numbers.isInteger(samples.getElementType())) {
-                isMinIncluded = converted.isMinIncluded();                     
    // This is the usual case.
-                isMaxIncluded = converted.isMaxIncluded();
-            } else {
-                isMinIncluded = samples.isMinIncluded();                       
     // Less common case.
-                isMaxIncluded = samples.isMaxIncluded();
-            }
+            final boolean isMinIncluded = samples.isMinIncluded();
+            final boolean isMaxIncluded = samples.isMaxIncluded() && 
samples.getSpan() > 0;     // `isEmpty()` is not sufficient.
             final double minValue  = converted.getMinDouble(isMinIncluded);
             final double Δvalue    = converted.getMaxDouble(isMaxIncluded) - 
minValue;
             final double minSample =   samples.getMinDouble(isMinIncluded);
@@ -1175,9 +1197,6 @@ defName:    if (name == null) {
                 }
                 name = 
createLocalName(Vocabulary.formatInternational(Vocabulary.Keys.Untitled));
             }
-            if (toNaN.background == null) {
-                toNaN.background = defaultBackground();
-            }
             return new SampleDimension(name, toNaN.background, 
UnmodifiableArrayList.wrap(categories, 0, count));
         }
 
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/SampleDimensions.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/SampleDimensions.java
index 4131f8a..c0121ec 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/SampleDimensions.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/SampleDimensions.java
@@ -23,8 +23,6 @@ import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.Category;
 import org.apache.sis.image.ImageProcessor;
 import org.apache.sis.measure.NumberRange;
-import org.apache.sis.internal.util.Numerics;
-import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.Static;
 
 
@@ -111,43 +109,4 @@ public final class SampleDimensions extends Static {
         }
         return sampleFilters;
     }
-
-    /**
-     * Adds categories to the given sample dimension builder for an image 
having no explicit transfer function.
-     * This method creates a default transfer function only if needed, for 
example if a "no data" value exists.
-     * If the transfer function would be identity, then this method does not 
add it even if {@code sampleRange}
-     * was non-null. This conservative policy is because the purpose of this 
method is only to avoid that image
-     * operations such as resampling do their calculations on wrong values. If 
we can avoid to create artificial
-     * information that did not existed in the original data, it is better.
-     *
-     * @param  sampleSize   size of sample values in bits, or 0 if unknown or 
if sample are floating-point values.
-     * @param  isUnsigned   whether sample values are unsigned integers. 
Ignored if {@code sampleSize} is 0.
-     * @param  sampleRange  minimum and maximum sample values, or {@code null} 
if unknown.
-     * @param  fillValue    the "no data" value, or {@code null} if none. May 
intersect {@code sampleRange}.
-     * @param  dest         where to add the categories.
-     */
-    public static void addDefaultCategories(final int sampleSize, final 
boolean isUnsigned, NumberRange<?> sampleRange,
-                                            final Number fillValue, final 
SampleDimension.Builder dest)
-    {
-        if (fillValue != null) {
-            dest.setBackground(null, fillValue);
-            if (sampleRange == null && sampleSize != 0) {
-                long min = 0, max = Numerics.bitmask(sampleSize) - 1;
-                if (!isUnsigned) {
-                    max >>>= 1;
-                    min = ~max;
-                }
-                sampleRange = NumberRange.createBestFit(min, true, max, true);
-            }
-            if (sampleRange != null && sampleRange.containsAny(fillValue)) {
-                final double fill = fillValue.doubleValue();
-                if (sampleRange.getMaxDouble() - fill < fill - 
sampleRange.getMinDouble()) {
-                    sampleRange = 
NumberRange.createBestFit(sampleRange.getMinValue(), 
sampleRange.isMinIncluded(), fill, false);
-                } else {
-                    sampleRange = NumberRange.createBestFit(fill, false, 
sampleRange.getMaxValue(), sampleRange.isMaxIncluded());
-                }
-                
dest.addQuantitative(Vocabulary.formatInternational(Vocabulary.Keys.Values), 
sampleRange, sampleRange);
-            }
-        }
-    }
 }
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/Colorizer.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/Colorizer.java
index 26e1c45..83468e2 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/Colorizer.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/Colorizer.java
@@ -418,7 +418,6 @@ reuse:  if (source != null) {
         for (int i=0; i<count; i++) {
             final ColorsForRange entry = entries[i];
             NumberRange<?> sourceRange = entry.sampleRange;
-            final double s = sourceRange.getSpan();
             if (!entry.isData()) {
                 if (lower >= MAX_VALUE) {
                     throw new 
IllegalArgumentException(Resources.format(Resources.Keys.TooManyQualitatives));
@@ -444,15 +443,18 @@ reuse:  if (source != null) {
                         themes = (themes != null) ? 
themes.unionAny(sourceRange) : sourceRange;
                     }
                 }
-            } else if (s > 0) {
-                // Range of real values: defer processing to next loop.
-                span += s;
-                System.arraycopy(entries, deferred, entries, deferred + 1, i - 
deferred);
-                entries[deferred++] = entry;
             } else {
-                // Invalid range: silently discard.
-                System.arraycopy(entries, i+1, entries, i, --count - i);
-                entries[count] = null;
+                final double s = sourceRange.getSpan();
+                if (s > 0) {
+                    // Range of real values: defer processing to next loop.
+                    span += s;
+                    System.arraycopy(entries, deferred, entries, deferred + 1, 
i - deferred);
+                    entries[deferred++] = entry;
+                } else {
+                    // Invalid range: silently discard.
+                    System.arraycopy(entries, i+1, entries, i, --count - i);
+                    entries[count] = null;
+                }
             }
         }
         /*
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
index bff4c87..994ec06 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/RenderingData.java
@@ -325,7 +325,7 @@ public class RenderingData implements Cloneable {
         }
         data = null;
         currentPyramidLevel = level;
-        return coverageLoader.getOrLoad(level).forConvertedValues(true);
+        return coverageLoader.getOrLoad(level);
     }
 
     /**
diff --git 
a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/landsat/Band.java
 
b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/landsat/Band.java
index dd9b4dd..52aa27f 100644
--- 
a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/landsat/Band.java
+++ 
b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/landsat/Band.java
@@ -193,7 +193,7 @@ final class Band extends GridResourceWrapper implements 
SchemaModifier {
      */
     @Override
     public SampleDimension customize(final int image, final int band, final 
NumberRange<?> sampleRange,
-                                     final Number fillValue, final 
SampleDimension.Builder dimension)
+                                     final SampleDimension.Builder dimension)
     {
         if ((image | band) == 0) {
             dimension.setName(identifier);
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
index 4f0f24c..6d19bab 100644
--- 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
@@ -20,7 +20,6 @@ import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.setup.OptionKey;
-import org.apache.sis.internal.coverage.SampleDimensions;
 import org.apache.sis.internal.storage.io.InternalOptionKey;
 import org.apache.sis.storage.DataStoreException;
 import org.opengis.metadata.Metadata;
@@ -76,25 +75,22 @@ public interface SchemaModifier {
     /**
      * Invoked when a sample dimension is created for a band in an image.
      * {@code GeoTiffStore} invokes this method with a builder initialized to 
band number as
-     * {@linkplain SampleDimension.Builder#setName(int) dimension name} and 
with no category.
-     * Implementations can override this method for setting a better name or 
for declaring the
-     * meaning of sample values (by adding "categories").
-     *
-     * <p>The default implementation creates categories only if {@code 
fillValue} is non-null.
-     * In such case, the fill value is also defined as the background 
value.</p>
+     * {@linkplain SampleDimension.Builder#setName(int) dimension name}, with 
the fill value
+     * declared as {@linkplain SampleDimension.Builder#setBackground(Number) 
background} and
+     * with no category. Implementations can override this method for setting 
a better name
+     * or for declaring the meaning of sample values (by adding "categories").
      *
      * @param  image        index of the image for which to create sample 
dimension.
      * @param  band         index of the band for which to create sample 
dimension.
      * @param  sampleRange  minimum and maximum values declared in the TIFF 
tags, or {@code null} if unknown.
-     * @param  fillValue    the "no data" value, or {@code null} if none. May 
intersect {@code sampleRange}.
+     *                      This range may contain the background value.
      * @param  dimension    a sample dimension builder initialized with band 
number as the dimension name.
      *                      This builder can be modified in-place.
      * @return the sample dimension to use.
      */
     default SampleDimension customize(final int image, final int band, 
NumberRange<?> sampleRange,
-                                      final Number fillValue, final 
SampleDimension.Builder dimension)
+                                      final SampleDimension.Builder dimension)
     {
-        SampleDimensions.addDefaultCategories(0, false, sampleRange, 
fillValue, dimension);
         return dimension.build();
     }
 
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index c7484ad..3e7a3f2 100644
--- 
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -1537,10 +1537,10 @@ final class ImageFileDirectory extends DataCube {
                                 minValues.get(Math.min(band, 
minValues.size()-1)), true,
                                 maxValues.get(Math.min(band, 
maxValues.size()-1)), true);
                     }
-                    builder.setName(band + 1);
+                    builder.setName(band + 
1).setBackground(getFillValue(true));
                     final SampleDimension sd;
                     if (isIndexValid) {
-                        sd = reader.store.customizer.customize(index, band, 
sampleRange, getFillValue(true), builder);
+                        sd = reader.store.customizer.customize(index, band, 
sampleRange, builder);
                     } else {
                         sd = builder.build();
                     }
@@ -1692,7 +1692,7 @@ final class ImageFileDirectory extends DataCube {
                         throw new 
DataStoreContentException(Errors.format(Errors.Keys.UnexpectedValueInElement_2, 
"numBands", numBands));
                     }
                     final boolean hasAlpha = (numBands >= 4);
-                    final boolean packed = sm instanceof 
SinglePixelPackedSampleModel;
+                    final boolean packed = (sm instanceof 
SinglePixelPackedSampleModel);
                     colorModel = ColorModelFactory.createRGB(bitsPerSample, 
packed, hasAlpha);
                     break;
                 }
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
index 82061cd..6f7e917 100644
--- 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java
@@ -44,7 +44,6 @@ import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridCoverage2D;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
-import org.apache.sis.internal.coverage.SampleDimensions;
 import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
 import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -383,9 +382,8 @@ public final class RasterReader extends RasterFormat {
                     // See `Band.OPPOSITE_SIGN` javadoc for more information 
on this limitation.
                     throw new RasterFormatException("Data type not yet 
supported.");
                 }
-                SampleDimensions.addDefaultCategories(band.getDataTypeSize(), 
band.isUnsigned(), null,
-                                                      band.noDataValue, 
builder.setName(b + 1));
-                sd[b] = builder.build();
+                sd[b] = builder.setName(b + 
1).setBackground(band.noDataValue).build();
+                builder.clear();
             }
             range = Arrays.asList(sd);
         }

Reply via email to