This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new 4049ee5d82 Add a DataType.UINT type for distinguishing whether Java2D `DataBuffer.TYPE_INT` should be interpreted as signed or unsigned. The sign of the integer type is ambiguous in Java2D, as it depends on the context. Methods were added in `DataType` for handling this ambiguity. 4049ee5d82 is described below commit 4049ee5d8216fac74b93cd1ff7a2b71ac7404d99 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Dec 27 16:57:55 2024 +0100 Add a DataType.UINT type for distinguishing whether Java2D `DataBuffer.TYPE_INT` should be interpreted as signed or unsigned. The sign of the integer type is ambiguous in Java2D, as it depends on the context. Methods were added in `DataType` for handling this ambiguity. --- .../org/apache/sis/image/BandAggregateLayout.java | 8 +- .../apache/sis/image/BandedSampleConverter.java | 2 +- .../main/org/apache/sis/image/DataType.java | 217 ++++++++++++++++----- .../main/org/apache/sis/image/PixelIterator.java | 12 +- .../main/org/apache/sis/image/ResampledImage.java | 2 +- .../main/org/apache/sis/image/Transferer.java | 6 +- .../apache/sis/image/privy/ColorModelBuilder.java | 3 +- .../apache/sis/image/privy/ColorModelFactory.java | 6 +- .../apache/sis/image/privy/ColorScaleBuilder.java | 8 +- .../org/apache/sis/image/privy/ImageUtilities.java | 84 +------- .../org/apache/sis/image/privy/RasterFactory.java | 7 +- .../apache/sis/image/privy/TilePlaceholder.java | 5 +- .../test/org/apache/sis/image/DataTypeTest.java | 28 ++- .../apache/sis/image/privy/ImageUtilitiesTest.java | 16 -- .../org/apache/sis/storage/geotiff/DataSubset.java | 2 +- .../sis/storage/geotiff/ImageFileDirectory.java | 2 +- .../org/apache/sis/storage/geotiff/Writer.java | 4 +- .../storage/geotiff/inflater/CopyFromBytes.java | 3 +- .../geotiff/inflater/HorizontalPredictor.java | 5 +- .../geotiff/writer/HorizontalPredictor.java | 5 +- .../storage/geotiff/writer/ReformattedImage.java | 5 +- .../sis/storage/geotiff/writer/TileMatrix.java | 1 + .../apache/sis/storage/netcdf/base/DataType.java | 2 +- .../apache/sis/storage/base/TiledGridResource.java | 2 +- .../org/apache/sis/storage/esri/RasterStore.java | 8 +- .../main/org/apache/sis/gui/coverage/GridView.java | 4 +- 26 files changed, 247 insertions(+), 200 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandAggregateLayout.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandAggregateLayout.java index 4d700e5aba..fdadc5e8cf 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandAggregateLayout.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandAggregateLayout.java @@ -22,7 +22,6 @@ import java.awt.Point; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.image.ColorModel; -import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; @@ -154,7 +153,7 @@ final class BandAggregateLayout { int tileHeight = 0; int tileAlignX = 0; int tileAlignY = 0; - int commonDataType = DataBuffer.TYPE_UNDEFINED; + DataType commonDataType = null; for (final RenderedImage source : sources) { /* * Ensure that all images use the same data type. This is mandatory. @@ -173,7 +172,7 @@ final class BandAggregateLayout { allowSharing |= (domain == null); } } - final int dataType = sm.getDataType(); + final var dataType = DataType.forBands(sm); if (domain == null) { domain = ImageUtilities.getBounds(source); commonDataType = dataType; @@ -234,9 +233,8 @@ final class BandAggregateLayout { final boolean exactTileSize = ((cx | cy) >>> Integer.SIZE) == 0; allowSharing &= exactTileSize; if (!allowSharing) scanlineStride = 0; // Means to force the use of tile width. - final var dataType = DataType.forDataBufferType(commonDataType); final var layout = new ImageLayout(null, preferredTileSize, !exactTileSize, false, false, minTile); - sampleModel = layout.createBandedSampleModel(null, domain, dataType, numBands, scanlineStride); + sampleModel = layout.createBandedSampleModel(null, domain, commonDataType, numBands, scanlineStride); } this.bandsPerSource = bandsPerSource; this.sources = sources; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java index 25d5ae161c..348e3f4a27 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java @@ -148,7 +148,7 @@ class BandedSampleConverter extends WritableComputedImage { } if (!Double.isFinite(middle)) { final SampleModel sm = source.getSampleModel(); - if (ImageUtilities.isUnsignedType(sm)) { + if (DataType.isUnsigned(sm)) { middle = Math.scalb(0.5, sm.getSampleSize(i)); } else { middle = 0; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/DataType.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/DataType.java index 0bb49fc4bb..caea60edb2 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/DataType.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/DataType.java @@ -16,62 +16,84 @@ */ package org.apache.sis.image; +import java.awt.image.Raster; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.RasterFormatException; +import java.awt.image.SampleModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; import org.apache.sis.util.Numbers; +import org.apache.sis.util.ArraysExt; +import org.apache.sis.util.resources.Errors; import org.apache.sis.measure.NumberRange; import org.apache.sis.image.privy.ImageUtilities; import org.apache.sis.feature.internal.Resources; -import org.apache.sis.util.resources.Errors; import static org.apache.sis.util.privy.Numerics.MAX_INTEGER_CONVERTIBLE_TO_FLOAT; /** * Identification of the primitive type used for storing sample values in an image. - * This is a type-safe version of the {@code TYPE_*} constants defined in {@link DataBuffer}. + * This is a type-safe version of the {@code TYPE_*} constants defined in {@link DataBuffer}, + * except that this enumeration distinguishes signed and unsigned 32 bits integers. * * @author Martin Desruisseaux (Geomatys) * @version 1.5 * @since 1.1 */ public enum DataType { - /* - * Enumeration values must be declared in order of increasing `DataBuffer.TYPE_*` constant values, - * without skiping values. This requirement allow us to get `FOO.ordinal() == DataBuffer.TYPE_FOO`. - * This matching is verified by DataTypeTest.verifyOrdinalValues(). - */ - /** * Unsigned 8-bits data. + * Mapped to {@link DataBuffer#TYPE_BYTE} in Java2D <abbr>API</abbr>. */ - BYTE((byte) 0), + BYTE(DataBuffer.TYPE_BYTE, (byte) 0), /** * Unsigned 16-bits data. + * Mapped to {@link DataBuffer#TYPE_USHORT} in Java2D <abbr>API</abbr>. */ - USHORT((short) 0), + USHORT(DataBuffer.TYPE_USHORT, (short) 0), /** * Signed 16-bits data. + * Mapped to {@link DataBuffer#TYPE_SHORT} in Java2D <abbr>API</abbr>. + */ + SHORT(DataBuffer.TYPE_SHORT, (short) 0), + + /** + * Signed 32-bits data. + * Mapped to {@link DataBuffer#TYPE_INT} in Java2D <abbr>API</abbr>. + * Note that the sign of the latter Java2D type is ambiguous. + * See {@link #forDataBufferType(int)} for more information. */ - SHORT((short) 0), + INT(DataBuffer.TYPE_INT, 0), /** - * Signed 32-bits data. Also used for storing unsigned data; the Java2D API such as - * {@link java.awt.image.Raster#getSample(int, int, int)} cannot distinguish the two cases. + * Unsigned 32-bits data. + * Mapped to {@link DataBuffer#TYPE_INT} in Java2D <abbr>API</abbr>. + * Note that the sign of the latter Java2D type is ambiguous. + * See {@link #forDataBufferType(int)} for more information. + * + * @since 1.5 */ - INT(0), + UINT(DataBuffer.TYPE_INT, 0), /** * Single precision (32-bits) floating point data. + * Mapped to {@link DataBuffer#TYPE_FLOAT} in Java2D <abbr>API</abbr>. */ - FLOAT(Float.NaN), + FLOAT(DataBuffer.TYPE_FLOAT, Float.NaN), /** * Double precision (64-bits) floating point data. + * Mapped to {@link DataBuffer#TYPE_DOUBLE} in Java2D <abbr>API</abbr>. + */ + DOUBLE(DataBuffer.TYPE_DOUBLE, Double.NaN); + + /** + * The data buffer type as one of the {@code DataBuffer.TYPE_*} constants. */ - DOUBLE(Double.NaN); + private final int dataType; /** * The default fill value, which is 0 for integer types and NaN for floating point types. @@ -82,32 +104,63 @@ public enum DataType { private final Number fillValue; /** - * All enumeration values, cached for avoiding to recreate this array - * on every {@link #forDataBufferType(int)} call. + * Enumeration values for {@code DataBuffer.TYPE_*} constants. + * The unsigned variant of {@code TYPE_INT} is discarded, keeping the signed variant. + * + * @see #forDataBufferType(int) */ - private static final DataType[] VALUES = values(); + private static final DataType[] VALUES = ArraysExt.remove(values(), DataBuffer.TYPE_INT + 1, 1); /** - * Creates a new enumeration. + * Creates a new enumeration value. */ - private DataType(final Number fillValue) { + private DataType(final int dataType, final Number fillValue) { + this.dataType = dataType; this.fillValue = fillValue; } /** - * Returns the data type of the bands in the given image. This is often the - * {@linkplain java.awt.image.SampleModel#getDataType() storage data type}, but not necessarily. - * For example if an ARGB image uses a storage mode where the sample values in the 4 bands are - * {@linkplain java.awt.image.SinglePixelPackedSampleModel packed in a single 32-bits integer}, - * then this method returns {@link #BYTE} (the type of a single band), not {@link #INT} - * (the type of a whole pixel). + * Returns the data type of the bands in the given image. + * This is often the {@linkplain SampleModel#getDataType() storage data type}, but not necessarily. + * See {@link #forBands(SampleModel)} for more information. * - * @param image the image for which to get the type. - * @return type of the given image (never {@code null}). + * @param image the image for which to get the band data type. + * @return type of sample values in the given image (never {@code null}). * @throws RasterFormatException if the image does not use a recognized data type. */ public static DataType forBands(final RenderedImage image) { - return forDataBufferType(ImageUtilities.getBandType(image.getSampleModel())); + return forBands(image.getSampleModel()); + } + + /** + * Returns the data type of the bands managed by the given the sample model. + * This is often the {@linkplain SampleModel#getDataType() storage data type}, but not necessarily. + * For example, if an <abbr>ARGB</abbr> image uses a storage mode where the sample values in the + * four bands are {@linkplain SinglePixelPackedSampleModel packed in a single 32-bits integer}, + * then this method returns {@link #BYTE} (the type of a single band) rather than {@link #INT} + * (the type of a whole pixel). + * + * @param sm the sample model for which to get the band data type. + * @return type of sample values in the bands managed by the given sample model (never {@code null}). + * @throws RasterFormatException if the sample model does not use a recognized data type. + * + * @since 1.5 + */ + public static DataType forBands(final SampleModel sm) { + final int type = sm.getDataType(); + if (type > DataBuffer.TYPE_BYTE && type <= DataBuffer.TYPE_INT) { + int numBits = 0; + for (int i=sm.getNumBands(); --i >= 0;) { + numBits = Math.max(numBits, sm.getSampleSize(i)); + } + if (isUnsigned(sm)) { + return (numBits <= Byte.SIZE) ? BYTE : + (numBits <= Short.SIZE) ? USHORT : UINT; + } else { + return (numBits <= Short.SIZE) ? SHORT : INT; + } + } + return forDataBufferType(type); } /** @@ -117,7 +170,7 @@ public enum DataType { * <ul> * <li>If {@code asInteger} is {@code false}, then this method returns * {@link #FLOAT} or {@link #DOUBLE} depending on the range type.</li> - * <li>Otherwise this method treats the floating point values as if they + * <li>Otherwise, this method treats the floating point values as if they * were integers, with minimum value rounded toward negative infinity * and maximum value rounded toward positive infinity.</li> * </ul> @@ -147,13 +200,13 @@ public enum DataType { } } /* - * Check most common types first. If the range could be both signed and unsigned short, - * give precedence to unsigned short because it works better with IndexColorModel. + * Check most common types first. If the range could be both signed and unsigned, + * give precedence to unsigned types because it works better with IndexColorModel. * If a bounds is NaN, fallback on TYPE_FLOAT. */ final DataType type; - if (min >= -0.5 && max < 0xFFFF + 0.5) { - type = (max < 0xFF + 0.5) ? BYTE : USHORT; + if (min >= -0.5 && max < 0xFFFFFFFF + 0.5) { + type = (max < 0xFF + 0.5) ? BYTE : (max < 0xFFFF + 0.5) ? USHORT : UINT; } else if (min >= Short.MIN_VALUE - 0.5 && max < Short.MAX_VALUE + 0.5) { type = SHORT; } else if (min >= Integer.MIN_VALUE - 0.5 && max < Integer.MAX_VALUE + 0.5) { @@ -177,7 +230,7 @@ public enum DataType { switch (Numbers.getEnumConstant(type)) { case Numbers.BYTE: return unsigned ? BYTE : SHORT; case Numbers.SHORT: return unsigned ? USHORT : SHORT; - case Numbers.INTEGER: if (unsigned) break; else return INT; + case Numbers.INTEGER: return unsigned ? UINT : INT; case Numbers.FLOAT: return FLOAT; case Numbers.DOUBLE: return DOUBLE; } @@ -189,6 +242,24 @@ public enum DataType { * This method is the converse of {@link #toDataBufferType()}. * It is provided for interoperability with Java2D. * + * <h4>32 bit integers</h4> + * The case of {@link DataBuffer#TYPE_INT} is ambiguous. + * Whether this type is considered as signed or unsigned depends on the context: + * <ul> + * <li>The sign is indistinguishable when using Java2D <abbr>API</abbr> working on integer values + * such as the {@link Raster#getSample(int, int, int) Raster.getSample(…)} method.</li> + * <li>When converted to floating point values by Java2D <abbr>API</abbr> such as + * {@link Raster#getSampleFloat(int, int, int) Raster.getSampleFloat(…)}, sample values are: + * <ul> + * <li>Unsigned when the raster uses {@link SinglePixelPackedSampleModel} or {@link MultiPixelPackedSampleModel}.</li> + * <li>Signed when the raster uses any other type of sample model.</li> + * </ul> + * </li> + * <li>The type is <em>unsigned</em> when converted to a color by {@link java.awt.image.ComponentColorModel}.</li> + * </ul> + * + * For resolving above ambiguities, consider using {@link #forBands(SampleModel)} instead of this method. + * * @param type one of {@code DataBuffer.TYPE_*} constants. * @return the data type (never {@code null}) for the given data buffer type. * @throws RasterFormatException if the given type is not a recognized {@code DataBuffer.TYPE_*} constant. @@ -213,7 +284,7 @@ public enum DataType { * <tr><td>4</td> <td>{@code false}</td> <td>{@code false}</td></tr> * <tr><td>{@value Byte#SIZE}</td> <td>{@code false}</td> <td>{@code false}</td></tr> * <tr><td>{@value Short#SIZE}</td> <td>{@code false}</td> <td>{@code false} or {@code true}</td></tr> - * <tr><td>{@value Integer#SIZE}</td> <td>{@code false}</td> <td>{@code true}</td></tr> + * <tr><td>{@value Integer#SIZE}</td> <td>{@code false}</td> <td>{@code false} or {@code true}</td></tr> * <tr><td>{@value Float#SIZE}</td> <td>{@code true}</td> <td>ignored</td></tr> * <tr><td>{@value Double#SIZE}</td> <td>{@code true}</td> <td>ignored</td></tr> * </table> @@ -238,14 +309,12 @@ public enum DataType { case Double.SIZE: return DOUBLE; } } else { - if (size == Short.SIZE) { - return signed ? SHORT : USHORT; + switch (size) { + case Short.SIZE: return signed ? SHORT : USHORT; + case Integer.SIZE: return signed ? INT : UINT; } - final boolean isInt = (size == Integer.SIZE); - if (isInt || size <= Byte.SIZE) { - if (isInt == signed) { - return isInt ? INT : BYTE; - } + if (size <= Byte.SIZE) { + if (!signed) return BYTE; argument = "signed"; value = signed; } @@ -259,7 +328,7 @@ public enum DataType { * @return size in bits of this data type. */ public final int size() { - return DataBuffer.getDataTypeSize(ordinal()); + return DataBuffer.getDataTypeSize(dataType); } /** @@ -276,22 +345,65 @@ public enum DataType { /** * Returns whether this type is an unsigned integer type. - * Unsigned types are {@link #BYTE} and {@link #USHORT}. + * Unsigned types are {@link #BYTE}, {@link #USHORT} and {@link #UINT}. * * @return {@code true} if this type is an unsigned integer type. */ public final boolean isUnsigned() { - return ordinal() <= DataBuffer.TYPE_USHORT; + return dataType <= DataBuffer.TYPE_USHORT || this == UINT; + } + + /** + * Returns {@code true} if the type of sample values is an unsigned integer type. + * Returns {@code false} if the type is a floating point type or in case of doubt + * (e.g. for {@link DataBuffer#TYPE_UNDEFINED}). + * + * @param sm the sample model, or {@code null}. + * @return whether the given sample model provides unsigned sample values. + * + * @since 1.5 + */ + public static boolean isUnsigned(final SampleModel sm) { + if (sm != null) { + final int dataType = sm.getDataType(); + if (dataType >= DataBuffer.TYPE_BYTE) { + if (dataType <= DataBuffer.TYPE_USHORT) return true; + if (dataType <= DataBuffer.TYPE_INT) { + /* + * Typical case: 4 bands (ARGB) stored in a single data element of type `int`. + * The javadoc of those classes explain how to unpack the sample values, + * and the result is always unsigned. + */ + return (sm instanceof SinglePixelPackedSampleModel) || + (sm instanceof MultiPixelPackedSampleModel); + } + } + } + return false; } /** * Returns whether this type is an integer type, signed or not. - * Integer types are {@link #BYTE}, {@link #USHORT}, {@link #SHORT} and {@link #INT}. + * Integer types are {@link #BYTE}, {@link #USHORT}, {@link #SHORT}, {@link #INT} and {@link #UINT}. * * @return {@code true} if this type is an integer type. */ public final boolean isInteger() { - return ordinal() <= DataBuffer.TYPE_INT; + return dataType <= DataBuffer.TYPE_INT; + } + + /** + * Returns {@code true} if the given sample model uses an integer type. + * Returns {@code false} if the type is a floating point type or in case + * of doubt (e.g. for {@link DataBuffer#TYPE_UNDEFINED}). + * + * @param sm the sample model, or {@code null}. + * @return whether the given sample model works on integer values. + * + * @since 1.5 + */ + public static boolean isInteger(final SampleModel sm) { + return (sm != null) && ImageUtilities.isIntegerType(sm.getDataType()); } /** @@ -299,7 +411,7 @@ public enum DataType { * without precision lost. This method returns: * * <ul> - * <li>{@link #DOUBLE} if this data type is {@link #DOUBLE} or {@link #INT}.</li> + * <li>{@link #DOUBLE} if this data type is {@link #DOUBLE}, {@link #INT} or {@link #UINT}.</li> * <li>{@link #FLOAT} for all other types.</li> * </ul> * @@ -310,8 +422,7 @@ public enum DataType { * which can store all values of this type without any lost. */ public final DataType toFloat() { - final int type = ordinal(); - return (type < DataBuffer.TYPE_INT || type == DataBuffer.TYPE_FLOAT) ? FLOAT : DOUBLE; + return (dataType < DataBuffer.TYPE_INT || dataType == DataBuffer.TYPE_FLOAT) ? FLOAT : DOUBLE; } /** @@ -322,7 +433,7 @@ public enum DataType { * @return one of the {@link DataBuffer} constants. */ public final int toDataBufferType() { - return ordinal(); + return dataType; } /** diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PixelIterator.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PixelIterator.java index cb5bd3c4cd..4155780ff0 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PixelIterator.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PixelIterator.java @@ -551,17 +551,17 @@ public class PixelIterator { } /** - * Returns the type used for storing data in the raster buffer. - * The data type identifies the {@link DataBuffer} subclass used for storage. + * Returns the type of sample values. This is usually the {@link DataBuffer} type, + * but may be a smaller type if many values are packed in each data buffer element. * - * @return the type used for storing data in the raster buffer. + * @return the type of sample values. * - * @see SampleModel#getDataType() + * @see DataType#forBands(SampleModel) * * @since 1.2 */ public DataType getDataType() { - return DataType.forDataBufferType(getSampleModel().getDataType()); + return DataType.forBands(getSampleModel()); } /** @@ -618,7 +618,7 @@ public class PixelIterator { final int size = model.getSampleSize(bandToDefine); long minimum = 0; long maximum = Numerics.bitmask(size) - 1; - if (!ImageUtilities.isUnsignedType(model)) { + if (!DataType.isUnsigned(model)) { maximum >>>= 1; // Convert unsigned range to signed range. minimum = ~maximum; } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ResampledImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ResampledImage.java index 2ecc0bb5dd..8d0b9d4624 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ResampledImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ResampledImage.java @@ -754,7 +754,7 @@ public class ResampledImage extends ComputedImage { for (int b=0; b<numBands; b++) { maxValues[b] = Numerics.bitmask(sm.getSampleSize(b)) - 1; } - if (!ImageUtilities.isUnsignedType(sm)) { + if (!DataType.isUnsigned(sm)) { for (int b=0; b<numBands; b++) { minValues[b] = ~(maxValues[b] >>>= 1); // Convert unsigned type to signed type range. } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/Transferer.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/Transferer.java index 6c953309cb..fc6a002d5a 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/Transferer.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/Transferer.java @@ -562,7 +562,7 @@ abstract class Transferer { * @return object to use for applying the operation. */ static Transferer create(final Raster source, final WritableRaster target, final Rectangle aoi) { - switch (ImageUtilities.getBandType(target.getSampleModel())) { + switch (DataType.forBands(target.getSampleModel()).toDataBufferType()) { case DataBuffer.TYPE_DOUBLE: { if (isDirect(target, aoi)) { return new DoubleToDirect(source, target, aoi); @@ -570,7 +570,7 @@ abstract class Transferer { break; } case DataBuffer.TYPE_FLOAT: { - switch (ImageUtilities.getBandType(source.getSampleModel())) { + switch (DataType.forBands(source.getSampleModel()).toDataBufferType()) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_USHORT: // TODO: consider using IntegerToDirect here. @@ -606,7 +606,7 @@ abstract class Transferer { * to the {@code float} type may lost precision digits. */ private static boolean singlePrecision(final Raster source) { - switch (ImageUtilities.getBandType(source.getSampleModel())) { + switch (DataType.forBands(source.getSampleModel()).toDataBufferType()) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelBuilder.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelBuilder.java index e970e8780a..89988e5d4d 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelBuilder.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelBuilder.java @@ -28,6 +28,7 @@ import java.awt.image.DataBuffer; import java.awt.image.SampleModel; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.ArraysExt; +import org.apache.sis.image.DataType; /** @@ -279,7 +280,7 @@ public final class ColorModelBuilder { * @throws IllegalArgumentException if any argument specified to the builder is invalid. */ public ColorModel createRGB(final SampleModel targetModel) { -check: if (ImageUtilities.isIntegerType(targetModel)) { +check: if (DataType.isInteger(targetModel)) { final int numBands = targetModel.getNumBands(); switch (numBands) { case 3: alphaBand = -1; break; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelFactory.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelFactory.java index e497dc2482..0e4322ef10 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelFactory.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorModelFactory.java @@ -579,9 +579,9 @@ public final class ColorModelFactory { } else { minimum = 0; maximum = 1; - if (ImageUtilities.isIntegerType(model)) { + if (DataType.isInteger(model)) { long max = Numerics.bitmask(model.getSampleSize(visibleBand)) - 1; - if (!ImageUtilities.isUnsignedType(model)) { + if (!DataType.isUnsigned(model)) { max >>>= 1; minimum = ~max; // Tild operator, not minus. } @@ -792,7 +792,7 @@ public final class ColorModelFactory { */ @Override public String toString() { - final StringBuilder buffer = new StringBuilder(Strings.toString(getClass(), + final var buffer = new StringBuilder(Strings.toString(getClass(), "dataType", DataType.forDataBufferType(dataType), "numBands", numBands, "visibleBand", visibleBand, "range", NumberRange.create(minimum, true, maximum, false))); final int n = (pieceStarts != null) ? pieceStarts.length : 0; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java index 2e83936957..f813f2a9da 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ColorScaleBuilder.java @@ -276,7 +276,7 @@ public final class ColorScaleBuilder { * If the model uses floating point values and there is no "no data" category, add one. * We force a "no data" category because floating point values may be NaN. */ - if (missingNodata && (model == null || !ImageUtilities.isIntegerType(model))) { + if (missingNodata && (model == null || !DataType.isInteger(model))) { final int count = entries.length; entries = Arrays.copyOf(entries, count + 1); entries[count] = new ColorsForRange(TRANSPARENT, @@ -303,10 +303,10 @@ public final class ColorScaleBuilder { */ public boolean initialize(final SampleModel source, final int band) { checkInitializationStatus(false); - if (ImageUtilities.isIntegerType(source)) { + if (DataType.isInteger(source)) { long minimum = 0; long maximum = Numerics.bitmask(source.getSampleSize(band)) - 1; - if (!ImageUtilities.isUnsignedType(source)) { + if (!DataType.isUnsigned(source)) { maximum >>>= 1; minimum = ~maximum; } @@ -700,7 +700,7 @@ reuse: if (source != null) { * @return a color model using a data type inferred from the given sample model. */ public ColorModel createColorModel(final SampleModel target, final int numBands, final int visibleBand) { - return createColorModel(DataType.forDataBufferType(ImageUtilities.getBandType(target)), numBands, visibleBand); + return createColorModel(DataType.forBands(target), numBands, visibleBand); } /** diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ImageUtilities.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ImageUtilities.java index c2e6dbd489..18f6eeea7b 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ImageUtilities.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/ImageUtilities.java @@ -30,13 +30,13 @@ import java.awt.image.RenderedImage; import java.awt.image.Raster; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.MultiPixelPackedSampleModel; import static java.lang.Math.abs; import static java.lang.Math.rint; import static java.lang.Math.floorDiv; import static java.lang.Math.toIntExact; import static java.lang.Math.multiplyFull; import org.apache.sis.feature.internal.Resources; +import org.apache.sis.image.DataType; import org.apache.sis.image.PlanarImage; import org.apache.sis.system.Modules; import org.apache.sis.util.Numbers; @@ -176,47 +176,6 @@ public final class ImageUtilities extends Static { return 0; } - /** - * Returns the data type of bands in rasters that use the given sample model. - * If each band is stored in its own {@link DataBuffer} element, then this method returns the same value - * as {@link SampleModel#getDataType()}. But if multiple sample values are packed in a single data element - * ({@link SinglePixelPackedSampleModel} or {@link MultiPixelPackedSampleModel}), then this method returns - * a smaller data type. As a general rule, this method returns the smallest data type capable to store all - * sample values with a {@link java.awt.image.BandedSampleModel}. - * - * @param sm the sample model for which to get the band type, or {@code null}. - * @return the data type, or {@link DataBuffer#TYPE_UNDEFINED} if unknown. - * - * @see #isIntegerType(int) - * @see #isUnsignedType(SampleModel) - */ - public static int getBandType(final SampleModel sm) { - if (sm == null) { - return DataBuffer.TYPE_UNDEFINED; - } - final int type = sm.getDataType(); - if (!isIntegerType(type)) { - return type; - } - final int maxBits = Math.min(DataBuffer.getDataTypeSize(type), Short.SIZE + 1); - int numBits = 0; - for (int i=sm.getNumBands(); --i >= 0;) { - final int n = sm.getSampleSize(i); - if (n > numBits) { - if (n >= maxBits) { - return type; - } - numBits = n; - } - } - final boolean isUnsignedType = (type <= DataBuffer.TYPE_USHORT) - || (sm instanceof SinglePixelPackedSampleModel) - || (sm instanceof MultiPixelPackedSampleModel); - - return isUnsignedType ? (numBits <= Byte.SIZE ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT) - : DataBuffer.TYPE_SHORT; - } - /** * Names of {@link DataBuffer} types. */ @@ -419,45 +378,6 @@ public final class ImageUtilities extends Static { return dataType >= DataBuffer.TYPE_BYTE && dataType <= DataBuffer.TYPE_INT; } - /** - * Returns {@code true} if the given sample model uses an integer type. - * Returns {@code false} if the type is a floating point type or in case - * of doubt (e.g. for {@link DataBuffer#TYPE_UNDEFINED}). - * - * @param sm the sample model, or {@code null}. - * @return whether the given sample model is for integer values. - */ - public static boolean isIntegerType(final SampleModel sm) { - return (sm != null) && isIntegerType(sm.getDataType()); - } - - /** - * Returns {@code true} if the type of sample values is an unsigned integer type. - * Returns {@code false} if the type is a floating point type or in case of doubt - * (e.g. for {@link DataBuffer#TYPE_UNDEFINED}). - * - * @param sm the sample model, or {@code null}. - * @return whether the given sample model provides unsigned sample values. - */ - public static boolean isUnsignedType(final SampleModel sm) { - if (sm != null) { - final int dataType = sm.getDataType(); - if (dataType >= DataBuffer.TYPE_BYTE) { - if (dataType <= DataBuffer.TYPE_USHORT) return true; - if (dataType <= DataBuffer.TYPE_INT) { - /* - * Typical case: 4 bands (ARGB) stored in a single data element of type `int`. - * The javadoc of those classes explain how to unpack the sample values, - * and the result is always unsigned. - */ - return (sm instanceof SinglePixelPackedSampleModel) || - (sm instanceof MultiPixelPackedSampleModel); - } - } - } - return false; - } - /** * Returns whether samples values stored using {@code source} model can be converted to {@code target} model * without data lost. This method verifies the number of bands and the size of data in each band. @@ -491,7 +411,7 @@ public final class ImageUtilities extends Static { * - Conversion from `int` to `float` can loose significant digits. * - Conversion from signed short to unsigned short (or conversely) can change values. */ - if (sourceIsInteger != targetIsInteger || isUnsignedType(source) != isUnsignedType(target)) { + if (sourceIsInteger != targetIsInteger || DataType.isUnsigned(source) != DataType.isUnsigned(target)) { return false; } } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/RasterFactory.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/RasterFactory.java index caa5b1edaf..1fb7e06a37 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/RasterFactory.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/RasterFactory.java @@ -211,9 +211,10 @@ public final class RasterFactory extends Static { */ public static Buffer createBuffer(final DataType dataType, final int capacity) { switch (dataType) { + case BYTE: return ByteBuffer .allocate(capacity); case USHORT: // Fallthrough case SHORT: return ShortBuffer .allocate(capacity); - case BYTE: return ByteBuffer .allocate(capacity); + case UINT: // Fallthrough case INT: return IntBuffer .allocate(capacity); case FLOAT: return FloatBuffer .allocate(capacity); case DOUBLE: return DoubleBuffer.allocate(capacity); @@ -268,10 +269,11 @@ public final class RasterFactory extends Static { final int numBands = data.length; final Object[] arrays; switch (dataType) { + case BYTE: arrays = new byte [numBands][]; break; case USHORT: // fall through case SHORT: arrays = new short [numBands][]; break; + case UINT: // fall through case INT: arrays = new int [numBands][]; break; - case BYTE: arrays = new byte [numBands][]; break; case FLOAT: arrays = new float [numBands][]; break; case DOUBLE: arrays = new double[numBands][]; break; default: throw new AssertionError(dataType); @@ -293,6 +295,7 @@ public final class RasterFactory extends Static { case BYTE: return new DataBufferByte ( (byte[][]) arrays, length, offsets); case SHORT: return new DataBufferShort ( (short[][]) arrays, length, offsets); case USHORT: return new DataBufferUShort( (short[][]) arrays, length, offsets); + case UINT: // Fall through case INT: return new DataBufferInt ( (int[][]) arrays, length, offsets); case FLOAT: return new DataBufferFloat ( (float[][]) arrays, length, offsets); case DOUBLE: return new DataBufferDouble((double[][]) arrays, length, offsets); diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/TilePlaceholder.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/TilePlaceholder.java index 66e60730df..65b4963e1f 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/TilePlaceholder.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/privy/TilePlaceholder.java @@ -34,6 +34,7 @@ import org.apache.sis.util.Workaround; import org.apache.sis.util.collection.WeakHashSet; import org.apache.sis.util.privy.Numerics; import org.apache.sis.system.ReferenceQueueConsumer; +import org.apache.sis.image.DataType; /** @@ -286,8 +287,8 @@ public class TilePlaceholder { WithCross(final RenderedImage image) { super(image.getSampleModel()); samples = new double[model.getNumBands()]; - if (ImageUtilities.isIntegerType(model)) { - final boolean isUnsigned = ImageUtilities.isUnsignedType(model); + if (DataType.isInteger(model)) { + final boolean isUnsigned = DataType.isUnsigned(model); for (int i=0; i<samples.length; i++) { int size = model.getSampleSize(i); if (!isUnsigned) size--; diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/DataTypeTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/DataTypeTest.java index ae429149a0..ae0728b148 100644 --- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/DataTypeTest.java +++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/DataTypeTest.java @@ -18,6 +18,9 @@ package org.apache.sis.image; import java.awt.image.DataBuffer; import java.awt.image.RasterFormatException; +import java.awt.image.SampleModel; +import java.awt.image.BandedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; // Test dependencies import org.junit.jupiter.api.Test; @@ -39,14 +42,15 @@ public final class DataTypeTest extends TestCase { } /** - * Verifies that {@link DataType} ordinal values match {@link DataBuffer} constant values. + * Verifies {@link DataType#toDataBufferType()}. */ @Test - public void verifyOrdinalValues() { + public void verifyToDataBufferType() { assertEquals(DataBuffer.TYPE_BYTE , DataType.BYTE .toDataBufferType()); assertEquals(DataBuffer.TYPE_USHORT, DataType.USHORT.toDataBufferType()); assertEquals(DataBuffer.TYPE_SHORT , DataType.SHORT .toDataBufferType()); assertEquals(DataBuffer.TYPE_INT , DataType.INT .toDataBufferType()); + assertEquals(DataBuffer.TYPE_INT , DataType.UINT .toDataBufferType()); assertEquals(DataBuffer.TYPE_FLOAT , DataType.FLOAT .toDataBufferType()); assertEquals(DataBuffer.TYPE_DOUBLE, DataType.DOUBLE.toDataBufferType()); } @@ -60,6 +64,7 @@ public final class DataTypeTest extends TestCase { assertEquals(Short .SIZE, DataType.USHORT.size()); assertEquals(Short .SIZE, DataType.SHORT .size()); assertEquals(Integer.SIZE, DataType.INT .size()); + assertEquals(Integer.SIZE, DataType.UINT .size()); assertEquals(Float .SIZE, DataType.FLOAT .size()); assertEquals(Double .SIZE, DataType.DOUBLE.size()); } @@ -73,6 +78,7 @@ public final class DataTypeTest extends TestCase { assertTrue (DataType.USHORT.isUnsigned()); assertFalse(DataType.SHORT .isUnsigned()); assertFalse(DataType.INT .isUnsigned()); + assertTrue (DataType.UINT .isUnsigned()); assertFalse(DataType.FLOAT .isUnsigned()); assertFalse(DataType.DOUBLE.isUnsigned()); } @@ -86,6 +92,7 @@ public final class DataTypeTest extends TestCase { assertTrue (DataType.USHORT.isInteger()); assertTrue (DataType.SHORT .isInteger()); assertTrue (DataType.INT .isInteger()); + assertTrue (DataType.UINT .isInteger()); assertFalse(DataType.FLOAT .isInteger()); assertFalse(DataType.DOUBLE.isInteger()); } @@ -99,6 +106,7 @@ public final class DataTypeTest extends TestCase { assertEquals(DataType.FLOAT, DataType.USHORT.toFloat()); assertEquals(DataType.FLOAT, DataType.SHORT .toFloat()); assertEquals(DataType.DOUBLE, DataType.INT .toFloat()); + assertEquals(DataType.DOUBLE, DataType.UINT .toFloat()); assertEquals(DataType.FLOAT, DataType.FLOAT .toFloat()); assertEquals(DataType.DOUBLE, DataType.DOUBLE.toFloat()); } @@ -113,6 +121,7 @@ public final class DataTypeTest extends TestCase { assertEquals(DataType.USHORT, DataType.forNumberOfBits(Short.SIZE, false, false)); assertEquals(DataType.SHORT, DataType.forNumberOfBits(Short.SIZE, false, true)); assertEquals(DataType.INT, DataType.forNumberOfBits(Integer.SIZE, false, true)); + assertEquals(DataType.UINT, DataType.forNumberOfBits(Integer.SIZE, false, false)); assertEquals(DataType.FLOAT, DataType.forNumberOfBits(Float.SIZE, true, true)); assertEquals(DataType.DOUBLE, DataType.forNumberOfBits(Double.SIZE, true, true)); @@ -121,4 +130,19 @@ public final class DataTypeTest extends TestCase { "Signed bytes should be invalid."); assertMessageContains(e, "signed", "true"); } + + /** + * Tests {@link DataType#forBands(SampleModel)}. + */ + @Test + public void testForBands() { + SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_INT, 1, 1, 3); + assertEquals(DataType.INT, DataType.forBands(sm)); + + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, 1, 1, new int[] {0x7F0000, 0x00FF00, 0x00007F}); + assertEquals(DataType.BYTE, DataType.forBands(sm)); + + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, 1, 1, new int[] {0x7F0000, 0x00FF80, 0x00007F}); + assertEquals(DataType.USHORT, DataType.forBands(sm)); + } } diff --git a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ImageUtilitiesTest.java b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ImageUtilitiesTest.java index 5e18396cbe..b8b00c3b7b 100644 --- a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ImageUtilitiesTest.java +++ b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/image/privy/ImageUtilitiesTest.java @@ -24,7 +24,6 @@ import java.awt.image.RenderedImage; import java.awt.image.BufferedImage; import java.awt.image.SampleModel; import java.awt.image.BandedSampleModel; -import java.awt.image.SinglePixelPackedSampleModel; import org.apache.sis.util.Numbers; import org.apache.sis.util.resources.Vocabulary; import static org.apache.sis.util.privy.Numerics.COMPARISON_THRESHOLD; @@ -70,21 +69,6 @@ public final class ImageUtilitiesTest extends TestCase { assertEquals(3, bounds.height); } - /** - * Tests {@link ImageUtilities#getBandType(SampleModel)}. - */ - @Test - public void testGetBandType() { - SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_INT, 1, 1, 3); - assertEquals(DataBuffer.TYPE_INT, ImageUtilities.getBandType(sm)); - - sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, 1, 1, new int[] {0x7F0000, 0x00FF00, 0x00007F}); - assertEquals(DataBuffer.TYPE_BYTE, ImageUtilities.getBandType(sm)); - - sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, 1, 1, new int[] {0x7F0000, 0x00FF80, 0x00007F}); - assertEquals(DataBuffer.TYPE_USHORT, ImageUtilities.getBandType(sm)); - } - /** * Tests {@link ImageUtilities#getDataTypeName(SampleModel)}. */ diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java index a041e4109c..75d66ebe5d 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/DataSubset.java @@ -546,7 +546,7 @@ class DataSubset extends TiledGridCoverage implements Localized { final int limit = bank.limit(); final int capacity = bank.capacity(); // Equals `this.capacity` except for packed sample model. if (limit != capacity) { - final Vector v = Vector.create(bank.limit(capacity), ImageUtilities.isUnsignedType(model)); + final Vector v = Vector.create(bank.limit(capacity), DataType.isUnsigned(model)); final Number f = fillValues[band]; /* * If all values are the same, we can delegate (indirectly) to an `Arrays.fill(…)` method. diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java index 8eae81ae1a..2249101ef6 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java @@ -1682,7 +1682,7 @@ final class ImageFileDirectory extends DataCube { case UNSIGNED: { if (bitsPerSample <= Byte .SIZE) return DataType.BYTE; if (bitsPerSample <= Short .SIZE) return DataType.USHORT; - if (bitsPerSample <= Integer.SIZE) return DataType.INT; + if (bitsPerSample <= Integer.SIZE) return DataType.UINT; break; } case FLOAT: { diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java index 495927a0e1..d657f0ab60 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/Writer.java @@ -43,7 +43,7 @@ import org.opengis.referencing.operation.TransformException; import org.apache.sis.image.ImageProcessor; import org.apache.sis.coverage.grid.GridGeometry; import org.apache.sis.coverage.grid.IncompleteGridGeometryException; -import org.apache.sis.image.privy.ImageUtilities; +import org.apache.sis.image.DataType; import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.DataStoreReferencingException; import org.apache.sis.storage.IncompatibleResourceException; @@ -363,7 +363,7 @@ final class Writer extends IOBase implements Flushable { { final SampleModel sm = image.exportable.getSampleModel(); Compression compression = store.getCompression().orElse(Compression.DEFLATE); - if (!ImageUtilities.isIntegerType(sm)) { + if (!DataType.isInteger(sm)) { compression = compression.withPredictor(PREDICTOR_NONE); } /* diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CopyFromBytes.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CopyFromBytes.java index 9e0565af5f..2d47dc5615 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CopyFromBytes.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/CopyFromBytes.java @@ -110,9 +110,10 @@ abstract class CopyFromBytes extends Inflater { throws UnsupportedEncodingException { switch (dataType) { + case BYTE: return new Bytes (input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); case USHORT: // Fall through case SHORT: return new Shorts (input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); - case BYTE: return new Bytes (input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); + case UINT: // Fall through case INT: return new Ints (input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); case FLOAT: return new Floats (input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); case DOUBLE: return new Doubles(input, chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/HorizontalPredictor.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/HorizontalPredictor.java index 40e6b87276..82e5a12c89 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/HorizontalPredictor.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/inflater/HorizontalPredictor.java @@ -105,9 +105,10 @@ abstract class HorizontalPredictor extends PredictorChannel { final int pixelStride, final int width) { switch (dataType) { - case USHORT: - case SHORT: return new Shorts (input, pixelStride, width); case BYTE: return new Bytes (input, pixelStride, width); + case USHORT: // Fall through + case SHORT: return new Shorts (input, pixelStride, width); + case UINT: // Fall through case INT: return new Integers(input, pixelStride, width); case FLOAT: return new Floats (input, pixelStride, width); case DOUBLE: return new Doubles (input, pixelStride, width); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/HorizontalPredictor.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/HorizontalPredictor.java index b6c174ec3b..2ec643fac2 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/HorizontalPredictor.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/HorizontalPredictor.java @@ -72,9 +72,10 @@ abstract class HorizontalPredictor extends PredictorChannel { final int pixelStride, final int scanlineStride) { switch (dataType) { - case USHORT: - case SHORT: return new Shorts (output, pixelStride, scanlineStride); case BYTE: return new Bytes (output, pixelStride, scanlineStride); + case USHORT: // Fall through + case SHORT: return new Shorts (output, pixelStride, scanlineStride); + case UINT: // Fall through case INT: return new Integers(output, pixelStride, scanlineStride); case FLOAT: return new Floats (output, pixelStride, scanlineStride); case DOUBLE: return new Doubles (output, pixelStride, scanlineStride); diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java index 0a9e64a32c..cc55c779ef 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/ReformattedImage.java @@ -27,6 +27,7 @@ import static javax.imageio.plugins.tiff.BaselineTIFFTagSet.*; import org.apache.sis.util.ArraysExt; import org.apache.sis.math.Statistics; import org.apache.sis.pending.jdk.JDK18; +import org.apache.sis.image.DataType; import org.apache.sis.image.ImageLayout; import org.apache.sis.image.PlanarImage; import org.apache.sis.image.ImageProcessor; @@ -208,8 +209,8 @@ found: if (property instanceof Statistics[]) { */ public int getSampleFormat() { final SampleModel sm = exportable.getSampleModel(); - if (ImageUtilities.isUnsignedType(sm)) return SAMPLE_FORMAT_UNSIGNED_INTEGER; - if (ImageUtilities.isIntegerType(sm)) return SAMPLE_FORMAT_SIGNED_INTEGER; + if (DataType.isUnsigned(sm)) return SAMPLE_FORMAT_UNSIGNED_INTEGER; + if (DataType.isInteger(sm)) return SAMPLE_FORMAT_SIGNED_INTEGER; return SAMPLE_FORMAT_FLOATING_POINT; } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java index 0292e39dbd..e38be04eb6 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/TileMatrix.java @@ -284,6 +284,7 @@ public final class TileMatrix { case BYTE: rect.write(compOutput, ((DataBufferByte) buffer).getData(b), offset, direct); break; case USHORT: rect.write(compOutput, ((DataBufferUShort) buffer).getData(b), offset); break; case SHORT: rect.write(compOutput, ((DataBufferShort) buffer).getData(b), offset); break; + case UINT: // Fall through case INT: rect.write(compOutput, ((DataBufferInt) buffer).getData(b), offset); break; case FLOAT: rect.write(compOutput, ((DataBufferFloat) buffer).getData(b), offset); break; case DOUBLE: rect.write(compOutput, ((DataBufferDouble) buffer).getData(b), offset); break; diff --git a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/DataType.java b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/DataType.java index f527627edc..d41f1d36a5 100644 --- a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/DataType.java +++ b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/DataType.java @@ -95,7 +95,7 @@ public enum DataType { * 32 bits unsigned integer (netCDF type 9). * Not available in netCDF classic format. */ - UINT(Numbers.INTEGER, Long.class, true, true, (byte) 4, org.apache.sis.image.DataType.INT), + UINT(Numbers.INTEGER, Long.class, true, true, (byte) 4, org.apache.sis.image.DataType.UINT), /** * 64 bits signed integer (netCDF type 10). diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java index f62048a07d..c71bc419bd 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java @@ -377,7 +377,7 @@ public abstract class TiledGridResource extends AbstractGridCoverageResource { */ protected Number[] getFillValues(final int[] bands) throws DataStoreException { final SampleModel model = getSampleModel(bands); - final var dataType = DataType.forDataBufferType(model.getDataType()); + final var dataType = DataType.forBands(model); IndexColorModel icm = null; check: if (dataType.isInteger()) { final ColorModel colors = getColorModel(bands); diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java index ba0a60df87..f3f1234c5c 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java @@ -42,9 +42,9 @@ import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.StorageConnector; import org.apache.sis.storage.base.PRJDataStore; import org.apache.sis.storage.base.MetadataBuilder; +import org.apache.sis.image.DataType; import org.apache.sis.image.privy.ColorModelFactory; import org.apache.sis.image.privy.ColorModelBuilder; -import org.apache.sis.image.privy.ImageUtilities; import org.apache.sis.image.privy.ObservableImage; import org.apache.sis.coverage.privy.RangeArgument; import org.apache.sis.util.CharSequences; @@ -339,9 +339,8 @@ abstract class RasterStore extends PRJDataStore implements GridCoverageResource * Build the sample dimensions and the color model. * Some minimum/maximum values will be used as fallback if no statistics were found. */ - final int dataType = sm.getDataType(); - final boolean isInteger = ImageUtilities.isIntegerType(dataType); - final boolean isUnsigned = isInteger && ImageUtilities.isUnsignedType(sm); + final boolean isInteger = DataType.isInteger(sm); + final boolean isUnsigned = isInteger && DataType.isUnsigned(sm); final boolean isRGB = isInteger && (bands.length == 3 || bands.length == 4); final var builder = new SampleDimension.Builder(); for (int band=0; band < bands.length; band++) { @@ -396,6 +395,7 @@ abstract class RasterStore extends PRJDataStore implements GridCoverageResource * The color file is optional and will be used if present. */ if (band == VISIBLE_BAND) { + final int dataType = sm.getDataType(); try { if (isRGB) { colorModel = new ColorModelBuilder().createRGB(sm); diff --git a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridView.java b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridView.java index 496cf9bec2..a2670c23d8 100644 --- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridView.java +++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridView.java @@ -45,7 +45,7 @@ import org.apache.sis.gui.internal.BackgroundThreads; import org.apache.sis.gui.internal.LogHandler; import org.apache.sis.gui.internal.Styles; import org.apache.sis.gui.internal.ExceptionReporter; -import org.apache.sis.image.privy.ImageUtilities; +import org.apache.sis.image.DataType; /** @@ -492,7 +492,7 @@ public class GridView extends Control { if (getBand() >= numBands) { ((BandProperty) bandProperty).setNoCheck(numBands - 1); } - cellFormat.dataTypeIsInteger = ImageUtilities.isIntegerType(sm); + cellFormat.dataTypeIsInteger = DataType.isInteger(sm); } cellFormat.configure(image, getBand()); }