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 d1a6399c25 Initial support of "tili" image type in GeoHEIF files.
d1a6399c25 is described below
commit d1a6399c251f354f104c69b3fc7bbf2aa809dfe7
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Jun 15 17:29:28 2026 +0200
Initial support of "tili" image type in GeoHEIF files.
---
.../sis/storage/geoheif/CoverageBuilder.java | 81 ++++++++++++---
.../org/apache/sis/storage/geoheif/ImageModel.java | 15 +--
.../apache/sis/storage/geoheif/ImageResource.java | 1 +
.../sis/storage/geoheif/ResourceBuilder.java | 12 +++
.../org/apache/sis/storage/geoheif/TiledImage.java | 115 +++++++++++++++++++++
.../sis/storage/geoheif/UncompressedImage.java | 65 +++++++++---
.../apache/sis/storage/isobmff/base/ItemData.java | 10 +-
.../sis/storage/isobmff/base/ItemInfoEntry.java | 3 +-
.../{geo => image}/TiledImageConfiguration.java | 3 +-
.../isobmff/mpeg/CompressedUnitsItemInfo.java | 2 +-
10 files changed, 261 insertions(+), 46 deletions(-)
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
index 7b51f15fe5..551fc2fec8 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/CoverageBuilder.java
@@ -21,6 +21,7 @@ import java.util.UUID;
import java.util.Set;
import java.util.Map;
import java.util.List;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Collection;
import java.util.StringJoiner;
@@ -28,6 +29,7 @@ import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.io.IOException;
import java.nio.ByteOrder;
+import java.awt.Dimension;
import java.awt.image.SampleModel;
import org.opengis.util.GenericName;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -43,6 +45,7 @@ import org.apache.sis.storage.modifier.CoverageModifier;
import org.apache.sis.storage.isobmff.Box;
import org.apache.sis.storage.isobmff.base.ItemInfoEntry;
import org.apache.sis.storage.isobmff.base.ItemProperties;
+import org.apache.sis.storage.isobmff.image.TiledImageConfiguration;
import org.apache.sis.storage.isobmff.geo.ModelTransformation;
import org.apache.sis.storage.isobmff.geo.ModelCRS;
import org.apache.sis.storage.isobmff.mpeg.ComponentType;
@@ -100,6 +103,14 @@ final class CoverageBuilder implements Emptiable {
*/
private int width, height;
+ /**
+ * Information about where to find the tiles when the image type is {@code
"tili"}.
+ * May be {@code null} if no such information was found.
+ *
+ * @see #tiling()
+ */
+ private TiledImageConfiguration tiling;
+
/**
* Coefficients of the matrix that defines the "grid to <abbr>CRS</abbr>"
coordinate conversion.
* May be {@code null} if no such information was found.
@@ -186,7 +197,7 @@ final class CoverageBuilder implements Emptiable {
*
* @param owner the resource which is creating a grid coverage.
* @param imageIndex an index of the image, for information purpose
only.
- * @param properties source of coverage properties for this
coverage item.
+ * @param properties source of coverage properties for this
coverage item, or {@code null} if none.
* @param duplicatedBoxes names of boxes that were duplicated. Used for
logging a warning only once per type of box.
*/
CoverageBuilder(final ResourceBuilder owner,
@@ -197,16 +208,26 @@ final class CoverageBuilder implements Emptiable {
this.owner = owner;
this.imageIndex = imageIndex;
unknownBoxes = new LinkedHashMap<>();
- if (properties == null) {
- return;
- }
- if (properties.missingItem) {
- // Some boxes could not be handled, but we don't have their
identifiers.
- unknownBoxes.put(null, properties.missingEssential);
+ if (properties != null) {
+ if (properties.missingItem) {
+ // Some boxes could not be handled, but we don't have their
identifiers.
+ unknownBoxes.put(null, properties.missingEssential);
+ }
+ load(properties, duplicatedBoxes);
}
+ }
+
+ /**
+ * Collects from the given boxes the data that this builder will need.
+ * This method may invoke itself recursively if a box is a container for
other boxes.
+ *
+ * @param properties source of coverage properties for this
coverage item.
+ * @param duplicatedBoxes names of boxes that were duplicated. Used for
logging a warning only once per type of box.
+ */
+ private void load(final List<Box> properties, final Set<String>
duplicatedBoxes) {
final int count = properties.size();
for (int i=0; i<count; i++) {
- boolean duplicated;
+ final boolean duplicated;
final Box property = properties.get(i);
switch (property.type()) {
/*
@@ -277,8 +298,19 @@ final class CoverageBuilder implements Emptiable {
if (!duplicated) palette = c;
break;
}
+ case TiledImageConfiguration.BOXTYPE: {
+ var c = (TiledImageConfiguration) property;
+ duplicated = (tiling != null);
+ if (!duplicated) {
+ tiling = c; // Before `load(…)` for safety against
nested tiling.
+ load(Arrays.asList(c.tileImageProperties),
duplicatedBoxes);
+ }
+ break;
+ }
default: {
- unknownBoxes.merge(property.typeKey(),
properties.essential(i), Boolean::logicalOr);
+ boolean essential = (properties instanceof
ItemProperties.ForID)
+ && ((ItemProperties.ForID)
properties).essential(i);
+ unknownBoxes.merge(property.typeKey(), essential,
Boolean::logicalOr);
continue;
}
}
@@ -291,6 +323,14 @@ final class CoverageBuilder implements Emptiable {
}
}
+ /**
+ * Returns information about where to find the tiles when the image type
is {@code "tili"}.
+ * This is used for reading the positions of tiles in the file and the
number of bytes to read.
+ */
+ final TiledImageConfiguration tiling() {
+ return tiling;
+ }
+
/**
* Returns the compression method, or 0 if none.
* The returned value should be one of the {@code
CompressionConfiguration.COMPRESSION_*} constants.
@@ -313,7 +353,7 @@ final class CoverageBuilder implements Emptiable {
}
if (compression.unitType == UnitType.IMAGE_TILE) {
if (compressedUnits == null) {
- throw new DataStoreContentException("Missing compressed
unit.");
+ return null;
}
final CompressedUnitsItemInfo.Unit[] units = compressedUnits.units;
if (units.length == 1) {
@@ -471,11 +511,18 @@ final class CoverageBuilder implements Emptiable {
case 1: return model.numTileRows;
}
} else if (!isEmpty()) {
- final SampleModel sampleModel = imageModel().sampleModel;
- if (sampleModel != null) {
+ if (tiling != null) {
switch (dimension) {
- case 0: return JDK18.ceilDiv(width,
sampleModel.getWidth());
- case 1: return JDK18.ceilDiv(height,
sampleModel.getHeight());
+ case 0: return JDK18.ceilDiv(width, tiling.tileWidth);
+ case 1: return JDK18.ceilDiv(height, tiling.tileHeight);
+ }
+ } else {
+ final SampleModel sampleModel = imageModel().sampleModel;
+ if (sampleModel != null) {
+ switch (dimension) {
+ case 0: return JDK18.ceilDiv(width,
sampleModel.getWidth());
+ case 1: return JDK18.ceilDiv(height,
sampleModel.getHeight());
+ }
}
}
}
@@ -517,7 +564,11 @@ final class CoverageBuilder implements Emptiable {
*/
final ImageModel imageModel() throws DataStoreException {
if (imageModel == null) {
- imageModel = new ImageModel(width, height, model, componentTypes,
bitsPerChannel, palette, this);
+ Dimension tileSize = null;
+ if (tiling != null) {
+ tileSize = new Dimension(tiling.tileWidth, tiling.tileHeight);
+ }
+ imageModel = new ImageModel(width, height, tileSize, model,
componentTypes, bitsPerChannel, palette, this);
if (imageModel.sampleModel == null && tileBuilder != null) {
imageModel = tileBuilder.imageModel();
}
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
index 9c285ab3d0..f11be26a60 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ImageModel.java
@@ -90,6 +90,7 @@ final class ImageModel {
*
* @param width the width (in pixels) of the reconstructed
image.
* @param height the height (in pixels) of the reconstructed
image.
+ * @param tileSize the tile size if known, or {@code null} for
computing from other information.
* @param model information about the sample model (data type,
<i>etc.</i>), or {@code null}.
* @param componentTypes pixel data displaying as {@link ComponentType},
{@link URI} or {@link Integer}.
* @param bitsPerChannel number of bits per channel in the reconstructed
image, or {@code null}.
@@ -100,6 +101,7 @@ final class ImageModel {
*/
ImageModel(final int width,
final int height,
+ Dimension tileSize,
final UncompressedFrameConfig model,
final Object[] componentTypes,
final byte[] bitsPerChannel,
@@ -206,12 +208,13 @@ final class ImageModel {
*/
this.dataType = dataType;
if (dataType != null) {
- InterleavingMode interleaveType = InterleavingMode.COMPONENT;
- final var tileSize = new Dimension(width, height);
- if (model != null) {
- tileSize.width /= model.numTileCols;
- tileSize.height /= model.numTileRows;
- interleaveType = model.interleaveType;
+ final InterleavingMode interleaveType = (model != null) ?
model.interleaveType : InterleavingMode.COMPONENT;
+ if (tileSize == null) {
+ tileSize = new Dimension(width, height);
+ if (model != null) {
+ tileSize.width /= model.numTileCols;
+ tileSize.height /= model.numTileRows;
+ }
}
final boolean isBanded;
switch (interleaveType) {
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 b0e49061fe..1d54bd888f 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
@@ -396,6 +396,7 @@ final class ImageResource extends TiledGridCoverageResource
implements StoreReso
* @param readers an initially empty map where to store image
readers for reuse.
* @param buffer an initially empty reference to a buffer.
* @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,
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ResourceBuilder.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ResourceBuilder.java
index a86c6508c3..f632022d99 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ResourceBuilder.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/ResourceBuilder.java
@@ -443,6 +443,18 @@ final class ResourceBuilder {
}
break;
}
+ /*
+ * Tiled image with offsets and lengths specified in a
separated array.
+ * This is an encoding more efficient than `GRID` because it
avoids to
+ * repeat the image color model and ample model for each tile.
+ */
+ case ItemInfoEntry.TILI: {
+ final ByteRanges.Reader locator =
getLocationByIdentifier(itemID);
+ if (locator != null) {
+ image = new TiledImage(coverage, locator, name);
+ }
+ break;
+ }
}
if (image == null) {
warning("No data found for the \"{0}\" resource.", name);
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/TiledImage.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/TiledImage.java
new file mode 100644
index 0000000000..6c881f00bc
--- /dev/null
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/TiledImage.java
@@ -0,0 +1,115 @@
+/*
+ * 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.geoheif;
+
+import java.io.IOException;
+import java.awt.image.RasterFormatException;
+import org.apache.sis.io.stream.ChannelDataInput;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.isobmff.ByteRanges;
+import org.apache.sis.storage.isobmff.base.ItemLocation;
+import org.apache.sis.storage.isobmff.mpeg.CompressedUnitsItemInfo;
+import org.apache.sis.storage.isobmff.image.TiledImageConfiguration;
+
+
+/**
+ * A tiled image ({@code 'tili'} item type) from the <abbr>HEIF</abbr> file.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+final class TiledImage extends UncompressedImage {
+ /**
+ * Positions relative to the beginning of the box where to find the tile
data.
+ */
+ private final long[] tileOffsets;
+
+ /**
+ * Number of bytes of the compressed data of each tile, or {@code null} if
not stored.
+ * The length of this array shall be equal to the {@link #tileOffsets}
array length.
+ * If {@code null}, then the lengths must be computed from the offsets.
+ */
+ private final long[] tileSizes;
+
+ /**
+ * Creates a new tile.
+ *
+ * @param builder helper class for building the grid geometry and sample
dimensions.
+ * @param locator the provider of bytes to read from the
<abbr>ISOBMFF</abbr> box.
+ * @param name a name that identifies this image, for debugging
purpose.
+ * @throws RasterFormatException if the sample model cannot be created.
+ * @throws IOException if an error occurred while reading bytes from the
input stream.
+ */
+ TiledImage(final CoverageBuilder builder, final ByteRanges.Reader locator,
final String name)
+ throws DataStoreException, IOException
+ {
+ super(builder, locator, name);
+ final int numTileCols = builder.numTiles(0);
+ final int numTileRows = builder.numTiles(1);
+ final int numTiles = Math.multiplyExact(numTileCols, numTileRows);
+ final TiledImageConfiguration tiling = builder.tiling();
+ final int offsetFieldLength = tiling.offsetFieldLength();
+ final int sizeFieldLength = tiling.sizeFieldLength();
+ final ChannelDataInput input = builder.store().ensureOpen();
+ input.seek(((ItemLocation.Item) locator).baseOffset);
+ tileOffsets = new long[numTiles];
+ tileSizes = (sizeFieldLength != 0) ? new long[numTiles] : null;
+ for (int i = 0; i < numTiles; i++) {
+ tileOffsets[i] = input.readBits(offsetFieldLength);
+ if (tileSizes != null) {
+ tileSizes[i] = input.readBits(sizeFieldLength);
+ }
+ }
+ }
+
+ /**
+ * Computes the range of bytes that will be needed for reading the tile at
the specified index.
+ * The result is stored in the given {@code context} argument.
+ *
+ * @param tileIndex index of the tile for which to compute the range of
bytes.
+ * @param tileSize ignored (replaced by the tile size which is stored
or computed from the offset).
+ * @param context where to add the ranges of bytes to read as offsets
relatives to the beginning of the file.
+ * @throws DataStoreException if an error occurred with the data in the
boxes.
+ * @throws ArithmeticException if an integer overflow occurred.
+ */
+ @Override
+ protected void computeByteRanges(final long tileIndex, long tileSize,
final ByteRanges context)
+ throws DataStoreException
+ {
+ final int i = Math.toIntExact(tileIndex);
+ final long offset = tileOffsets[i];
+ if (tileSizes != null) {
+ tileSize = tileSizes[i];
+ } else {
+ long next = tileOffsets[Math.incrementExact(i)]; // TODO:
handle the case of the last tile.
+ tileSize = next - offset;
+ }
+ locator.resolve(offset, tileSize, context);
+ }
+
+ /**
+ * Returns the compression units which contains tile data.
+ *
+ * @param tileIndex index of the tile for which to get the compression
unit.
+ * @return the compression unit for the tile at the given index.
+ */
+ @Override
+ protected CompressedUnitsItemInfo.Unit compressedImageUnit(final long
tileIndex) {
+ final int i = Math.toIntExact(tileIndex);
+ return new CompressedUnitsItemInfo.Unit(tileOffsets[i], tileSizes[i]);
+ }
+}
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 28a7dfa0bd..47a6477193 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
@@ -30,6 +30,7 @@ import org.apache.sis.io.stream.HyperRectangleReader;
import org.apache.sis.io.stream.Region;
import org.apache.sis.io.stream.inflater.ComputedByteChannel;
import org.apache.sis.io.stream.inflater.Deflate;
+import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.UnsupportedEncodingException;
import org.apache.sis.storage.isobmff.ByteRanges;
@@ -53,7 +54,7 @@ import
org.apache.sis.storage.isobmff.mpeg.CompressionConfiguration;
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
*/
-final class UncompressedImage extends Image {
+class UncompressedImage extends Image {
/**
* The type of sample values in the raster.
*/
@@ -67,13 +68,15 @@ final class UncompressedImage extends Image {
private final SampleModel sampleModel;
/**
- * The type of compression, or 0 if none.
+ * The type of compression, or 0 if the image is uncompressed.
* Should be one of the {@code CompressionConfiguration.COMPRESSION_*}
constants.
*/
private final int compressionType;
/**
- * The compression units which contains all image data, or {@code null} if
the image is uncompressed.
+ * The compression units which contains all image data, or {@code null} if
none.
+ * A compressed image may have no compression unit if the location of data
are
+ * specified by another type of box.
*/
private final CompressedUnitsItemInfo.Unit compressedImageUnit;
@@ -97,15 +100,15 @@ final class UncompressedImage extends Image {
/**
* Returns a channel which will decompress data on-the-fly.
- * This method shall be invoked only if {@link #compressedImageUnit} is
non-null.
* Callers shall invoke {@link ComputedByteChannel#setInputRegion(long,
long)} on the returned object.
*
* @param input the channel of compressed data.
- * @return the channel of uncompressed data.
+ * @return the channel of uncompressed data, or {@code null} if the data
are uncompressed.
* @throws UnsupportedEncodingException if the compression type is not
supported.
*/
private ComputedByteChannel inflater(final ChannelDataInput input) throws
UnsupportedEncodingException {
switch (compressionType) {
+ case 0: return null;
case CompressionConfiguration.COMPRESSION_ZLIB: return new
Deflate(input, listeners, false);
case CompressionConfiguration.COMPRESSION_DEFLATE: return new
Deflate(input, listeners, true);
default: throw new UnsupportedEncodingException("The \"" +
@@ -140,15 +143,47 @@ final class UncompressedImage extends Image {
return new Region(sourceSize, new long[2], regionUpper, new long[] {1,
1});
}
+ /**
+ * Computes the range of bytes that will be needed for reading the tile at
the specified index.
+ * The result is stored in the given {@code context} argument.
+ *
+ * @param tileIndex index of the tile for which to compute the range of
bytes.
+ * @param tileSize number of bytes of uncompressed data in each tile.
+ * @param context where to add the ranges of bytes to read as offsets
relatives to the beginning of the file.
+ * @throws DataStoreException if an error occurred with the data in the
boxes.
+ * @throws ArithmeticException if an integer overflow occurred.
+ */
+ protected void computeByteRanges(final long tileIndex, final long
tileSize, final ByteRanges context)
+ throws DataStoreException
+ {
+ locator.resolve(multiplyExact(tileIndex, tileSize), tileSize, context);
+ }
+
+ /**
+ * Returns the compression units which contains tile data.
+ *
+ * @param tileIndex index of the tile for which to get the compression
unit.
+ * @return the compression unit for the tile at the given index.
+ * @throws DataStoreException if the compression unit cannot be obtained.
+ */
+ protected CompressedUnitsItemInfo.Unit compressedImageUnit(final long
tileIndex) throws DataStoreException {
+ if (compressedImageUnit == null) {
+ throw new DataStoreContentException("Missing compressed unit.");
+ }
+ return compressedImageUnit;
+ }
+
/**
* Computes the range of bytes that will be needed for reading a single
tile of this image.
+ * This method is invoked in a code synchronized on {@link
ImageResource#getSynchronizationLock()}.
*
* @param context where to store the ranges of bytes.
* @return the function to invoke later for reading the tile.
* @throws DataStoreException if an error occurred while computing the
range of bytes.
+ * @throws ArithmeticException if an offset or index overflows the
capacity of 32-bits integers.
*/
@Override
- protected Reader computeByteRanges(final
ImageResource.Coverage.ReadContext context) throws DataStoreException {
+ protected final Reader computeByteRanges(final
ImageResource.Coverage.ReadContext context) throws DataStoreException {
final long[] sourceSize = size(sampleModel);
/*
* In the current implementation, we read the whole tile. If a future
implementation allows
@@ -156,22 +191,18 @@ final class UncompressedImage extends Image {
* `Buffer` with an arbitrary position in argument.
*/
final var region = region(sourceSize, sourceSize);
- final int dataSize = dataType.bytes();
- final long tileSize = multiplyExact(region.length, dataSize);
+ final long tileSize = multiplyExact(region.length, dataType.bytes());
final long tileIndex = addExact(multiplyExact(context.subTileY,
numXTiles), context.subTileX);
- final long offset = multiplyExact(tileIndex, tileSize);
- locator.resolve(offset, tileSize, context);
+ computeByteRanges(tileIndex, tileSize, context);
return (ChannelDataInput input) -> {
long origin = context.offset();
- final ComputedByteChannel inflater;
- final CompressedUnitsItemInfo.Unit unit = compressedImageUnit;
- if (unit != null) {
- inflater = inflater(input);
+ final ComputedByteChannel inflater = inflater(input);
+ if (inflater != null) {
+ final CompressedUnitsItemInfo.Unit unit =
compressedImageUnit(tileIndex);
inflater.setInputRegion(addExact(origin, unit.offset),
unit.size);
- input = inflater.createDataInput(context.reuseBuffer(), (int)
sourceSize[0]); // (int) cast okay even if inexact.
+ // The following (int) cast is okay even if inexact because it
is only a hint.
+ input = inflater.createDataInput(context.reuseBuffer(), (int)
sourceSize[0]);
origin = 0;
- } else {
- inflater = null;
}
/*
* Now read all banks and store the values in the image buffer.
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemData.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemData.java
index c044b827f8..4432a05528 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemData.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemData.java
@@ -18,7 +18,7 @@ package org.apache.sis.storage.isobmff.base;
import java.io.IOException;
import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.isobmff.ByteRanges;
import org.apache.sis.storage.isobmff.Reader;
import org.apache.sis.storage.isobmff.Box;
@@ -58,9 +58,8 @@ public class ItemData extends Box implements
ByteRanges.Reader {
/**
* Number of bytes to read, or -1 for reading until the end of file.
- * Note that -1 is also the maximal unsigned value.
+ * Note that -1 is also the maximal value when treated as unsigned integer.
*/
- @Interpretation(Type.UNSIGNED)
public final long size;
/**
@@ -82,17 +81,18 @@ public class ItemData extends Box implements
ByteRanges.Reader {
* @param offset offset of the first byte to read relative to the data
stored in this item.
* @param length maximum number of bytes to read, starting at the
offset, or a negative value for reading all.
* @param addTo where to add the range of bytes to read as offsets
relatives to the beginning of the file.
+ * @throws DataStoreContentException if the length is unspecified.
* @throws ArithmeticException if an integer overflow occurred.
*/
@Override
- public void resolve(long offset, long length, ByteRanges addTo) throws
DataStoreException {
+ public void resolve(long offset, long length, ByteRanges addTo) throws
DataStoreContentException {
if (size >= 0) {
ArgumentChecks.ensureBetween("offset", 0, size - Math.max(0,
length), offset);
if (length > size || length < 0) {
length = size;
}
} else if (length < 0) {
- throw new DataStoreException("Stream of unknown length.");
+ throw new DataStoreContentException("Stream of unknown length.");
}
offset = Math.addExact(payloadOffset, offset);
addTo.addRange(offset, Math.addExact(offset, length));
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfoEntry.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfoEntry.java
index ae01af1687..ec648b0edd 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfoEntry.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfoEntry.java
@@ -72,7 +72,8 @@ public final class ItemInfoEntry extends FullBox {
URI = ((((('u' << 8) | 'r') << 8) | 'i') << 8) |
' ',
UNCI = ((((('u' << 8) | 'n') << 8) | 'c') << 8) |
'i',
JPEG = ((((('j' << 8) | 'p') << 8) | 'e') << 8) |
'g',
- GRID = ((((('g' << 8) | 'r') << 8) | 'i') << 8) |
'd';
+ GRID = ((((('g' << 8) | 'r') << 8) | 'i') << 8) |
'd',
+ TILI = ((((('t' << 8) | 'i') << 8) | 'l') << 8) |
'i';
/**
* Item type indicator such as {@link #MIME} or {@link #URI}.
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/TiledImageConfiguration.java
similarity index 97%
rename from
incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
rename to
incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/TiledImageConfiguration.java
index 94b9bb993f..955b7cf8f8 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/TiledImageConfiguration.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sis.storage.isobmff.geo;
+package org.apache.sis.storage.isobmff.image;
import java.io.IOException;
import org.apache.sis.io.stream.ChannelDataInput;
@@ -132,6 +132,7 @@ public final class TiledImageConfiguration extends FullBox {
/**
* Returns the number of bits used to store the length of the image data
of a specific tile.
+ * Value 0 means that size is not stored. Instead, it is computed from
offsets.
*
* @return the number of bits for tile length.
*/
diff --git
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressedUnitsItemInfo.java
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressedUnitsItemInfo.java
index 7385bb2752..bfc4fcdd46 100644
---
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressedUnitsItemInfo.java
+++
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressedUnitsItemInfo.java
@@ -92,7 +92,7 @@ public final class CompressedUnitsItemInfo extends FullBox {
public final long size;
/** Creates a new unit with the given offset and size. */
- Unit(final long offset, final long size) {
+ public Unit(final long offset, final long size) {
this.offset = offset;
this.size = size;
}