Search in sources :

Example 1 with DataType

use of org.apache.sis.image.DataType in project sis by apache.

the class ImageRenderer method setData.

/**
 * Sets the data as vectors. The number of vectors must be equal to the {@linkplain #getNumBands() expected number of bands}.
 * All vectors must be backed by arrays (indirectly, through {@linkplain Vector#buffer() buffers} backed by arrays) and have
 * the same {@linkplain Vector#size() size}.
 * This method wraps the underlying arrays of a primitive type into a Java2D buffer; data are not copied.
 *
 * <p><b>Implementation note:</b> the NIO buffers are set by a call to {@link #setData(DataType, Buffer...)},
 * which can be overridden by subclasses if desired.</p>
 *
 * @param  data  the vectors wrapping arrays of primitive type.
 * @throws NullArgumentException if {@code data} is null or one of {@code data} element is null.
 * @throws MismatchedCoverageRangeException if the number of specified vectors is not equal to the number of bands.
 * @throws UnsupportedOperationException if a vector is not backed by an accessible array or is read-only.
 * @throws RasterFormatException if vectors do not have the same size.
 * @throws ArithmeticException if a buffer position overflows the 32 bits integer capacity.
 */
public void setData(final Vector... data) {
    ArgumentChecks.ensureNonNull("data", data);
    ensureExpectedBandCount(data.length, true);
    final Buffer[] buffers = new Buffer[data.length];
    DataType dataType = null;
    for (int i = 0; i < data.length; i++) {
        final Vector v = data[i];
        ArgumentChecks.ensureNonNullElement("data", i, v);
        final DataType t = DataType.forPrimitiveType(v.getElementType(), v.isUnsigned());
        if (dataType == null) {
            dataType = t;
        } else if (dataType != t) {
            throw new RasterFormatException(Resources.format(Resources.Keys.MismatchedDataType));
        }
        buffers[i] = v.buffer().orElseThrow(UnsupportedOperationException::new);
    }
    setData(dataType, buffers);
}
Also used : Buffer(java.nio.Buffer) DataBuffer(java.awt.image.DataBuffer) DataType(org.apache.sis.image.DataType) Vector(org.apache.sis.math.Vector) Point(java.awt.Point) RasterFormatException(java.awt.image.RasterFormatException)

Example 2 with DataType

use of org.apache.sis.image.DataType in project sis by apache.

the class ConvertedGridCoverage method getBandType.

/**
 * Returns the data type for range of values of given sample dimensions.
 * This data type applies to each band, not to a packed sample model
 * (e.g. we assume no packing of 4 byte values in a single 32-bits integer).
 *
 * @param  targets    the sample dimensions for which to get the data type.
 * @param  converted  whether the image will hold converted or packed values.
 * @param  source     if the type can not be determined, coverage from which to inherit the type as a fallback.
 * @return the data type (never null).
 *
 * @see GridCoverage#getBandType()
 */
static DataType getBandType(final List<SampleDimension> targets, final boolean converted, final GridCoverage source) {
    NumberRange<?> union = null;
    boolean allowsNaN = false;
    for (final SampleDimension dimension : targets) {
        final Optional<NumberRange<?>> c = dimension.getSampleRange();
        if (c.isPresent()) {
            final NumberRange<?> range = c.get();
            if (union == null) {
                union = range;
            } else {
                /*
                     * We do not want unit conversions for this union, because the union is used
                     * only for determining a data type having the capacity to store the values.
                     * The physical meaning of those values is not relevant here.
                     */
                if (union instanceof MeasurementRange<?>) {
                    union = new NumberRange<>(union);
                }
                union = union.unionAny(range);
            }
        }
        if (!allowsNaN)
            allowsNaN = dimension.allowsNaN();
    }
    if (union == null) {
        return source.getBandType();
    }
    DataType type = DataType.forRange(union, !converted);
    if (allowsNaN) {
        type = type.toFloat();
    }
    return type;
}
Also used : NumberRange(org.apache.sis.measure.NumberRange) MeasurementRange(org.apache.sis.measure.MeasurementRange) DataType(org.apache.sis.image.DataType) SampleDimension(org.apache.sis.coverage.SampleDimension)

Example 3 with DataType

use of org.apache.sis.image.DataType in project sis by apache.

the class DataSubset method readSlice.

/**
 * Reads a two-dimensional slice of the data cube from the given input channel. This method is usually
 * invoked for reading the tile in full, in which case the {@code lower} argument is (0,0) and the
 * {@code upper} argument is the tile size. But those arguments may identify a smaller region if the
 * {@link DataSubset} contains only one (potentially large) tile.
 *
 * <p>The length of {@code lower}, {@code upper} and {@code subsampling} arrays shall be 2.</p>
 *
 * <h4>Default implementation</h4>
 * The default implementation in this base class assumes uncompressed data without band subset.
 * Subsampling on the <var>X</var> axis is not supported if the image has interleaved pixels.
 * Packed pixels (é.g. bilevel images with 8 pixels per byte) are not supported.
 * Those restrictions are verified by {@link DataCube#canReadDirect(TiledGridResource.Subset)}.
 * Subclasses must override for handling decompression or for resolving above-cited limitations.
 *
 * @todo It is possible to relax a little bit some restrictions. If the tile width is a divisor
 *       of the sample size, we could round {@code lower[0]} and {@code upper[0]} to a multiple
 *       of {@code sampleSize}. We would need to adjust the coordinates of returned image accordingly.
 *       This adjustment need to be done by the caller.
 *
 * @param  offsets      position in the channel where tile data begins, one value per bank.
 * @param  byteCounts   number of bytes for the compressed tile data, one value per bank.
 * @param  lower        (<var>x</var>, <var>y</var>) coordinates of the first pixel to read relative to the tile.
 * @param  upper        (<var>x</var>, <var>y</var>) coordinates after the last pixel to read relative to the tile.
 * @param  subsampling  (<var>sx</var>, <var>sy</var>) subsampling factors.
 * @param  location     pixel coordinates in the upper-left corner of the tile to return.
 * @return a single tile decoded from the GeoTIFF file.
 * @throws IOException if an I/O error occurred.
 * @throws DataStoreException if a logical error occurred.
 * @throws RuntimeException if the Java2D image can not be created for another reason
 *         (too many exception types to list them all).
 *
 * @see DataCube#canReadDirect(TiledGridResource.Subset)
 */
Raster readSlice(final long[] offsets, final long[] byteCounts, final long[] lower, final long[] upper, final int[] subsampling, final Point location) throws IOException, DataStoreException {
    final DataType type = getDataType();
    // Assumed same as `SampleModel.getSampleSize(…)` by pre-conditions.
    final int sampleSize = type.size();
    final long width = subtractExact(upper[X_DIMENSION], lower[X_DIMENSION]);
    final long height = subtractExact(upper[Y_DIMENSION], lower[Y_DIMENSION]);
    /*
         * The number of bytes to read should not be greater than `byteCount`. It may be smaller however if only
         * a subregion is read. Note that the `length` value may be different than `capacity` if the tile to read
         * is smaller than the "standard" tile size of the image. It happens often when reading the last strip.
         * This length is used only for verification purpose so it does not need to be exact.
         */
    final long length = ceilDiv(width * height * sourcePixelStride * sampleSize, Byte.SIZE);
    final long[] size = new long[] { multiplyFull(sourcePixelStride, getTileSize(X_DIMENSION)), getTileSize(Y_DIMENSION) };
    /*
         * If we use an interleaved sample model, each "element" from `HyperRectangleReader` perspective is actually a
         * group of `sourcePixelStride` values. Note that in such case, we can not handle subsampling on the first axis.
         * Such case should be handled by the `CompressedSubset` subclass instead, even if there is no compression.
         */
    assert sourcePixelStride == 1 || subsampling[X_DIMENSION] == 1;
    lower[X_DIMENSION] *= sourcePixelStride;
    upper[X_DIMENSION] *= sourcePixelStride;
    /*
         * Read each plane ("banks" in Java2D terminology). Note that a single bank contains all bands
         * in the interleaved sample model case. This block assumes that each bank element contains
         * exactly one sample value (verified by assertion), as documented in the Javadoc of this method.
         * If that assumption was not true, we would have to adjust `capacity`, `lower[0]` and `upper[0]`
         * (we may do that as an optimization in a future version).
         */
    final HyperRectangleReader hr = new HyperRectangleReader(ImageUtilities.toNumberEnum(type.toDataBufferType()), input());
    final Region region = new Region(size, lower, upper, subsampling);
    final Buffer[] banks = new Buffer[numBanks];
    for (int b = 0; b < numBanks; b++) {
        if (b < byteCounts.length && length > byteCounts[b]) {
            throw new DataStoreContentException(source.reader.resources().getString(Resources.Keys.UnexpectedTileLength_2, length, byteCounts[b]));
        }
        hr.setOrigin(offsets[b]);
        // See above comment.
        assert model.getSampleSize(b) == sampleSize;
        final Buffer bank = hr.readAsBuffer(region, getBankCapacity(1));
        fillRemainingRows(bank);
        banks[b] = bank;
    }
    final DataBuffer buffer = RasterFactory.wrap(type, banks);
    return Raster.createWritableRaster(model, buffer, location);
}
Also used : Buffer(java.nio.Buffer) DataBuffer(java.awt.image.DataBuffer) DataStoreContentException(org.apache.sis.storage.DataStoreContentException) DataType(org.apache.sis.image.DataType) Region(org.apache.sis.internal.storage.io.Region) Point(java.awt.Point) HyperRectangleReader(org.apache.sis.internal.storage.io.HyperRectangleReader) DataBuffer(java.awt.image.DataBuffer)

Example 4 with DataType

use of org.apache.sis.image.DataType in project sis by apache.

the class CompressedSubset method readSlice.

/**
 * Reads a two-dimensional slice of the data cube from the given input channel.
 *
 * @param  offsets      position in the channel where tile data begins, one value per bank.
 * @param  byteCounts   number of bytes for the compressed tile data, one value per bank.
 * @param  lower        (<var>x</var>, <var>y</var>) coordinates of the first pixel to read relative to the tile.
 * @param  upper        (<var>x</var>, <var>y</var>) coordinates after the last pixel to read relative to the tile.
 * @param  subsampling  (<var>sx</var>, <var>sy</var>) subsampling factors.
 * @param  location     pixel coordinates in the upper-left corner of the tile to return.
 * @return a single tile decoded from the GeoTIFF file.
 */
@Override
Raster readSlice(final long[] offsets, final long[] byteCounts, final long[] lower, final long[] upper, final int[] subsampling, final Point location) throws IOException, DataStoreException {
    final DataType dataType = getDataType();
    final int width = pixelCount(lower, upper, subsampling, X_DIMENSION);
    final int height = pixelCount(lower, upper, subsampling, Y_DIMENSION);
    final int chunksPerRow = width * (targetPixelStride / samplesPerChunk);
    final int betweenRows = subsampling[1] - 1;
    final long head = beforeFirstBand + sourcePixelStride * (lower[X_DIMENSION]);
    final long tail = afterLastBand - sourcePixelStride * (lower[X_DIMENSION] + (width - 1) * subsampling[X_DIMENSION]);
    /*
         * `head` and `tail` are the number of sample values to skip at the beginning and end of each row.
         * `betweenPixels` is the number of sample values to skip between each pixel, but the actual skips
         * are more complicated if only a subset of the bands are read. The actual number of sample values
         * to skip between "chunks" is detailed by `skipAfterChunks`.
         *
         * `pixelsPerElement` below is a factor for converting a count of pixels to a count of primitive elements
         * in the bank. The `pixelsPerElement` factor is usually 1, except when more than one pixel is packed in
         * each single primitive type (e.g. 8 bits per byte in bilevel image). The `head` needs to be a multiple
         * of `pixelsPerElement`; this restriction is documented in `Inflater.skip(long)` and should have been
         * verified by `TiledGridResource`.
         */
    // Always ≥ 1 and usually = 1.
    final int pixelsPerElement = getPixelsPerElement();
    assert (head % pixelsPerElement) == 0 : head;
    if (inflater == null) {
        inflater = Inflater.create(this, input(), source.getCompression(), source.getPredictor(), sourcePixelStride, getTileSize(X_DIMENSION), chunksPerRow, samplesPerChunk, skipAfterChunks, pixelsPerElement, dataType);
    }
    final Inflater inflater = this.inflater;
    final int capacity = getBankCapacity(pixelsPerElement);
    final Buffer[] banks = new Buffer[numBanks];
    for (int b = 0; b < numBanks; b++) {
        /*
             * Prepare the object which will perform the actual decompression row-by-row,
             * optionally skipping chunks if a subsampling is applied.
             */
        final Buffer bank = RasterFactory.createBuffer(dataType, capacity);
        inflater.setInputOutput(offsets[b], byteCounts[b], bank);
        /*
             * At this point, `inflater` is a data input doing decompression eventually followed
             * by the mathematical operation identified by `predictor`.
             */
        for (long y = lower[1]; --y >= 0; ) {
            // `skip(…)` may round to next element boundary.
            inflater.skip(scanlineStride);
        }
        for (int y = height; --y > 0; ) {
            // (height - 1) iterations.
            inflater.skip(head);
            inflater.uncompressRow();
            inflater.skip(tail);
            for (int j = betweenRows; --j >= 0; ) {
                inflater.skip(scanlineStride);
            }
        }
        // Last iteration without the trailing `skip(…)` calls.
        inflater.skip(head);
        inflater.uncompressRow();
        fillRemainingRows(bank.flip());
        banks[b] = bank;
    }
    return Raster.createWritableRaster(model, RasterFactory.wrap(dataType, banks), location);
}
Also used : Buffer(java.nio.Buffer) DataType(org.apache.sis.image.DataType) Inflater(org.apache.sis.internal.storage.inflater.Inflater) Point(java.awt.Point)

Aggregations

DataType (org.apache.sis.image.DataType)4 Point (java.awt.Point)3 Buffer (java.nio.Buffer)3 DataBuffer (java.awt.image.DataBuffer)2 RasterFormatException (java.awt.image.RasterFormatException)1 SampleDimension (org.apache.sis.coverage.SampleDimension)1 Inflater (org.apache.sis.internal.storage.inflater.Inflater)1 HyperRectangleReader (org.apache.sis.internal.storage.io.HyperRectangleReader)1 Region (org.apache.sis.internal.storage.io.Region)1 Vector (org.apache.sis.math.Vector)1 MeasurementRange (org.apache.sis.measure.MeasurementRange)1 NumberRange (org.apache.sis.measure.NumberRange)1 DataStoreContentException (org.apache.sis.storage.DataStoreContentException)1