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 f2376c46f8 Fix a buffer used when inflating tile data in HEIF.
f2376c46f8 is described below
commit f2376c46f8cb42595b014f4e6a53b371d7abcc17
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jun 19 17:06:08 2026 +0200
Fix a buffer used when inflating tile data in HEIF.
---
.../sis/storage/geotiff/inflater/Inflater.java | 2 +-
.../io/stream/inflater/CompressionException.java | 6 ++++
.../io/stream/inflater/ComputedByteChannel.java | 7 ++---
.../org/apache/sis/io/stream/inflater/Deflate.java | 2 +-
.../apache/sis/storage/geoheif/ImageResource.java | 36 ++++++++++++----------
.../sis/storage/geoheif/UncompressedImage.java | 9 ++++--
6 files changed, 35 insertions(+), 27 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java
index 05b805181d..409f1bfa10 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/Inflater.java
@@ -238,7 +238,7 @@ public abstract class Inflater implements Closeable {
}
}
final int scanlineStride = Math.multiplyExact(sourceWidth,
sourcePixelStride * dataType.bytes());
- final ChannelDataInput inflated = channel.createDataInput(null,
scanlineStride);
+ final ChannelDataInput inflated =
channel.createDataInput(scanlineStride);
return CopyFromBytes.create(inflated, dataType, chunksPerRow,
samplesPerChunk, skipAfterChunks, pixelsPerElement);
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/CompressionException.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/CompressionException.java
index bbd7626981..f567cb4643 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/CompressionException.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/CompressionException.java
@@ -30,6 +30,12 @@ public class CompressionException extends IOException {
*/
private static final long serialVersionUID = -5493223452276185518L;
+ /**
+ * Constructs a new exception with no detail message and no cause.
+ */
+ public CompressionException() {
+ }
+
/**
* Constructs a new exception with the specified detail message and cause.
*
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/ComputedByteChannel.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/ComputedByteChannel.java
index 95c92da1da..3e80e1fab1 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/ComputedByteChannel.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/ComputedByteChannel.java
@@ -91,12 +91,11 @@ public abstract class ComputedByteChannel implements
ReadableByteChannel {
* for performance reasons. A well adjusted buffer size reduces calls to
{@link ByteBuffer#compact()},
* which in turn reduces the number of copy operations between different
regions of the buffer.</p>
*
- * @param buffer buffer to reuse if {@code null}. The content of
this buffer will be discarded.
* @param scanlineStride the scanline stride of the image to read. Used
for choosing a buffer size.
* @throws IOException if an error occurred while filling the buffer with
initial data.
* @return the data input for uncompressed data.
*/
- public final ChannelDataInput createDataInput(ByteBuffer buffer, final int
scanlineStride) throws IOException {
+ public final ChannelDataInput createDataInput(final int scanlineStride)
throws IOException {
final int capacity;
if (scanlineStride > BUFFER_SIZE) {
final int[] divisors = MathFunctions.divisors(scanlineStride);
@@ -109,9 +108,7 @@ public abstract class ComputedByteChannel implements
ReadableByteChannel {
capacity = BUFFER_SIZE;
}
final ChannelDataInput input = compressedInput();
- if (buffer == null) {
- buffer = preferNativeBuffer() ?
ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity);
- }
+ ByteBuffer buffer = preferNativeBuffer() ?
ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity);
buffer = buffer.order(input.buffer.order()).limit(0);
return new ChannelDataInput(input.filename, this, buffer, true);
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/Deflate.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/Deflate.java
index 1db05bd9dd..47917355d9 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/Deflate.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/inflater/Deflate.java
@@ -100,7 +100,7 @@ public final class Deflate extends InflaterChannel {
} else if (inflater.finished()) {
return -1;
} else {
- throw new IOException();
+ throw new CompressionException();
}
}
} catch (DataFormatException e) {
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
index c1a0f9ee4b..76f9879804 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageResource.java
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
-import java.nio.ByteBuffer;
import java.io.IOException;
import java.io.UncheckedIOException;
import static java.lang.Math.addExact;
@@ -48,6 +47,7 @@ import org.apache.sis.storage.tiling.TiledGridCoverage;
import org.apache.sis.storage.tiling.TiledGridCoverageResource;
import org.apache.sis.storage.isobmff.ByteRanges;
import org.apache.sis.io.stream.ChannelDataInput;
+import org.apache.sis.io.stream.inflater.ComputedByteChannel;
import org.apache.sis.util.internal.shared.Numerics;
@@ -324,15 +324,15 @@ final class ImageResource extends
TiledGridCoverageResource implements StoreReso
final var requests = new ReadContext[result.length];
int count = 0;
synchronized (getSynchronizationLock()) {
- final var readers = new HashMap<ImageReaderSpi, ImageReader>();
- final var buffer = new AtomicReference<ByteBuffer>();
+ final var readers = new HashMap<ImageReaderSpi,
ImageReader>();
+ final var inflater = new
AtomicReference<ComputedByteChannel>();
try {
do {
Raster raster = iterator.getCachedTile();
if (raster != null) {
result[iterator.getTileIndexInResultArray()] =
raster;
} else {
- requests[count++] = new ReadContext(iterator,
readers, buffer, ImageResource.this);
+ requests[count++] = new ReadContext(iterator,
readers, inflater, ImageResource.this);
}
} while (iterator.next());
/*
@@ -361,6 +361,8 @@ final class ImageResource extends TiledGridCoverageResource
implements StoreReso
/**
* Context about a {@code readTile(…)} operation. Contains the tile to
create, or
* the image reader to use in the case of read operations delegated to
Image I/O.
+ * An instance of this class exist for each tile and is discarded
after the tile
+ * has been read.
*/
static final class ReadContext extends ByteRanges {
/**
@@ -385,29 +387,29 @@ final class ImageResource extends
TiledGridCoverageResource implements StoreReso
final long subTileX, subTileY;
/**
- * Buffer to reuse for each tile.
+ * Inflater to reuse for each tile.
*/
- private final AtomicReference<ByteBuffer> buffer;
+ private final AtomicReference<ComputedByteChannel> inflater;
/**
* Creates a new read context.
*
* @param iterator iterator over the tiles to read.
* @param readers an initially empty map where to store image
readers for reuse.
- * @param buffer an initially empty reference to a buffer.
+ * @param inflater an initially empty reference to an inflater
to recycle.
* @param owner the resource for which to read a tile.
* @throws DataStoreException if an error occurred while computing
the range of bytes.
*/
@SuppressWarnings("LeakingThisInConstructor")
private ReadContext(final AOI iterator,
final Map<ImageReaderSpi, ImageReader> readers,
- final AtomicReference<ByteBuffer> buffer,
+ final AtomicReference<ComputedByteChannel>
inflater,
final ImageResource owner)
throws DataStoreException
{
this.iterator = new Snapshot(iterator);
this.readers = readers;
- this.buffer = buffer;
+ this.inflater = inflater;
final long[] tileCoord =
iterator.getTileCoordinatesInResource();
final Image tile = owner.getTile(tileCoord[0], tileCoord[1]);
subTileX = tileCoord[0] % tile.numXTiles;
@@ -465,21 +467,21 @@ final class ImageResource extends
TiledGridCoverageResource implements StoreReso
}
/**
- * If a buffer has already been used in a previous read operation,
returns that buffer.
+ * If a inflater has already been used in a previous read
operation, returns that inflater.
*
- * @return buffer that can be reused, or {@code null} if none.
+ * @return inflater that can be reused, or {@code null} if none.
*/
- public ByteBuffer reuseBuffer() {
- return buffer.getAndSet(null);
+ public ComputedByteChannel reuseInflater() {
+ return inflater.getAndSet(null);
}
/**
- * Saves the given buffer for reuse.
+ * Saves the given inflater for reuse.
*
- * @param done a buffer which is no longer needed.
+ * @param done a inflater which is no longer needed.
*/
- public void saveForReuse(final ByteBuffer done) {
- buffer.set(done);
+ public void saveForReuse(final ComputedByteChannel done) {
+ inflater.set(done);
}
}
}
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/UncompressedImage.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/UncompressedImage.java
index ebdbdfd590..db2fc606a3 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/UncompressedImage.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/UncompressedImage.java
@@ -189,12 +189,15 @@ class UncompressedImage extends Image {
computeByteRanges(tileIndex, region, context);
return (ChannelDataInput input) -> {
long origin = context.offset();
- final ComputedByteChannel inflater = inflater(input);
+ ComputedByteChannel inflater = context.reuseInflater();
+ if (inflater == null || inflater.compressedInput() != input) {
+ inflater = inflater(input);
+ }
if (inflater != null) {
final CompressedUnitsItemInfo.Unit unit =
compressedImageUnit(tileIndex);
inflater.setInputRegion(addExact(origin, unit.offset),
unit.size);
// The following (int) cast is okay even if inexact because it
is only a hint.
- input = inflater.createDataInput(context.reuseBuffer(), (int)
sourceSize[0]);
+ input = inflater.createDataInput((int) sourceSize[0]);
origin = 0;
}
/*
@@ -221,7 +224,7 @@ class UncompressedImage extends Image {
hr.readAsBuffer(bank, 0);
}
if (inflater != null) {
- context.saveForReuse(inflater.compressedInput().buffer);
+ context.saveForReuse(inflater);
}
return raster;
};