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 acd0b93002 Provide a better error message when an image cannot be 
rendered because of an invalid "grid to CRS" transform.
acd0b93002 is described below

commit acd0b93002a4d861eb7aa5dea75a38a8f2a106e4
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Feb 21 12:04:36 2026 +0100

    Provide a better error message when an image cannot be rendered because of 
an invalid "grid to CRS" transform.
---
 .../main/org/apache/sis/image/ImageProcessor.java  |   4 +-
 .../iso/extent/NotSpatioTemporalException.java     |   4 +-
 .../org.apache.sis.portrayal/main/module-info.java |   2 +-
 .../org/apache/sis/map/coverage/RenderingData.java |  46 ++++++++++
 .../org/apache/sis/map/internal/Resources.java     | 102 +++++++++++++++++++++
 .../apache/sis/map/internal/Resources.properties   |  23 +++++
 .../apache/sis/map/internal/Resources_en.java}     |  32 ++-----
 .../apache/sis/map/internal/Resources_fr.java}     |  32 ++-----
 .../sis/map/internal/Resources_fr.properties       |  28 ++++++
 .../apache/sis/map/internal/package-info.java}     |  30 ++----
 .../main/org/apache/sis/geometry/Shapes2D.java     |   2 +-
 .../org/apache/sis/gui/internal/LogHandler.java    |   2 +-
 12 files changed, 231 insertions(+), 76 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageProcessor.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageProcessor.java
index a5e8c35960..2d4391ebb9 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageProcessor.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageProcessor.java
@@ -1125,11 +1125,11 @@ public class ImageProcessor implements Cloneable {
     }
 
     /**
-     * Verifies that the given rectangle, if non-null, is non-empty.
+     * Verifies that the given rectangle is non-empty.
      * This method assumes that the argument name is "bounds".
      */
     private static void ensureNonEmpty(final Rectangle bounds) {
-        if (bounds != null && bounds.isEmpty()) {
+        if (bounds.isEmpty()) {
             throw new 
IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "bounds"));
         }
     }
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/NotSpatioTemporalException.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/NotSpatioTemporalException.java
index 1c4b4823ce..229117c07e 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/NotSpatioTemporalException.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/NotSpatioTemporalException.java
@@ -26,8 +26,8 @@ import org.apache.sis.util.resources.Errors;
 
 /**
  * Thrown when an envelope cannot be transformed to a geographic, vertical or 
temporal extent.
- * This exception occurs when the envelope Coordinate Reference System (CRS) 
has no spatial or temporal component.
- * For example, it may be an engineering CRS.
+ * This exception occurs when the envelope Coordinate Reference System 
(<abbr>CRS</abbr>) has
+ * no spatial or temporal component. For example, it may be an engineering 
<abbr>CRS</abbr>.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.5
diff --git a/endorsed/src/org.apache.sis.portrayal/main/module-info.java 
b/endorsed/src/org.apache.sis.portrayal/main/module-info.java
index af2abe2d2f..667ff94334 100644
--- a/endorsed/src/org.apache.sis.portrayal/main/module-info.java
+++ b/endorsed/src/org.apache.sis.portrayal/main/module-info.java
@@ -20,7 +20,7 @@
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
  * @since   1.2
  */
 module org.apache.sis.portrayal {
diff --git 
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
index 6b8a2ff765..3792d369ea 100644
--- 
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/coverage/RenderingData.java
@@ -20,6 +20,8 @@ import java.util.Map;
 import java.util.List;
 import java.util.HashMap;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.Locale;
 import java.util.logging.Logger;
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -30,6 +32,7 @@ import java.awt.image.RenderedImage;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
+import org.opengis.util.GenericName;
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.metadata.extent.GeographicBoundingBox;
@@ -68,9 +71,12 @@ import org.apache.sis.math.Statistics;
 import org.apache.sis.measure.Quantities;
 import org.apache.sis.measure.Units;
 import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.matrix.AffineTransforms2D;
+import org.apache.sis.map.internal.Resources;
+import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.portrayal.PlanarCanvas;       // For javadoc.
 
@@ -248,6 +254,11 @@ public class RenderingData implements CloneAccess {
      */
     public final ImageProcessor processor;
 
+    /**
+     * The locale for error message, or {@code null} for the default locale.
+     */
+    public Locale locale;
+
     /**
      * Creates a new instance initialized to no image.
      *
@@ -668,6 +679,10 @@ public class RenderingData implements CloneAccess {
         bounds.y      = (int)  Math.ceil (resampled.getMinY() - 
Numerics.COMPARISON_THRESHOLD);
         bounds.width  = (int) (Math.floor(resampled.getMaxX() + 
Numerics.COMPARISON_THRESHOLD) - bounds.x);
         bounds.height = (int) (Math.floor(resampled.getMaxY() + 
Numerics.COMPARISON_THRESHOLD) - bounds.y);
+        if (bounds.isEmpty() || !Double.isFinite(resampled.getWidth()) || 
!Double.isFinite(resampled.getHeight())) {
+            throw new TransformException(Resources.forLocale(locale)
+                    .getString(Resources.Keys.InvalidRasterToCRS_2, 
getDataName(), getCRSName()));
+        }
         /*
          * Verify if wraparound is really necessary. We do this check because 
the `displayToCenter` transform
          * may be used for every pixels, so it is worth to make that transform 
more efficient if possible.
@@ -881,6 +896,37 @@ public class RenderingData implements CloneAccess {
         return (previous.dataGeometry != dataGeometry) || 
(previous.objectiveToCenter != objectiveToCenter);
     }
 
+    /**
+     * Returns the identifier of the <abbr>CRS</abbr> of the data, or 
"unnamed" (potentially localized) if unknown.
+     * This is used for error reporting.
+     */
+    private String getCRSName() {
+        if (dataGeometry.isDefined(GridGeometry.CRS)) {
+            String name = 
IdentifiedObjects.getDisplayName(dataGeometry.getCoordinateReferenceSystem(), 
locale);
+            if (name != null) {
+                return name;
+            }
+        }
+        return Vocabulary.forLocale(locale).getString(Vocabulary.Keys.Unnamed);
+    }
+
+    /**
+     * Returns the identifier of the data to render, or "unnamed" (potentially 
localized) if unknown.
+     * This is used for error reporting.
+     */
+    private String getDataName() {
+        final MultiResolutionCoverageLoader loader = coverageLoader;
+        if (loader != null) try {
+            Optional<GenericName> name = loader.resource.getIdentifier();
+            if (name.isPresent()) {
+                return name.get().toString();
+            }
+        } catch (DataStoreException e) {
+            recoverableException(e);
+        }
+        return Vocabulary.forLocale(locale).getString(Vocabulary.Keys.Unnamed);
+    }
+
     /**
      * Invoked when an exception occurred while computing a transform but the 
painting process can continue.
      * This method pretends that the warning come from {@link PlanarCanvas} 
class since it is the public API.
diff --git 
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.java
 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.java
new file mode 100644
index 0000000000..e80ebd1814
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.java
@@ -0,0 +1,102 @@
+/*
+ * 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.map.internal;
+
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import org.apache.sis.util.resources.KeyConstants;
+import org.apache.sis.util.resources.IndexedResourceBundle;
+
+
+/**
+ * Messages that are specific to the {@code org.apache.sis.portrayal} module.
+ * Resources in this file should not be used by any other module. For 
resources shared by
+ * all modules in the Apache SIS project, see {@code 
org.apache.sis.util.resources} package.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public class Resources extends IndexedResourceBundle {
+    /**
+     * Resource keys. This class is used when compiling sources, but no 
dependencies to
+     * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
+     * inlines final integer values, using long identifiers will not bloat the 
constant
+     * pools of compiled classes.
+     */
+    public static final class Keys extends KeyConstants {
+        /**
+         * The unique instance of key constants handler.
+         */
+        static final Keys INSTANCE = new Keys();
+
+        /**
+         * For {@link #INSTANCE} creation only.
+         */
+        private Keys() {
+        }
+
+        /**
+         * The “{0}” resource specifies an invalid conversion from pixel 
coordinates to the “{1}”
+         * coordinate reference system.
+         */
+        public static final short InvalidRasterToCRS_2 = 1;
+    }
+
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name as this class.
+     */
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module as the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
+    }
+
+    /**
+     * Returns the handle for the {@code Keys} constants.
+     *
+     * @return a handler for the constants declared in the inner {@code Keys} 
class.
+     */
+    @Override
+    protected KeyConstants getKeyConstants() {
+        return Keys.INSTANCE;
+    }
+
+    /**
+     * Returns resources in the given locale.
+     *
+     * @param  locale  the locale, or {@code null} for the default locale.
+     * @return resources in the given locale.
+     * @throws MissingResourceException if resources cannot be found.
+     */
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.properties
 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.properties
new file mode 100644
index 0000000000..ace4765055
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources.properties
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+#
+# Resources in this file are for `org.apache.sis.portrayal` usage only and 
should not be used by any other module.
+# For resources shared by all modules in the Apache SIS project, see 
"org.apache.sis.util.resources" package.
+#
+
+InvalidRasterToCRS_2 = The \u201c{0}\u201d resource specifies an invalid 
conversion from pixel coordinates to the \u201c{1}\u201d coordinate reference 
system.
diff --git a/endorsed/src/org.apache.sis.portrayal/main/module-info.java 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_en.java
similarity index 51%
copy from endorsed/src/org.apache.sis.portrayal/main/module-info.java
copy to 
endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_en.java
index af2abe2d2f..a8811c8148 100644
--- a/endorsed/src/org.apache.sis.portrayal/main/module-info.java
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_en.java
@@ -14,31 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.map.internal;
+
 
 /**
- * Raster imagery and geometry features.
- *
- * @author  Johann Sorel (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
- * @since   1.2
+ * Resource in English language.
  */
-module org.apache.sis.portrayal {
-    requires transitive org.apache.sis.storage;
-    requires jakarta.xml.bind;
-
-    exports org.apache.sis.style;
-    exports org.apache.sis.portrayal;
-
-    exports org.apache.sis.map.coverage to
-            org.apache.sis.gui;                         // In the "optional" 
sub-project.
-
-    exports org.apache.sis.style.se1 to
-            org.apache.sis.portrayal.map;               // In the "incubator" 
sub-project.
-
-    /*
-     * Allow JAXB to use reflection for marshalling and
-     * unmarshalling Apache SIS objects in XML documents.
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name as this class.
      */
-    opens org.apache.sis.style.se1 to jakarta.xml.bind;
+    public Resources_en() {
+    }
 }
diff --git a/endorsed/src/org.apache.sis.portrayal/main/module-info.java 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.java
similarity index 51%
copy from endorsed/src/org.apache.sis.portrayal/main/module-info.java
copy to 
endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.java
index af2abe2d2f..207283741a 100644
--- a/endorsed/src/org.apache.sis.portrayal/main/module-info.java
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.java
@@ -14,31 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.map.internal;
+
 
 /**
- * Raster imagery and geometry features.
- *
- * @author  Johann Sorel (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
- * @since   1.2
+ * Messages in French language.
  */
-module org.apache.sis.portrayal {
-    requires transitive org.apache.sis.storage;
-    requires jakarta.xml.bind;
-
-    exports org.apache.sis.style;
-    exports org.apache.sis.portrayal;
-
-    exports org.apache.sis.map.coverage to
-            org.apache.sis.gui;                         // In the "optional" 
sub-project.
-
-    exports org.apache.sis.style.se1 to
-            org.apache.sis.portrayal.map;               // In the "incubator" 
sub-project.
-
-    /*
-     * Allow JAXB to use reflection for marshalling and
-     * unmarshalling Apache SIS objects in XML documents.
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name as this class.
      */
-    opens org.apache.sis.style.se1 to jakarta.xml.bind;
+    public Resources_fr() {
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.properties
 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.properties
new file mode 100644
index 0000000000..2a9ad0c9e2
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/Resources_fr.properties
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+#
+# Resources in this file are for `org.apache.sis.portrayal` usage only and 
should not be used by any other module.
+# For resources shared by all modules in the Apache SIS project, see 
"org.apache.sis.util.resources" package.
+#
+# Punctuation rules in French (source: 
http://unicode.org/udhr/n/notes_fra.html)
+#
+#   U+202F NARROW NO-BREAK SPACE  before  ; ! and ?
+#   U+00A0 NO-BREAK SPACE         before  :
+#
+
+InvalidRasterToCRS_2 = La ressource \u00ab\u202f{0}\u202f\u00bb sp\u00e9cifie 
une conversion invalide des coordonn\u00e9es pixels vers le syst\u00e8me de 
r\u00e9f\u00e9rence des coordonn\u00e9es \u00ab\u202f{1}\u202f\u00bb.
diff --git a/endorsed/src/org.apache.sis.portrayal/main/module-info.java 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/package-info.java
similarity index 53%
copy from endorsed/src/org.apache.sis.portrayal/main/module-info.java
copy to 
endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/package-info.java
index af2abe2d2f..a5557757a8 100644
--- a/endorsed/src/org.apache.sis.portrayal/main/module-info.java
+++ 
b/endorsed/src/org.apache.sis.portrayal/main/org/apache/sis/map/internal/package-info.java
@@ -16,29 +16,13 @@
  */
 
 /**
- * Raster imagery and geometry features.
+ * A set of helper classes for the SIS implementation.
+ *
+ * <STRONG>Do not use!</STRONG>
+ *
+ * This package is for internal use by SIS only. Classes in this package
+ * may change in incompatible ways in any future version without notice.
  *
- * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
- * @since   1.2
  */
-module org.apache.sis.portrayal {
-    requires transitive org.apache.sis.storage;
-    requires jakarta.xml.bind;
-
-    exports org.apache.sis.style;
-    exports org.apache.sis.portrayal;
-
-    exports org.apache.sis.map.coverage to
-            org.apache.sis.gui;                         // In the "optional" 
sub-project.
-
-    exports org.apache.sis.style.se1 to
-            org.apache.sis.portrayal.map;               // In the "incubator" 
sub-project.
-
-    /*
-     * Allow JAXB to use reflection for marshalling and
-     * unmarshalling Apache SIS objects in XML documents.
-     */
-    opens org.apache.sis.style.se1 to jakarta.xml.bind;
-}
+package org.apache.sis.map.internal;
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Shapes2D.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Shapes2D.java
index 8196510f19..433dedafa6 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Shapes2D.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Shapes2D.java
@@ -218,7 +218,7 @@ public final class Shapes2D {
         double ymin = Double.POSITIVE_INFINITY;
         double xmax = Double.NEGATIVE_INFINITY;
         double ymax = Double.NEGATIVE_INFINITY;
-        final WraparoundInEnvelope.Controller wc = new 
WraparoundInEnvelope.Controller(transform);
+        final var wc = new WraparoundInEnvelope.Controller(transform);
         do {
             /*
              * Notation (as if we were applying a map projection, but this is 
not necessarily the case):
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/LogHandler.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/LogHandler.java
index 000a6704e1..4925812218 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/LogHandler.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/LogHandler.java
@@ -88,7 +88,7 @@ public final class LogHandler extends Handler implements 
StoreListener<WarningEv
          * Names of all logger in the {@link #queue} list, associated to a 
count of occurrences.
          * The occurrence count is used for detecting when to remove an entry 
from the map.
          */
-        private TreeMap<String,Integer> nameCount;
+        private TreeMap<String, Integer> nameCount;
 
         /**
          * Root of a tree of logger names. Created when first needed.

Reply via email to