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 71b882f252 feat(Geotiff): if added resource is tiled, try to reuse
it's matrix model.
71b882f252 is described below
commit 71b882f252651c47119bdc100fc060cf998a3a25
Author: jsorel <[email protected]>
AuthorDate: Thu Jun 11 13:27:22 2026 +0200
feat(Geotiff): if added resource is tiled, try to reuse it's matrix model.
Co-authored-by: Martin Desruisseaux <[email protected]>
---
.../main/module-info.java | 6 +-
.../apache/sis/storage/geotiff/GeoTiffStore.java | 41 ++++++++---
.../apache/sis/storage/geotiff/WritableStore.java | 36 ++++++++-
.../org/apache/sis/storage/geotiff/Writer.java | 24 +++++-
.../apache/sis/storage/geotiff/package-info.java | 3 +
.../apache/sis/storage/base/OverviewIterator.java} | 31 ++++----
.../storage/base/WritableTiledResourceSupport.java | 86 ++++++++++++++++++++++
7 files changed, 195 insertions(+), 32 deletions(-)
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 e6e3125b05..7171870355 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
@@ -16,12 +16,16 @@
*/
/**
- * GeoTIFF store.
+ * A data store for reading and writing GeoTIFF files.
+ * This module supports big <abbr>TIFF</abbr> and Cloud Optimized GeoTIFF
(<abbr>COG</abbr>).
*
* @author Rémi Maréchal (Geomatys)
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
+ * @author Alexis Manin (Geomatys)
+ * @author Estelle Idée (Geomatys)
+ * @author Johann Sorel (Geomatys)
* @version 1.7
* @since 0.8
*/
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
index 97657c40af..c9ef2dbf25 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
@@ -50,6 +50,7 @@ import org.apache.sis.storage.IncompatibleResourceException;
import org.apache.sis.storage.IllegalNameException;
import org.apache.sis.storage.metadata.MetadataBuilder;
import org.apache.sis.storage.base.StoreUtilities;
+import org.apache.sis.storage.base.OverviewIterator;
import org.apache.sis.storage.base.URIDataStoreOption;
import org.apache.sis.storage.base.URIDataStoreProvider;
import org.apache.sis.storage.base.GridResourceWrapper;
@@ -77,12 +78,22 @@ import org.apache.sis.util.resources.Errors;
/**
* A data store backed by GeoTIFF files.
+ * Each <abbr>TIFF</abbr> file can contains an arbitrary number of images.
+ * Some of these images may be overviews of a full-resolution image, thus
forming a
+ * pyramid as defined by the Cloud Optimized GeoTIFF (<abbr>COG</abbr>)
convention.
+ * This store supports the big <abbr>TIFF</abbr> extension.
+ *
+ * <p>While it is possible to create instances of this class directly,
+ * the recommended way is to use {@link GeoTiffStoreProvider} because
+ * the latter may return instances that implement additional interfaces
+ * such as {@link org.apache.sis.storage.WritableAggregate}.</p>
*
* @author Rémi Maréchal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Alexis Manin (Geomatys)
* @author Estelle Idée (Geomatys)
+ * @author Johann Sorel (Geomatys)
* @version 1.7
* @since 0.8
*/
@@ -688,6 +699,16 @@ public class GeoTiffStore extends DataStore implements
Aggregate {
}
}
+ /**
+ * Returns the source of overviews for the image which is currently in
process of being written.
+ *
+ * @param writer the default source of overview.
+ * @return the source of overview to use.
+ */
+ OverviewIterator overviews(final OverviewIterator writer) {
+ return writer;
+ }
+
/**
* Encodes the given image in the GeoTIFF file.
* The image is appended after any existing images in the GeoTIFF file.
@@ -713,23 +734,19 @@ public class GeoTiffStore extends DataStore implements
Aggregate {
final Reader reader = this.reader;
final Writer writer = writer();
writer.synchronize(reader, false);
- long offsetIFD;
+ long offsetIFD = -1;
try {
offsetIFD = writer.append(image, grid, metadata, false);
- if (writer.isPyramided) {
- while (image.getWidth() > Writer.OVERVIEW_SIZE ||
- image.getHeight() > Writer.OVERVIEW_SIZE)
- {
- image = writer.processor().overview(image);
- offsetIFD = writer.append(image, null, null, true);
- // Grid and metadata are null as we don't want to
repeat metadata in overviews.
- }
+ final OverviewIterator it = overviews(writer);
+ while ((image = it.nextOverview(image)) != null) {
+ offsetIFD = writer.append(image, null, null, true);
+ // Grid and metadata are null as we don't want to repeat
metadata in overviews.
}
} finally {
writer.synchronize(reader, true);
- }
- if (reader != null) {
- reader.offsetOfWrittenIFD(offsetIFD);
+ if (reader != null && offsetIFD >= 0) {
+ reader.offsetOfWrittenIFD(offsetIFD); // Last
successfully written image.
+ }
}
index = writer.imageIndex++;
} catch (RasterFormatException | ArithmeticException |
IllegalArgumentException e) {
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/WritableStore.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/WritableStore.java
index 04e5a73e56..a744cc71ab 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/WritableStore.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/WritableStore.java
@@ -22,7 +22,12 @@ import org.apache.sis.storage.WritableAggregate;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.base.OverviewIterator;
import org.apache.sis.storage.base.WritableAggregateSupport;
+import org.apache.sis.storage.base.WritableTiledResourceSupport;
+import org.apache.sis.storage.tiling.TileMatrixSet;
+import org.apache.sis.storage.tiling.TiledResource;
+import org.apache.sis.util.collection.Containers;
/**
@@ -30,8 +35,14 @@ import org.apache.sis.storage.base.WritableAggregateSupport;
*
* @author Erwan Roussel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
+ * @author Johann Sorel (Geomatys)
*/
final class WritableStore extends GeoTiffStore implements WritableAggregate {
+ /**
+ * Provider of overviews, or {@code null} if none.
+ */
+ private WritableTiledResourceSupport overviews;
+
/**
* Creates a new GeoTIFF store from the given file, URL or stream object.
* This constructor invokes {@link
StorageConnector#closeAllExcept(Object)},
@@ -54,13 +65,34 @@ final class WritableStore extends GeoTiffStore implements
WritableAggregate {
* @throws DataStoreException if the given resource cannot be stored in
this {@code Aggregate}.
*/
@Override
- public Resource add(final Resource resource) throws DataStoreException {
+ public synchronized Resource add(final Resource resource) throws
DataStoreException {
final var helper = new WritableAggregateSupport(this);
if (resource instanceof Aggregate) {
return helper.writeComponents((Aggregate) resource);
}
final GridCoverageResource gr = helper.asGridCoverage(resource);
- return append(gr.read(null, null), gr.getMetadata());
+ if (gr instanceof TiledResource) {
+ final TileMatrixSet tms = Containers.peekFirst(((TiledResource)
gr).getTileMatrixSets());
+ if (tms != null) {
+ overviews = new WritableTiledResourceSupport(gr, tms);
+ }
+ }
+ try {
+ return append(gr.read(null, null), gr.getMetadata());
+ } finally {
+ overviews = null;
+ }
+ }
+
+ /**
+ * Returns the source of overviews for the image which is currently in
process of being written.
+ *
+ * @param writer the default source of overview.
+ * @return the source of overview to use.
+ */
+ @Override
+ final OverviewIterator overviews(final OverviewIterator writer) {
+ return (overviews != null) ? overviews : writer;
}
/**
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java
index 9e7022f300..5f08e4000d 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java
@@ -49,6 +49,7 @@ import org.apache.sis.storage.DataStoreReferencingException;
import org.apache.sis.storage.IncompatibleResourceException;
import org.apache.sis.storage.ReadOnlyStorageException;
import org.apache.sis.storage.metadata.MetadataFetcher;
+import org.apache.sis.storage.base.OverviewIterator;
import org.apache.sis.storage.geotiff.writer.TagValue;
import org.apache.sis.storage.geotiff.writer.TileMatrix;
import org.apache.sis.storage.geotiff.writer.GeoEncoder;
@@ -82,7 +83,7 @@ import org.opengis.coverage.CannotEvaluateException;
* @author Martin Desruisseaux (Geomatys)
* @author Estelle Idée (Geomatys)
*/
-final class Writer extends IOBase implements Flushable {
+final class Writer extends IOBase implements OverviewIterator, Flushable {
/**
* Maximal size of the highest overview.
* Used as a criteria for deciding when to stop creating overviews in a
pyramided file.
@@ -153,7 +154,7 @@ final class Writer extends IOBase implements Flushable {
*
* @see #getFormat()
*/
- final boolean isPyramided;
+ private final boolean isPyramided;
/**
* Whether to disable the <abbr>TIFF</abbr> requirement that tile sizes
are multiple of 16 pixels.
@@ -295,13 +296,30 @@ final class Writer extends IOBase implements Flushable {
* Returns the processor to use for reformatting the image before to write
it.
* The processor is created only when this method is first invoked.
*/
- final ImageProcessor processor() {
+ private ImageProcessor processor() {
if (processor == null) {
processor = new ImageProcessor();
}
return processor;
}
+ /**
+ * Returns the next overview level, from finest resolution to coarsest
resolution.
+ *
+ * @param previous the image at finer resolution which has been written
before this method call.
+ * @return the next overview level, or {@code null} if the iteration is
finished.
+ * @throws DataStoreException if the resource cannot be read.
+ */
+ @Override
+ public final RenderedImage nextOverview(final RenderedImage previous)
throws DataStoreException {
+ if (isPyramided) {
+ if (previous.getWidth() > OVERVIEW_SIZE || previous.getHeight() >
OVERVIEW_SIZE) {
+ return processor().overview(previous);
+ }
+ }
+ return null;
+ }
+
/**
* Encodes the given image to the output stream given at construction time.
* The image is appended after any previous images written before the
given one.
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/package-info.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/package-info.java
index 76accbbda4..a40b1ead9c 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/package-info.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/package-info.java
@@ -33,6 +33,9 @@
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
+ * @author Alexis Manin (Geomatys)
+ * @author Estelle Idée (Geomatys)
+ * @author Johann Sorel (Geomatys)
* @version 1.7
* @since 0.8
*/
diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/OverviewIterator.java
similarity index 51%
copy from endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
copy to
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/OverviewIterator.java
index e6e3125b05..e3d0f5e26f 100644
--- a/endorsed/src/org.apache.sis.storage.geotiff/main/module-info.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/OverviewIterator.java
@@ -14,23 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.sis.storage.base;
+
+import java.awt.image.RenderedImage;
+import org.apache.sis.storage.DataStoreException;
+
/**
- * GeoTIFF store.
+ * Provider of overviews for writing a pyramided image.
+ * Overviews are returned from finest resolution to coarsest resolution.
+ * They may be computed on the fly or read from an existing source.
*
- * @author Rémi Maréchal (Geomatys)
- * @author Thi Phuong Hao Nguyen (VNSC)
- * @author Minh Chinh Vu (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.7
- * @since 0.8
*/
-module org.apache.sis.storage.geotiff {
- requires jakarta.xml.bind;
- requires transitive org.apache.sis.storage;
-
- provides org.apache.sis.storage.DataStoreProvider
- with org.apache.sis.storage.geotiff.GeoTiffStoreProvider;
-
- exports org.apache.sis.storage.geotiff;
+public interface OverviewIterator {
+ /**
+ * Returns the next overview level, from finest resolution to coarsest
resolution.
+ *
+ * @param previous the image at finer resolution which can be used as a
base for the next overview.
+ * @return the next overview level, or {@code null} if the iteration is
finished.
+ * @throws DataStoreException if the source of overviews cannot be read.
+ */
+ RenderedImage nextOverview(RenderedImage previous) throws
DataStoreException;
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableTiledResourceSupport.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableTiledResourceSupport.java
new file mode 100644
index 0000000000..908dc95cad
--- /dev/null
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/WritableTiledResourceSupport.java
@@ -0,0 +1,86 @@
+/*
+ * 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.storage.base;
+
+import java.awt.image.RenderedImage;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.tiling.TileMatrix;
+import org.apache.sis.storage.tiling.TileMatrixSet;
+
+
+/**
+ * Helper classes for writing a tiled resource.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+public final class WritableTiledResourceSupport implements OverviewIterator {
+ /**
+ * The resource from which to read get the data to write.
+ */
+ private final GridCoverageResource resource;
+
+ /**
+ * Grid geometry of the level with finest resolution.
+ */
+ private final GridGeometry baseGrid;
+
+ /**
+ * Tile matrices from coarser resolution (highest scale denominator)
+ * to most detailed resolution (lowest scale denominator).
+ */
+ private final TileMatrix[] matrices;
+
+ /**
+ * Index of the next level to return. We traverse {@link #matrices} in
reverse order,
+ * from finest resolution to coarsest resolution and ignoring the finest
resolution.
+ */
+ private int index;
+
+ /**
+ * Creates a new helper class for writing the given tile matrix set.
+ *
+ * @param resource the resource from which to read the levels.
+ * @param tiling the tile matrix to write.
+ * @throws DataStoreException if the resource cannot be read.
+ */
+ public WritableTiledResourceSupport(final GridCoverageResource resource,
final TileMatrixSet tiling) throws DataStoreException {
+ this.resource = resource;
+ this.baseGrid = resource.getGridGeometry();
+ this.matrices =
tiling.getTileMatrices().values().toArray(TileMatrix[]::new);
+ index = matrices.length - 1;
+ }
+
+ /**
+ * Returns the next overview level, from finest resolution to coarsest
resolution.
+ *
+ * @param previous ignored.
+ * @return the next overview level, or {@code null} if the iteration is
finished.
+ * @throws DataStoreException if the resource cannot be read.
+ */
+ @Override
+ public final RenderedImage nextOverview(final RenderedImage previous)
throws DataStoreException {
+ if (--index >= 0) {
+ final TileMatrix matrix = matrices[index];
+ final GridGeometry domain = baseGrid.derive().subgrid(null,
matrix.getResolution()).build();
+ return resource.read(domain, (int[]) null).render(null);
+ }
+ return null;
+ }
+}