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 0e983e5d1ed879a8d94dcf4bf6450679065ea199 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Apr 22 19:04:07 2022 +0200 Move in a separated class some `AsciiGridStore` code which will be shared by BIL/BIP/BSQ data store. Add some convenience static methods will will be needed as well. --- .../main/java/org/apache/sis/image/DataType.java | 55 ++++++++- .../org/apache/sis/internal/feature/Resources.java | 5 + .../sis/internal/feature/Resources.properties | 1 + .../sis/internal/feature/Resources_fr.properties | 1 + .../java/org/apache/sis/image/DataTypeTest.java | 25 +++- .../org/apache/sis/internal/util/Numerics.java | 13 ++ .../java/org/apache/sis/util/resources/Errors.java | 5 + .../apache/sis/util/resources/Errors.properties | 1 + .../apache/sis/util/resources/Errors_fr.properties | 1 + .../sis/internal/storage/esri/AsciiGridStore.java | 70 ++--------- .../sis/internal/storage/esri/RasterStore.java | 131 +++++++++++++++++++++ .../sis/internal/storage/esri/package-info.java | 6 +- .../sis/internal/storage/image/WorldFileStore.java | 1 + 13 files changed, 249 insertions(+), 66 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java b/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java index f4c1c197e1..9c18299b04 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/DataType.java @@ -24,6 +24,7 @@ import org.apache.sis.util.ArgumentChecks; import org.apache.sis.measure.NumberRange; import org.apache.sis.internal.coverage.j2d.ImageUtilities; import org.apache.sis.internal.feature.Resources; +import org.apache.sis.util.resources.Errors; import static org.apache.sis.internal.util.Numerics.MAX_INTEGER_CONVERTIBLE_TO_FLOAT; @@ -33,7 +34,7 @@ import static org.apache.sis.internal.util.Numerics.MAX_INTEGER_CONVERTIBLE_TO_F * This is a type-safe version of the {@code TYPE_*} constants defined in {@link DataBuffer}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 1.1 * @module */ @@ -195,6 +196,58 @@ public enum DataType { } } + /** + * Returns the enumeration value for the given number of bits. + * Only the following combinations of argument values are accepted: + * + * <table class="sis"> + * <caption>Valid combinations of argument values</caption> + * <tr><th>size</th> <th>real</th> <th>signed</th></tr> + * <tr><td>1</td> <td>{@code false}</td> <td>{@code false}</td></tr> + * <tr><td>2</td> <td>{@code false}</td> <td>{@code false}</td></tr> + * <tr><td>4</td> <td>{@code false}</td> <td>{@code false}</td></tr> + * <tr><td>{@value Byte#SIZE}</td> <td>{@code false}</td> <td>{@code false}</td></tr> + * <tr><td>{@value Short#SIZE}</td> <td>{@code false}</td> <td>{@code false} or {@code true}</td></tr> + * <tr><td>{@value Integer#SIZE}</td> <td>{@code false}</td> <td>{@code true}</td></tr> + * <tr><td>{@value Float#SIZE}</td> <td>{@code true}</td> <td>ignored</td></tr> + * <tr><td>{@value Double#SIZE}</td> <td>{@code true}</td> <td>ignored</td></tr> + * </table> + * + * @param size number of bits as a power of 2 between 1 and {@value Double#SIZE} inclusive. + * @param real {@code true} for floating point numbers or {@code false} for integers. + * @param signed {@code true} for signed numbers of {@code false} for unsigned numbers. + * @return the data type (never {@code null}) for the given number of bits. + * @throws RasterFormatException if the combination of argument values is invalid. + * + * @since 1.2 + */ + public static DataType forNumberOfBits(final int size, final boolean real, final boolean signed) { + if (size < 1 || size > Double.SIZE || Integer.lowestOneBit(size) != size) { + throw new RasterFormatException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "size", size)); + } + String argument = "real"; // For reporting which argument is inconsistent with sample size. + boolean value = real; + if (real) { + switch (size) { + case Float.SIZE: return FLOAT; + case Double.SIZE: return DOUBLE; + } + } else { + if (size == Short.SIZE) { + return signed ? SHORT : USHORT; + } + final boolean isInt = (size == Integer.SIZE); + if (isInt || size <= Byte.SIZE) { + if (isInt == signed) { + return isInt ? INT : BYTE; + } + argument = "signed"; + value = signed; + } + } + throw new RasterFormatException(Resources.format(Resources.Keys.UnsupportedSampleType_3, size, argument, value)); + } + /** * Returns the size in bits of this data type. * diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java index 3a82bb6a71..71d22be341 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java @@ -454,6 +454,11 @@ public final class Resources extends IndexedResourceBundle { * Unsupported geometry {0}D object. */ public static final short UnsupportedGeometryObject_1 = 76; + + /** + * Sample type with a size of {0} bits can not have ‘{1}’ = “{2}” characteristic. + */ + public static final short UnsupportedSampleType_3 = 78; } /** diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties index 018e03ecb7..b2a78dd762 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties @@ -95,4 +95,5 @@ UnspecifiedCRS = Coordinate reference system is unspecified. UnspecifiedGridExtent = Grid extent is unspecified. UnspecifiedRasterData = Raster data are unspecified. UnspecifiedTransform = Coordinates transform is unspecified. +UnsupportedSampleType_3 = Sample type with a size of {0} bits can not have \u2018{1}\u2019\u202f=\u202f\u201c{2}\u201d characteristic. UnsupportedGeometryObject_1 = Unsupported geometry {0}D object. diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties index 1f08c3fd38..40d9f79027 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties @@ -100,4 +100,5 @@ UnspecifiedCRS = Le syst\u00e8me de r\u00e9f\u00e9rence des c UnspecifiedGridExtent = L\u2019\u00e9tendue de la grille n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9e. UnspecifiedRasterData = Les donn\u00e9es du raster n\u2019ont pas \u00e9t\u00e9 sp\u00e9cifi\u00e9es. UnspecifiedTransform = La transformation de coordonn\u00e9es n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9e. +UnsupportedSampleType_3 = Les types de valeurs sur {0} bits ne peuvent pas avoir la caract\u00e9ristique \u2018{1}\u2019\u202f=\u202f\u00ab\u202f{2}\u202f\u00bb. UnsupportedGeometryObject_1 = Object g\u00e9om\u00e9trique {0}D non-support\u00e9. diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/DataTypeTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/DataTypeTest.java index a0b6f60d0d..b427c1c649 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/image/DataTypeTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/image/DataTypeTest.java @@ -17,6 +17,7 @@ package org.apache.sis.image; import java.awt.image.DataBuffer; +import java.awt.image.RasterFormatException; import org.apache.sis.test.TestCase; import org.junit.Test; @@ -27,7 +28,7 @@ import static org.junit.Assert.*; * Verifies {@link DataType}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 1.1 * @module */ @@ -96,4 +97,26 @@ public final strictfp class DataTypeTest extends TestCase { assertEquals(DataType.FLOAT, DataType.FLOAT .toFloat()); assertEquals(DataType.DOUBLE, DataType.DOUBLE.toFloat()); } + + /** + * Tests {@link DataType#forNumberOfBits(int, boolean, boolean)}. + */ + @Test + public void testForNumberOfBits() { + assertEquals(DataType.BYTE, DataType.forNumberOfBits(1, false, false)); + assertEquals(DataType.BYTE, DataType.forNumberOfBits(Byte.SIZE, false, false)); + assertEquals(DataType.USHORT, DataType.forNumberOfBits(Short.SIZE, false, false)); + assertEquals(DataType.SHORT, DataType.forNumberOfBits(Short.SIZE, false, true)); + assertEquals(DataType.INT, DataType.forNumberOfBits(Integer.SIZE, false, true)); + assertEquals(DataType.FLOAT, DataType.forNumberOfBits(Float.SIZE, true, true)); + assertEquals(DataType.DOUBLE, DataType.forNumberOfBits(Double.SIZE, true, true)); + try { + DataType.forNumberOfBits(Byte.SIZE, false, true); + fail("Signed bytes should be invalid."); + } catch (RasterFormatException e) { + final String message = e.getMessage(); + assertTrue(message, message.contains("signed")); + assertTrue(message, message.contains("true")); + } + } } diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java index bb68a2b420..6f7bea5f17 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java +++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java @@ -224,6 +224,19 @@ public final class Numerics extends Static { return r; } + /** + * Returns x/y with the requirement that the division must be integer. + * + * @param x the dividend. + * @param y the divisor. + * @return x/y. + * @throws ArithmeticException if y is zero of if the result of x/y is not an integer. + */ + public static int wholeDiv(final int x, final int y) { + if ((x % y) != 0) throw new ArithmeticException(); + return x / y; // TODO: use Math.divideExact with JDK18. + } + /** * Returns {@code value} × {@code multiplier} / {@code divisor} with control against overflow. * The result is rounded toward zero. diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java index 4cf445a241..739c255be8 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java @@ -425,6 +425,11 @@ public final class Errors extends IndexedResourceBundle { */ public static final short IllegalPropertyValueClass_3 = 59; + /** + * Property “{0}” can not take the “{1}” value. + */ + public static final short IllegalPropertyValue_2 = 198; + /** * Range [{0} … {1}] is not valid. */ diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties index c052d47030..c0b3168576 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties @@ -94,6 +94,7 @@ IllegalLanguageCode_1 = The \u201c{0}\u201d language is not recogniz IllegalMapping_2 = Illegal mapping: {0} \u2192 {1}. IllegalMemberType_2 = Member \u201c{0}\u201d can not be associated to type \u201c{1}\u201d. IllegalOptionValue_2 = Option \u2018{0}\u2019 can not take the \u201c{1}\u201d value. +IllegalPropertyValue_2 = Property \u201c{0}\u201d can not take the \u201c{1}\u201d value. IllegalPropertyValueClass_2 = Property \u201c{0}\u201d does not accept instances of \u2018{1}\u2019. IllegalPropertyValueClass_3 = Expected an instance of \u2018{1}\u2019 for the \u201c{0}\u201d property, but got an instance of \u2018{2}\u2019. IllegalRange_2 = Range [{0} \u2026 {1}] is not valid. diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties index 9c1e1db682..b93ab77358 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties +++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties @@ -91,6 +91,7 @@ IllegalLanguageCode_1 = Le code de langue \u00ab\u202f{0}\u202f\u00b IllegalMapping_2 = Correspondance ill\u00e9gale: {0} \u2192 {1}. IllegalMemberType_2 = Le membre \u00ab\u202f{0}\u202f\u00bb ne peut pas \u00eatre associ\u00e9 au type \u00ab\u202f{1}\u202f\u00bb. IllegalOptionValue_2 = L\u2019option \u2018{0}\u2019 n\u2019accepte pas la valeur \u00ab\u202f{1}\u202f\u00bb. +IllegalPropertyValue_2 = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019accepte pas la valeur \u00ab\u202f{1}\u202f\u00bb. IllegalPropertyValueClass_2 = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019accepte pas les valeurs de type \u2018{1}\u2019. IllegalPropertyValueClass_3 = Une instance \u2018{1}\u2019 \u00e9tait attendue pour la propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb, mais la valeur donn\u00e9e est une instance de \u2018{2}\u2019. IllegalRange_2 = La plage [{0} \u2026 {1}] n\u2019est pas valide. diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/AsciiGridStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/AsciiGridStore.java index 9fa01da1cc..19d803778f 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/AsciiGridStore.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/AsciiGridStore.java @@ -18,16 +18,12 @@ package org.apache.sis.internal.storage.esri; import java.util.Map; import java.util.List; -import java.util.Optional; import java.util.StringJoiner; import java.io.IOException; import java.nio.file.StandardOpenOption; import java.awt.image.RenderedImage; import java.awt.image.DataBufferFloat; -import org.opengis.geometry.Envelope; import org.opengis.metadata.Metadata; -import org.opengis.metadata.maintenance.ScopeCode; -import org.opengis.referencing.operation.TransformException; import org.opengis.referencing.datum.PixelInCell; import org.apache.sis.coverage.SampleDimension; import org.apache.sis.coverage.grid.GridCoverage; @@ -40,15 +36,10 @@ import org.apache.sis.storage.StorageConnector; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.DataStoreClosedException; import org.apache.sis.storage.DataStoreContentException; -import org.apache.sis.storage.DataStoreReferencingException; -import org.apache.sis.storage.GridCoverageResource; -import org.apache.sis.internal.storage.MetadataBuilder; -import org.apache.sis.internal.storage.PRJDataStore; import org.apache.sis.internal.storage.RangeArgument; import org.apache.sis.internal.storage.Resources; import org.apache.sis.internal.storage.io.ChannelDataInput; import org.apache.sis.measure.NumberRange; -import org.apache.sis.metadata.sql.MetadataStoreException; import org.apache.sis.referencing.operation.matrix.Matrix3; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.util.resources.Errors; @@ -153,12 +144,11 @@ import org.apache.sis.util.resources.Errors; * @since 1.2 * @module */ -class AsciiGridStore extends PRJDataStore implements GridCoverageResource { +class AsciiGridStore extends RasterStore { /** * Keys of elements expected in the header. Must be in upper-case letters. */ static final String - NCOLS = "NCOLS", NROWS = "NROWS", XLLCORNER = "XLLCORNER", YLLCORNER = "YLLCORNER", XLLCENTER = "XLLCENTER", YLLCENTER = "YLLCENTER", CELLSIZE = "CELLSIZE", NODATA_VALUE = "NODATA_VALUE"; @@ -208,18 +198,6 @@ class AsciiGridStore extends PRJDataStore implements GridCoverageResource { */ private String nodataText; - /** - * The image size together with the "grid to CRS" transform. - * This is also used as a flag for checking whether the - * {@code "*.prj"} file and the header have been read. - */ - private GridGeometry gridGeometry; - - /** - * The metadata object, or {@code null} if not yet created. - */ - private Metadata metadata; - /** * The full coverage, read when first requested then cached. * We cache the full coverage on the assumption that the @@ -254,7 +232,6 @@ class AsciiGridStore extends PRJDataStore implements GridCoverageResource { if (channel != null) { input = new CharactersView(channel, channel.buffer); } - listeners.useWarningEventsOnly(); } /** @@ -406,45 +383,11 @@ cellsize: if (value != null) { @Override public synchronized Metadata getMetadata() throws DataStoreException { if (metadata == null) { - readHeader(); - final MetadataBuilder builder = new MetadataBuilder(); - try { - builder.setPredefinedFormat("ASCGRD"); - } catch (MetadataStoreException e) { - builder.addFormatName(AsciiGridStoreProvider.NAME); - listeners.warning(e); - } - builder.addEncoding(encoding, MetadataBuilder.Scope.METADATA); - builder.addResourceScope(ScopeCode.COVERAGE, null); - try { - builder.addExtent(gridGeometry.getEnvelope()); - } catch (TransformException e) { - throw new DataStoreReferencingException(getLocale(), AsciiGridStoreProvider.NAME, getDisplayName(), null).initCause(e); - } - /* - * Do not add the sample dimension, because in current version computing the sample dimension - * requires loading the full image. Even if the `band` field is already computed and could be - * used opportunistically, we do not use it in order to keep a deterministic behavior - * (we do not want the metadata to vary depending on the order in which methods are invoked). - */ - addTitleOrIdentifier(builder); - builder.setISOStandards(false); - metadata = builder.buildAndFreeze(); + createMetadata(AsciiGridStoreProvider.NAME, "ASCGRD"); } return metadata; } - /** - * Returns the spatiotemporal extent of the ASCII grid file. - * - * @return the spatiotemporal resource extent. - * @throws DataStoreException if an error occurred while computing the envelope. - */ - @Override - public Optional<Envelope> getEnvelope() throws DataStoreException { - return Optional.ofNullable(getGridGeometry().getEnvelope()); - } - /** * Returns the valid extent of grid coordinates together with the conversion from those grid * coordinates to real world coordinates. @@ -475,13 +418,14 @@ cellsize: if (value != null) { } /** - * Loads the data if not already done and closes the channel. In current implementation the image is always - * fully loaded and cached. The given domain is ignored. We do that in order to have determinist and stable - * values for the sample range and for the data type. Loading the full image is reasonable if ASCII Grid + * Loads the data if not already done and closes the channel if read-only. + * In current implementation the image is always fully loaded and cached. + * The given domain is ignored. We do that in order to have determinist and stable values + * for the sample range and for the data type. Loading the full image is reasonable if ASCII Grid * files contain only small images, which is usually the case given how inefficient this format is. * * @param domain desired grid extent and resolution, or {@code null} for reading the whole domain. - * @param range shall be either 0 or an containing only 0. + * @param range shall be either 0 or a range containing only 0. * @return the grid coverage for the specified domain. * @throws DataStoreException if an error occurred while reading the grid coverage data. */ diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java new file mode 100644 index 0000000000..0d7338b556 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RasterStore.java @@ -0,0 +1,131 @@ +/* + * 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.internal.storage.esri; + +import java.util.Optional; +import org.opengis.geometry.Envelope; +import org.opengis.metadata.Metadata; +import org.opengis.metadata.maintenance.ScopeCode; +import org.opengis.referencing.operation.TransformException; +import org.apache.sis.coverage.grid.GridGeometry; +import org.apache.sis.storage.GridCoverageResource; +import org.apache.sis.storage.DataStoreProvider; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.DataStoreReferencingException; +import org.apache.sis.storage.StorageConnector; +import org.apache.sis.internal.storage.PRJDataStore; +import org.apache.sis.internal.storage.MetadataBuilder; +import org.apache.sis.metadata.sql.MetadataStoreException; + + +/** + * Base class for the implementation of ASCII Grid or raw binary store. + * This base class manages the reading of following auxiliary files: + * + * <ul> + * <li>{@code *.stx} for statistics about bands.</li> + * <li>{@code *.clr} for the image color map.</li> + * <li>{@code *.prj} for the CRS definition.</li> + * </ul> + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 + * @module + */ +abstract class RasterStore extends PRJDataStore implements GridCoverageResource { + /** + * Keyword for the number of rows in the image. + */ + static final String NROWS = "NROWS"; + + /** + * Keyword for the number of columns in the image. + */ + static final String NCOLS = "NCOLS"; + + /** + * The image size together with the "grid to CRS" transform. + * This is also used as a flag for checking whether the + * {@code "*.prj"} file and the header have been read. + */ + GridGeometry gridGeometry; + + /** + * The metadata object, or {@code null} if not yet created. + */ + Metadata metadata; + + /** + * Creates a new raster store from the given file, URL or stream. + * + * @param provider the factory that created this {@code DataStore} instance, or {@code null} if unspecified. + * @param connector information about the storage (file, URL, stream, <i>etc</i>). + * @throws DataStoreException if an error occurred while creating the data store for the given storage. + */ + RasterStore(final DataStoreProvider provider, final StorageConnector connector) throws DataStoreException { + super(provider, connector); + listeners.useWarningEventsOnly(); + } + + /** + * Builds metadata and assigns the result to the {@link #metadata} field. + * + * @param formatName name of the raster format. + * @param formatKey key of format description in the {@code SpatialMetadata} database. + * @throws DataStoreException if an error occurred during the parsing process. + */ + final void createMetadata(final String formatName, final String formatKey) throws DataStoreException { + final GridGeometry gridGeometry = getGridGeometry(); // May cause parsing of header. + final MetadataBuilder builder = new MetadataBuilder(); + try { + builder.setPredefinedFormat(formatKey); + } catch (MetadataStoreException e) { + builder.addFormatName(formatName); + listeners.warning(e); + } + builder.addResourceScope(ScopeCode.COVERAGE, null); + builder.addEncoding(encoding, MetadataBuilder.Scope.METADATA); + builder.addSpatialRepresentation(null, gridGeometry, true); + try { + builder.addExtent(gridGeometry.getEnvelope()); + } catch (TransformException e) { + throw new DataStoreReferencingException(getLocale(), formatName, getDisplayName(), null).initCause(e); + } + /* + * Do not add the sample dimensions because in current version computing the sample dimensions without + * statistics requires loading the full image. Even if `GridCoverage.getSampleDimensions()` exists and + * could be used opportunistically, we do not use it in order to keep a deterministic behavior + * (we do not want the metadata to vary depending on the order in which methods are invoked). + */ + addTitleOrIdentifier(builder); + builder.setISOStandards(false); + metadata = builder.buildAndFreeze(); + } + + /** + * Returns the spatiotemporal extent of the raster file. + * + * @return the spatiotemporal resource extent. + * @throws DataStoreException if an error occurred while computing the envelope. + * @hidden + */ + @Override + public Optional<Envelope> getEnvelope() throws DataStoreException { + return Optional.ofNullable(getGridGeometry().getEnvelope()); + } +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/package-info.java index c32a629d97..e03933fae7 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/package-info.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/package-info.java @@ -34,7 +34,11 @@ * * @author Martin Desruisseaux (Geomatys) * @version 1.2 - * @since 1.2 + * + * @see <a href="https://desktop.arcgis.com/en/arcmap/latest/manage-data/raster-and-images/esri-ascii-raster-format.htm">Esri ASCII raster format</a> + * @see <a href="https://desktop.arcgis.com/en/arcmap/latest/manage-data/raster-and-images/bil-bip-and-bsq-raster-files.htm">BIL, BIP, and BSQ raster files</a> + * + * @since 1.2 * @module */ package org.apache.sis.internal.storage.esri; diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java index 62052b1731..9dc93e9363 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java @@ -226,6 +226,7 @@ class WorldFileStore extends PRJDataStore implements Aggregate { { super(provider, connector); identifiers = new HashMap<>(); + listeners.useWarningEventsOnly(); final Object storage = connector.getStorage(); if (storage instanceof ImageReader) { reader = (ImageReader) storage;