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

commit 255d12c4b66ac722d9e831a15c985f08ebe7593e
Author: jsorel <[email protected]>
AuthorDate: Tue Jun 2 14:51:47 2026 +0200

    Basic support of some compression in GeoHEIF files:
    
    - Add `CompressionConfiguration`, `CompressedUnitsItemInfo`, 
`CompressionAV1`, `CompressionJP2K`, `HevcConfigurationItem` and 
`CleanAperture` boxes.
    - Add "auxl", "base", "prem" and "thmb" image references.
    - Support signed integer component, added in ISO:23001-17 amendment 2.
    - Support single chunk of zlib compressed tiles.
    
    The compression boxes such as AV1 and JP2K are mostly empty for now,
    but these boxes were nevertheless added for metadata purpose and also
    for making possible (in a next commit) to provide better error message.
---
 .../org/apache/sis/image/StatisticsCalculator.java |   8 +-
 .../org/apache/sis/io/stream/ChannelDataInput.java |  15 ++-
 .../apache/sis/io/stream/HyperRectangleReader.java |   1 -
 .../main/org/apache/sis/io/stream/Region.java      |   2 +-
 .../sis/storage/geoheif/CoverageBuilder.java       |  70 ++++++++++--
 .../apache/sis/storage/geoheif/GeoHeifStore.java   |  20 ++--
 .../main/org/apache/sis/storage/geoheif/Image.java |   2 +-
 .../sis/storage/geoheif/UncompressedImage.java     |  27 ++++-
 .../sis/storage/isobmff/MainBoxRegistry.java       |  10 ++
 .../org/apache/sis/storage/isobmff/Reader.java     |   4 +-
 .../isobmff/image/AuxiliaryImageReference.java     |  54 +++++++++
 .../storage/isobmff/image/BaseImageReference.java  |  53 +++++++++
 .../isobmff/image/PremultipliedImageReference.java |  53 +++++++++
 .../storage/isobmff/image/ThumbnailReference.java  |  53 +++++++++
 .../sis/storage/isobmff/mpeg/CleanAperture.java    |  57 ++++++++++
 .../apache/sis/storage/isobmff/mpeg/Component.java |   5 +-
 .../isobmff/mpeg/CompressedUnitsItemInfo.java      | 122 +++++++++++++++++++++
 .../sis/storage/isobmff/mpeg/CompressionAV1.java   |  57 ++++++++++
 .../isobmff/mpeg/CompressionConfiguration.java     |  80 ++++++++++++++
 .../sis/storage/isobmff/mpeg/CompressionJP2K.java  |  57 ++++++++++
 .../isobmff/mpeg/HevcConfigurationItem.java        |  57 ++++++++++
 .../apache/sis/storage/isobmff/mpeg/UnitType.java  |  71 ++++++++++++
 22 files changed, 849 insertions(+), 29 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/StatisticsCalculator.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/StatisticsCalculator.java
index 3d480b20c6..61cf0a5288 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/StatisticsCalculator.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/StatisticsCalculator.java
@@ -168,9 +168,11 @@ final class StatisticsCalculator extends AnnotatedImage {
      * Clones the given array and all values in the array.
      */
     static Statistics[] clone(Statistics[] result) {
-        result = result.clone();
-        for (int i=0; i<result.length; i++) {
-            result[i] = result[i].clone();
+        if (result != null) {
+            result = result.clone();
+            for (int i=0; i<result.length; i++) {
+                result[i] = result[i].clone();
+            }
         }
         return result;
     }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelDataInput.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelDataInput.java
index bb819a57e4..53999a9f56 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelDataInput.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelDataInput.java
@@ -1155,7 +1155,7 @@ loop:   while (hasRemaining()) {
     /**
      * Skips over and discards exactly <var>n</var> bytes of data from this 
input stream.
      *
-     * @param  n  number of bytes to skip. Can be negative.
+     * @param  n  number of bytes to skip. Can be negative for moving backward.
      * @throws IOException if an error occurred while reading.
      */
     public final void skipNBytes(int n) throws IOException {
@@ -1165,6 +1165,19 @@ loop:   while (hasRemaining()) {
         }
     }
 
+    /**
+     * Skips over and discards exactly <var>n</var> bytes of data from this 
input stream.
+     *
+     * @param  n  number of bytes to skip. Can be negative for moving backward.
+     * @throws IOException if an error occurred while reading.
+     */
+    public final void skipNBytes(long n) throws IOException {
+        n -= skipBytes((int) Math.min(n, Integer.MAX_VALUE));
+        if (n != 0) {
+            seek(Math.addExact(position(), n));
+        }
+    }
+
     /**
      * Moves to the given position in this stream.
      *
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleReader.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleReader.java
index 512e06d849..0f1e7fbd24 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleReader.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/HyperRectangleReader.java
@@ -51,7 +51,6 @@ public class HyperRectangleReader {
 
     /**
      * The {@code input} position of the first sample (ignoring sub-area and 
subsampling).
-     * This is initially the {@code origin} argument given to the constructor, 
copied verbatim.
      *
      * @see #getOrigin()
      */
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/Region.java 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/Region.java
index 5d1da03a63..4a7bd9442f 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/Region.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/Region.java
@@ -267,7 +267,7 @@ public final class Region {
     /**
      * Compares this region with the given object for equality.
      *
-     * @return the object to compare with this region.
+     * @param  obj  the object to compare with this region.
      * @return whether this region and the given object are equal.
      */
     @Override
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 f72a91de76..c16745d0e4 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
@@ -45,6 +45,8 @@ import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.PixelInCell;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.UnsupportedEncodingException;
 import org.apache.sis.storage.metadata.MetadataBuilder;
 import org.apache.sis.storage.modifier.CoverageModifier;
 import org.apache.sis.storage.isobmff.Box;
@@ -56,7 +58,10 @@ import org.apache.sis.storage.isobmff.mpeg.Component;
 import org.apache.sis.storage.isobmff.mpeg.ComponentType;
 import org.apache.sis.storage.isobmff.mpeg.ComponentPalette;
 import org.apache.sis.storage.isobmff.mpeg.ComponentDefinition;
+import org.apache.sis.storage.isobmff.mpeg.CompressedUnitsItemInfo;
+import org.apache.sis.storage.isobmff.mpeg.CompressionConfiguration;
 import org.apache.sis.storage.isobmff.mpeg.UncompressedFrameConfig;
+import org.apache.sis.storage.isobmff.mpeg.UnitType;
 import org.apache.sis.storage.isobmff.mpeg.InterleavingMode;
 import org.apache.sis.storage.isobmff.image.ImageSpatialExtents;
 import org.apache.sis.storage.isobmff.image.PixelInformation;
@@ -116,6 +121,24 @@ final class CoverageBuilder implements Emptiable {
      */
     private ModelCRS crsDefinition;
 
+    /**
+     * Identification of the compression algorithm.
+     */
+    private CompressionConfiguration compression;
+
+    /**
+     * Locations in the file where to find compressed data.
+     */
+    private CompressedUnitsItemInfo compressedUnits;
+
+    /**
+     * Information about the sample model (data type, <i>etc.</i>).
+     * May be {@code null} if no such information was found.
+     * This is actually a mandatory information according ISO/IEC 
23001-17:2024,
+     * but this class is nevertheless tolerant to its absence.
+     */
+    private UncompressedFrameConfig model;
+
     /**
      * How pixel data should be displayed.
      * Values are instance of {@link ComponentType}, {@link URI} or {@link 
Integer}, in preference order.
@@ -131,14 +154,6 @@ final class CoverageBuilder implements Emptiable {
      */
     private byte[] bitsPerChannel;
 
-    /**
-     * Information about the sample model (data type, <i>etc.</i>).
-     * May be {@code null} if no such information was found.
-     * This is actually a mandatory information according ISO/IEC 
23001-17:2024,
-     * but this class is nevertheless tolerant to its absence.
-     */
-    private UncompressedFrameConfig model;
-
     /**
      * The color palette of an indexed color model.
      * May be {@code null} if no such information was found.
@@ -264,6 +279,18 @@ final class CoverageBuilder implements Emptiable {
                     if (!duplicated) crsDefinition = c;
                     break;
                 }
+                case CompressionConfiguration.BOXTYPE: {
+                    var c = (CompressionConfiguration) property;
+                    duplicated = (compression != null);
+                    if (!duplicated) compression = c;
+                    break;
+                }
+                case CompressedUnitsItemInfo.BOXTYPE: {
+                    var c = (CompressedUnitsItemInfo) property;
+                    duplicated = (compressedUnits != null);
+                    if (!duplicated) compressedUnits = c;
+                    break;
+                }
                 case UncompressedFrameConfig.BOXTYPE: {
                     var c = (UncompressedFrameConfig) property;
                     duplicated = (model != null);
@@ -290,6 +317,33 @@ final class CoverageBuilder implements Emptiable {
         }
     }
 
+    /**
+     * Returns the compression units which contains all image data, or {@code 
null} if the image is uncompressed.
+     * This method requires that the compression unit is {@link 
UnitType#IMAGE_TILE}.
+     *
+     * @return the compression units for the whole image, or {@code null}.
+     * @throws UnsupportedEncodingException if the compression configuration 
is unsupported.
+     * @throws DataStoreContentException if the compression cannot be decoded 
for another reason.
+     */
+    final CompressedUnitsItemInfo.Unit getCompressedImageUnit() throws 
DataStoreContentException {
+        if (compression == null) {
+            return null;
+        }
+        if (compression.unitType == UnitType.IMAGE_TILE) {
+            if (compressedUnits == null) {
+                throw new DataStoreContentException("Missing compressed 
unit.");
+            }
+            final CompressedUnitsItemInfo.Unit[] units = compressedUnits.units;
+            if (units.length == 1) {
+                // Current implementation supports only ZLIB, we may add more 
in the future.
+                if (compression.compressionType == 
CompressionConfiguration.COMPRESSION_ZLIB) {
+                    return units[0];
+                }
+            }
+        }
+        throw new UnsupportedEncodingException("Unsupported compression.");
+    }
+
     /**
      * If any boxes were unrecognized, reports these boxes in a warning.
      * If at least one ignored box was flagged as essential, then this method 
returns {@code true}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java
index 0a1643f888..91a945075b 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java
@@ -70,12 +70,12 @@ public class GeoHeifStore extends DataStore implements 
Aggregate {
 
     /**
      * Same value as {@link #location} but as a path, or {@code null} if none.
-     * Stored separately because conversion from path to URI then back to path
-     * is not looseness (relative paths become absolutes).
+     * Stored separately because conversion from path to <abbr>URI</abbr> then
+     * back to path is not looseness (relative paths become absolutes).
      *
      * @see #getFileSet()
      */
-    private final Path path;
+    private final Path locationAsPath;
 
     /**
      * The data store identifier created from the filename, or {@code null} if 
none.
@@ -141,11 +141,11 @@ public class GeoHeifStore extends DataStore implements 
Aggregate {
      */
     public GeoHeifStore(final DataStoreProvider provider, final 
StorageConnector connector) throws DataStoreException {
         super(provider, connector);
-        location    = connector.getStorageAs(URI.class);
-        path        = connector.getStorageAs(Path.class);
-        input       = connector.commit(ChannelImageInputStream.class, 
GeoHeifStoreProvider.NAME);
-        customizer  = CoverageModifier.getOrDefault(connector);
-        nameFactory = DefaultNameFactory.provider();
+        location       = connector.getStorageAs(URI.class);
+        locationAsPath = connector.getStorageAs(Path.class);
+        input          = connector.commit(ChannelImageInputStream.class, 
GeoHeifStoreProvider.NAME);
+        customizer     = CoverageModifier.getOrDefault(connector);
+        nameFactory    = DefaultNameFactory.provider();
         if (location != null) {
             String filename = 
IOUtilities.filenameWithoutExtension(input.filename);
             namespace = 
nameFactory.createNameSpace(nameFactory.createLocalName(null, filename), null);
@@ -176,8 +176,8 @@ public class GeoHeifStore extends DataStore implements 
Aggregate {
      */
     @Override
     public Optional<FileSet> getFileSet() throws DataStoreException {
-        if (path != null) {
-            return Optional.of(new FileSet(path));
+        if (locationAsPath != null) {
+            return Optional.of(new FileSet(locationAsPath));
         }
         return Optional.empty();
     }
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Image.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Image.java
index 5db1afde60..39813392f9 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Image.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/Image.java
@@ -28,7 +28,7 @@ import org.apache.sis.storage.isobmff.ByteRanges;
 
 
 /**
- * A single image ({@code 'unci'} item type) from the HEIF file.
+ * A single image ({@code 'unci'} item type) from the <abbr>HEIF</abbr> file.
  * An image may be used as a tile in a larger image ({@code 'grid'} item type).
  * In the uncompressed case, the image may be implicitly tiled if {@link 
#numXTiles} is greater than 1.
  *
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 8d65edfa79..df4d47afc4 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
@@ -17,6 +17,8 @@
 package org.apache.sis.storage.geoheif;
 
 import java.util.Arrays;
+import java.util.zip.InflaterInputStream;
+import java.io.ByteArrayInputStream;
 import static java.lang.Math.addExact;
 import static java.lang.Math.multiplyExact;
 import java.awt.image.DataBuffer;
@@ -30,7 +32,9 @@ import org.apache.sis.io.stream.ChannelDataInput;
 import org.apache.sis.io.stream.HyperRectangleReader;
 import org.apache.sis.io.stream.Region;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.isobmff.ByteRanges;
+import org.apache.sis.storage.isobmff.mpeg.CompressedUnitsItemInfo;
 
 
 /**
@@ -38,6 +42,10 @@ import org.apache.sis.storage.isobmff.ByteRanges;
  * An image may be used as a tile in a larger image ({@code 'grid'} item type).
  * The image may be implicitly tiled if {@link #numXTiles} is greater than 1.
  *
+ * <p>This class is named "uncompressed" image because the <abbr>HEIF</abbr> 
format uses that name.
+ * Nevertheless, the data may be composed of compressed units. A compressed 
unit may be the whole
+ * image or only part of it (tile, row or pixel).</p>
+ *
  * <h4>Requirement</h4>
  * This class requires that {@link CoverageBuilder#sampleModel()} can build a 
sample model.
  * In other words, the boxes such as {@code UncompressedFrameConfig} must have 
been found.
@@ -58,6 +66,11 @@ final class UncompressedImage extends Image {
      */
     private final SampleModel sampleModel;
 
+    /**
+     * The compression units which contains all image data, or {@code null} if 
the image is uncompressed.
+     */
+    private final CompressedUnitsItemInfo.Unit compressedImageUnit;
+
     /**
      * Creates a new tile.
      *
@@ -72,6 +85,7 @@ final class UncompressedImage extends Image {
         super(builder, locator, name);
         sampleModel = builder.sampleModel();
         dataType    = builder.dataType();     // Shall be after 
`sampleModel()`.
+        compressedImageUnit = builder.getCompressedImageUnit();
     }
 
     /**
@@ -122,7 +136,16 @@ final class UncompressedImage extends Image {
         final long tileIndex = addExact(multiplyExact(context.subTileY, 
numXTiles), context.subTileX);
         final long offset    = addExact(multiplyExact(tileIndex, tileSize), 
skipBytes);
         locator.resolve(offset, tileSize - skipBytes, context);
-        return (final ChannelDataInput input) -> {
+        return (ChannelDataInput input) -> {
+            long origin = context.offset() - skipBytes;
+            final CompressedUnitsItemInfo.Unit unit = compressedImageUnit;
+            if (unit != null) {
+                input.skipNBytes(unit.offset);
+                final byte[] compressedChunk = input.readBytes((int) 
unit.size);
+                InflaterInputStream iis = new InflaterInputStream(new 
ByteArrayInputStream(compressedChunk));
+                input = new 
StorageConnector(iis).getStorageAs(ChannelDataInput.class);
+                origin = 0;
+            }
             /*
              * Now read all banks and store the values in the image buffer.
              * If there is many banks (`InterleavingMode.COMPONENT`), these
@@ -130,7 +153,7 @@ final class UncompressedImage extends Image {
              */
             input.buffer.order(byteOrder);
             final var hr = new 
HyperRectangleReader(ImageUtilities.toNumberEnum(dataType), input);
-            hr.setOrigin(context.offset() - skipBytes);
+            hr.setOrigin(origin);
             final WritableRaster raster       = context.createRaster();
             final long[]         rasterSize   = size(raster.getSampleModel());
             final Region         rasterRegion = Arrays.equals(sourceSize, 
rasterSize) ? region : region(sourceSize, rasterSize);
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/MainBoxRegistry.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/MainBoxRegistry.java
index 86a0236970..c0e7730736 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/MainBoxRegistry.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/MainBoxRegistry.java
@@ -78,13 +78,20 @@ final class MainBoxRegistry extends BoxRegistry {
     @Override
     public Box create(final Reader reader, final int fourCC) throws 
IOException, DataStoreException {
         switch (fourCC) {
+            case AuxiliaryImageReference.BOXTYPE:       return new 
AuxiliaryImageReference(reader);
+            case BaseImageReference.BOXTYPE:            return new 
BaseImageReference(reader);
             case ChromaLocation.BOXTYPE:                return new 
ChromaLocation(reader);
+            case CleanAperture.BOXTYPE:                 return new 
CleanAperture(reader);
             case ColourInformation.BOXTYPE:             return new 
ColourInformation(reader);
             case CombinaisonType.BOXTYPE:               return new 
CombinaisonType(reader);
             case ComponentDefinition.BOXTYPE:           return 
reader.componentDefinition = new ComponentDefinition(reader);
             case ComponentPalette.BOXTYPE:              return new 
ComponentPalette(reader, reader.componentDefinition);
             case ComponentPatternDefinition.BOXTYPE:    return new 
ComponentPatternDefinition(reader, reader.componentDefinition);
             case ComponentReferenceLevel.BOXTYPE:       return new 
ComponentReferenceLevel(reader);
+            case CompressedUnitsItemInfo.BOXTYPE:       return new 
CompressedUnitsItemInfo(reader);
+            case CompressionAV1.BOXTYPE:                return new 
CompressionAV1(reader);
+            case CompressionConfiguration.BOXTYPE:      return new 
CompressionConfiguration(reader);
+            case CompressionJP2K.BOXTYPE:               return new 
CompressionJP2K(reader);
             case ContentDescribes.BOXTYPE:              return new 
ContentDescribes(reader);
             case Copyright.BOXTYPE:                     return new 
Copyright(reader);
             case CreationTime.BOXTYPE:                  return new 
CreationTime(reader);
@@ -101,6 +108,7 @@ final class MainBoxRegistry extends BoxRegistry {
             case FreeSpace.BOXTYPE:                     return new FreeSpace();
             case GroupList.BOXTYPE:                     return new 
GroupList(reader);
             case HandlerReference.BOXTYPE:              return new 
HandlerReference(reader);
+            case HevcConfigurationItem.BOXTYPE:         return new 
HevcConfigurationItem(reader);
             case IdentifiedMediaData.BOXTYPE:           return new 
IdentifiedMediaData(reader);
             case ImagePyramid.BOXTYPE:                  return new 
ImagePyramid(reader);
             case ImageSpatialExtents.BOXTYPE:           return new 
ImageSpatialExtents(reader);
@@ -123,12 +131,14 @@ final class MainBoxRegistry extends BoxRegistry {
             case OriginalFileType.BOXTYPE:              return new 
OriginalFileType(reader);
             case PixelInformation.BOXTYPE:              return new 
PixelInformation(reader);
             case PolarizationPatternDefinition.BOXTYPE: return new 
PolarizationPatternDefinition(reader);
+            case PremultipliedImageReference.BOXTYPE:   return new 
PremultipliedImageReference(reader);
             case PrimaryItem.BOXTYPE:                   return new 
PrimaryItem(reader);
             case ProgressiveDownloadInfo.BOXTYPE:       return new 
ProgressiveDownloadInfo(reader);
             case SensorBadPixelsMap.BOXTYPE:            return new 
SensorBadPixelsMap(reader);
             case SensorNonUniformityCorrection.BOXTYPE: return new 
SensorNonUniformityCorrection(reader);
             case TAIClockInfo.BOXTYPE:                  return new 
TAIClockInfo(reader);
             case TAITimeStamp.BOXTYPE:                  return new 
TAITimeStamp(reader);
+            case ThumbnailReference.BOXTYPE:            return new 
ThumbnailReference(reader);
             case TiledImageConfiguration.BOXTYPE:       return new 
TiledImageConfiguration(reader);
             case Track.BOXTYPE:                         return new 
Track(reader);
             case TrackHeader.BOXTYPE:                   return new 
TrackHeader(reader, reader.movieHeader);
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Reader.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Reader.java
index fab31bd934..3e66f51870 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Reader.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Reader.java
@@ -214,7 +214,9 @@ public final class Reader implements Cloneable {
             }
         }
         endOfCurrentBox = end;      // May have been modified by recursive 
invocations.
-        assert (end < 0) || input.getStreamPosition() <= end : 
Box.formatFourCC(box.type());
+        if (end >= 0 && input.getStreamPosition() > end) {
+            throw new DataStoreContentException("The \"" + 
Box.formatFourCC(box.type()) + "\" box is longer than expected.");
+        }
         return box;
     }
 
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/AuxiliaryImageReference.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/AuxiliaryImageReference.java
new file mode 100644
index 0000000000..37828c2d18
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/AuxiliaryImageReference.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed withz
+ * 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.isobmff.image;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.base.SingleItemTypeReference;
+
+
+/**
+ * Image other than thumbnail which is related to a master image.
+ * Example: an alpha plane.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class AuxiliaryImageReference extends SingleItemTypeReference {
+    /**
+     * Numerical representation of the {@code "auxl"} box type.
+     */
+    public static final int BOXTYPE = ((((('a' << 8) | 'u') << 8) | 'x') << 8) 
| 'l';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public AuxiliaryImageReference(final Reader reader) throws IOException {
+        super(reader, false);
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/BaseImageReference.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/BaseImageReference.java
new file mode 100644
index 0000000000..35aafce21a
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/BaseImageReference.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed withz
+ * 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.isobmff.image;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.base.SingleItemTypeReference;
+
+
+/**
+ * Base image reference.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class BaseImageReference extends SingleItemTypeReference {
+    /**
+     * Numerical representation of the {@code "base"} box type.
+     */
+    public static final int BOXTYPE = ((((('b' << 8) | 'a') << 8) | 's') << 8) 
| 'e';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public BaseImageReference(final Reader reader) throws IOException {
+        super(reader, false);
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/PremultipliedImageReference.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/PremultipliedImageReference.java
new file mode 100644
index 0000000000..61a86bd1b2
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/PremultipliedImageReference.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed withz
+ * 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.isobmff.image;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.base.SingleItemTypeReference;
+
+
+/**
+ * Color values in an image have been premultiplied with alpha values.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class PremultipliedImageReference extends SingleItemTypeReference 
{
+    /**
+     * Numerical representation of the {@code "prem"} box type.
+     */
+    public static final int BOXTYPE = ((((('p' << 8) | 'r') << 8) | 'e') << 8) 
| 'm';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public PremultipliedImageReference(final Reader reader) throws IOException 
{
+        super(reader, false);
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/ThumbnailReference.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/ThumbnailReference.java
new file mode 100644
index 0000000000..da99569fca
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/image/ThumbnailReference.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed withz
+ * 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.isobmff.image;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.base.SingleItemTypeReference;
+
+
+/**
+ * Image is a thumbnail of another image.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public final class ThumbnailReference extends SingleItemTypeReference {
+    /**
+     * Numerical representation of the {@code "thmb"} box type.
+     */
+    public static final int BOXTYPE = ((((('t' << 8) | 'h') << 8) | 'm') << 8) 
| 'b';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public ThumbnailReference(final Reader reader) throws IOException {
+        super(reader, false);
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CleanAperture.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CleanAperture.java
new file mode 100644
index 0000000000..d55594e389
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CleanAperture.java
@@ -0,0 +1,57 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Box;
+import org.apache.sis.storage.isobmff.Incomplete;
+import org.apache.sis.storage.isobmff.Reader;
+
+
+/**
+ * Cropping transformation of the input image.
+ * <b>Not yet implemented.</b>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+@Incomplete
+public final class CleanAperture extends Box {
+    /**
+     * Numerical representation of the {@code "clap"} box type.
+     */
+    public static final int BOXTYPE = ((((('c' << 8) | 'l') << 8) | 'a') << 8) 
| 'p';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public CleanAperture(final Reader reader) {
+        // TODO
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/Component.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/Component.java
index 0abf1ec19d..70146b2c57 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/Component.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/Component.java
@@ -72,6 +72,7 @@ public final class Component extends TreeNode {
      *   <li>0: unsigned integer coded on {@link #bitDepth} bits.</li>
      *   <li>1: IEEE 754 floating point coded on {@link #bitDepth} bits: 16, 
32, 64, 128 or 256.</li>
      *   <li>2: complex number where the real and imaginary parts are coded on 
{@link #bitDepth} bits each.</li>
+     *   <li>3: signed integer coded on {@link #bitDepth} bits. Added in 
ISO/IEC 23001-17:2024/Amd 2:2025.</li>
      * </ul>
      *
      * Other values are reserved by ISO/IEC for future definitions.
@@ -128,12 +129,14 @@ public final class Component extends TreeNode {
      * @throws RasterFormatException if the {@link #format} value is 
unsupported.
      */
     public DataType getDataType() {
+        boolean signed = false;
         boolean real = false;
         switch (format) {
             case 0: break;
             case 1: real = true; break;
+            case 3: signed = true; break;
             default: throw new 
RasterFormatException(Errors.format(Errors.Keys.UnsupportedFormat_1, format));
         }
-        return DataType.forNumberOfBits(Short.toUnsignedInt(bitDepth), real, 
false);
+        return DataType.forNumberOfBits(Short.toUnsignedInt(bitDepth), real, 
signed);
     }
 }
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
new file mode 100644
index 0000000000..7385bb2752
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressedUnitsItemInfo.java
@@ -0,0 +1,122 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.io.stream.ChannelDataInput;
+import org.apache.sis.storage.isobmff.FullBox;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.TreeNode;
+import org.apache.sis.storage.isobmff.UnsupportedVersionException;
+
+
+/**
+ * Compressed units item info.
+ *
+ * <p><b>Source:</b> ISO/IEC 23001-17:2024/Amd 2:2025</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+public final class CompressedUnitsItemInfo extends FullBox {
+    /**
+     * Numerical representation of the {@code "icef"} box type.
+     */
+    public static final int BOXTYPE = ((((('i' << 8) | 'c') << 8) | 'e') << 8) 
| 'f';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Mapping from the 3 bits encoded in the stream to the actual unit offset 
size.
+     */
+    private static final byte[] OFFSET_LENGTHS = new byte[] {0, Short.SIZE, 
3*Byte.SIZE, Integer.SIZE, Long.SIZE};
+
+    /**
+     * Mapping from the 3 bits encoded in the stream to the actual unit size 
value.
+     */
+    private static final byte[] SIZE_LENGTHS = new byte[] {Byte.SIZE, 
Short.SIZE, 3*Byte.SIZE, Integer.SIZE, Long.SIZE};
+
+    /**
+     * Number of bits used to encode the offset of an unit.
+     * This information is not needed after the box has been read, but is kept 
for metadata purpose.
+     */
+    @Interpretation(Type.UNSIGNED)
+    public final byte offsetFieldLength;
+
+    /**
+     * Number of bits used to encode the size of an unit, or 0.
+     * This information is not needed after the box has been read, but is kept 
for metadata purpose.
+     *
+     * @todo What is the meaning of 0? Does it means that the size has the 
same size as the offset?
+     */
+    @Interpretation(Type.UNSIGNED)
+    public final byte sizeFieldLength;
+
+    /**
+     * Compressed units offsets and sizes.
+     * The number of compressed units is the length of this array.
+     */
+    public final Unit[] units;
+
+    /**
+     * A unit specified by an offset and a size.
+     */
+    public static final class Unit extends TreeNode {
+        /** The offset in bytes, or 0 if unspecified. */
+        @Interpretation(Type.UNSIGNED)
+        public final long offset;
+
+        /** The size in bytes. */
+        @Interpretation(Type.UNSIGNED)
+        public final long size;
+
+        /** Creates a new unit with the given offset and size. */
+        Unit(final long offset, final long size) {
+            this.offset = offset;
+            this.size   = size;
+        }
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public CompressedUnitsItemInfo(final Reader reader) throws IOException, 
UnsupportedVersionException {
+        super(reader);
+        requireVersionZero();
+        final ChannelDataInput input = reader.input;
+        final int unitLayout = input.readUnsignedByte();
+        offsetFieldLength = OFFSET_LENGTHS[(unitLayout >>> (Byte.SIZE - 3)) & 
0b111];
+        sizeFieldLength   =   SIZE_LENGTHS[(unitLayout >>> (Byte.SIZE - 6)) & 
0b111];
+        final int numCompressedUnits = input.readInt();
+        units = new Unit[numCompressedUnits];
+        for (int i = 0; i < numCompressedUnits; i++) {
+            units[i] = new Unit(input.readBits(offsetFieldLength),
+                                input.readBits(sizeFieldLength));
+        }
+        input.skipRemainingBits();
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionAV1.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionAV1.java
new file mode 100644
index 0000000000..3d802c4fb5
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionAV1.java
@@ -0,0 +1,57 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Box;
+import org.apache.sis.storage.isobmff.Incomplete;
+import org.apache.sis.storage.isobmff.Reader;
+
+
+/**
+ * AV1 compression.
+ * <b>Not yet implemented.</b>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+@Incomplete
+public final class CompressionAV1 extends Box {
+    /**
+     * Numerical representation of the {@code "av1C"} box type.
+     */
+    public static final int BOXTYPE = ((((('a' << 8) | 'v') << 8) | '1') << 8) 
| 'C';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public CompressionAV1(final Reader reader) {
+        // TODO
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
new file mode 100644
index 0000000000..abe2a52fd1
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionConfiguration.java
@@ -0,0 +1,80 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.io.stream.ChannelDataInput;
+import org.apache.sis.storage.isobmff.FullBox;
+import org.apache.sis.storage.isobmff.Reader;
+import org.apache.sis.storage.isobmff.UnsupportedVersionException;
+
+
+/**
+ * Compression configuration box.
+ *
+ * <p><b>Source:</b> ISO/IEC 23001-17:2024/Amd 2:2025</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+public final class CompressionConfiguration extends FullBox {
+    /**
+     * Numerical representation of the {@code "cmpC"} box type.
+     */
+    public static final int BOXTYPE = ((((('c' << 8) | 'm') << 8) | 'p') << 8) 
| 'C';
+
+    /**
+     * The {@code "zlib"} value for {@link #compressionType}.
+     */
+    public static final int COMPRESSION_ZLIB = ((((('z' << 8) | 'l') << 8) | 
'i') << 8) | 'b';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Identifier of the compression.
+     *
+     * @see #COMPRESSION_ZLIB
+     */
+    @Interpretation(Type.FOURCC)
+    public final int compressionType;
+
+    /**
+     * Identifier of which data are in a unit, or {@code null} if unknown.
+     */
+    public final UnitType unitType;
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public CompressionConfiguration(final Reader reader) throws IOException, 
UnsupportedVersionException {
+        super(reader);
+        requireVersionZero();
+        final ChannelDataInput input = reader.input;
+        compressionType = input.readInt();
+        unitType = UnitType.valueOf(input.readUnsignedByte());
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionJP2K.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionJP2K.java
new file mode 100644
index 0000000000..024fbde4a7
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/CompressionJP2K.java
@@ -0,0 +1,57 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Box;
+import org.apache.sis.storage.isobmff.Incomplete;
+import org.apache.sis.storage.isobmff.Reader;
+
+
+/**
+ * <abbr>JPEG</abbr> 2000 compression.
+ * <b>Not yet implemented.</b>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+@Incomplete
+public final class CompressionJP2K extends Box {
+    /**
+     * Numerical representation of the {@code "j2kH"} box type.
+     */
+    public static final int BOXTYPE = ((((('j' << 8) | '2') << 8) | 'k') << 8) 
| 'H';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public CompressionJP2K(final Reader reader) {
+        // TODO
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/HevcConfigurationItem.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/HevcConfigurationItem.java
new file mode 100644
index 0000000000..70b3f8149c
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/HevcConfigurationItem.java
@@ -0,0 +1,57 @@
+/*
+ * 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,z
+ * 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.isobmff.mpeg;
+
+import java.io.IOException;
+import org.apache.sis.storage.isobmff.Box;
+import org.apache.sis.storage.isobmff.Incomplete;
+import org.apache.sis.storage.isobmff.Reader;
+
+
+/**
+ * <abbr>HEVC</abbr> configuration item.
+ * <b>Not yet implemented.</b>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+@Incomplete
+public final class HevcConfigurationItem extends Box {
+    /**
+     * Numerical representation of the {@code "hvcC"} box type.
+     */
+    public static final int BOXTYPE = ((((('h' << 8) | 'v') << 8) | 'c') << 8) 
| 'C';
+
+    /**
+     * Returns the four-character type of this box.
+     * This value is fixed to {@link #BOXTYPE}.
+     */
+    @Override
+    public final int type() {
+        return BOXTYPE;
+    }
+
+    /**
+     * Creates a new box and loads the payload from the given reader.
+     *
+     * @param  reader  the reader from which to read the payload.
+     * @throws IOException if an error occurred while reading the payload.
+     */
+    public HevcConfigurationItem(final Reader reader) {
+        // TODO
+    }
+}
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/UnitType.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/UnitType.java
new file mode 100644
index 0000000000..e91ad57747
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/mpeg/UnitType.java
@@ -0,0 +1,71 @@
+/*
+ * 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.isobmff.mpeg;
+
+
+/**
+ * Identifies which data are in a unit.
+ *
+ * In the current version, the ordinal of each enumeration value is the 
numerical code stored
+ * in <abbr>HEIF</abbr> files, but this is not yet a requirement and may 
change in the future.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ */
+public enum UnitType {
+    /**
+     * The unit contains the full item.
+     */
+    FULL_ITEM,
+
+    /**
+     * The unit contains an image.
+     */
+    IMAGE,
+
+    /**
+     * The unit contains an image tile.
+     */
+    IMAGE_TILE,
+
+    /**
+     * The unit contains a row of an image time.
+     */
+    IMAGE_ROW,
+
+    /**
+     * The unit contains a pixel of a row.
+     */
+    IMAGE_PIXEL;
+
+    /**
+     * Returns the enumeration value for the given code, or {@code null} if 
unknown.
+     *
+     * @param  code  code stored in <abbr>HEIF</abbr> file.
+     * @return enumeration value for the given code, or {@code null} if 
unknown.
+     */
+    public static UnitType valueOf(final int code) {
+        switch (code) {
+            case 0:  return FULL_ITEM;
+            case 1:  return IMAGE;
+            case 2:  return IMAGE_TILE;
+            case 3:  return IMAGE_ROW;
+            case 4:  return IMAGE_PIXEL;
+            default: return null;
+        }
+    }
+}

Reply via email to