    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.imaging.formats.tiff;
    018
    019import java.util.stream.IntStream;
    020
    021import org.apache.commons.imaging.common.Allocator;
    022
    023/**
    024 * Provides a simple container for floating-point data. Some TIFF files are used to store floating-point data rather than images. This class is intended to
    025 * support access to those TIFF files.
    026 * <p>
    027 * <strong>Note:</strong> The getData() and getIntData() methods can return direct references to the internal arrays stored in instances of this class. Because
    028 * these are not safe copies of the data, an application that modified the arrays returned by these methods will change the content of the associated instance.
    029 * This approach is used for purposes of efficiency when dealing with very large TIFF images.
    030 * <p>
    031 * <strong>Data layout:</strong> The elements in the returned array are stored in row-major order. In cases where the data contains multiple samples per raster
    032 * cell (pixel), the data is organized into blocks of data one sample at a time. The first block contains width*height values for the first sample for each
    033 * cell, the second block contains width*height values for the second sample for each cell, etc. Thus, the array index for a particular value is computed as
    034 *
    035 * <pre>
    036 * index = y * width + x + iSample * width * height;
    037 * </pre>
    038 */
    039public final class TiffRasterDataFloat extends AbstractTiffRasterData {
    040
    041    private final float[] data;
    042
    043    /**
    044     * Constructs an instance allocating memory for the specified dimensions.
    045     *
    046     * @param width  a value of 1 or greater
    047     * @param height a value of 1 or greater
    048     */
    049    public TiffRasterDataFloat(final int width, final int height) {
    050        super(width, height, 1);
    051        data = Allocator.floatArray(nCells);
    052    }
    053
    054    /**
    055     * Constructs an instance allocating memory for the specified dimensions.
    056     *
    057     * @param width  a value of 1 or greater
    058     * @param height a value of 1 or greater
    059     * @param data   the data to be stored in the raster.
    060     */
    061    public TiffRasterDataFloat(final int width, final int height, final float[] data) {
    062        super(width, height, 1);
    063        if (data == null || data.length < nCells) {
    064            throw new IllegalArgumentException("Specified data does not contain sufficient elements");
    065        }
    066        this.data = data;
    067    }
    068
    069    /**
    070     * Constructs an instance allocating memory for the specified dimensions.
    071     *
    072     * @param width           a value of 1 or greater
    073     * @param height          a value of 1 or greater
    074     * @param samplesPerPixel a value of 1 or greater
    075     */
    076    public TiffRasterDataFloat(final int width, final int height, final int samplesPerPixel) {
    077        super(width, height, samplesPerPixel);
    078        data = Allocator.floatArray(nCells);
    079    }
    080
    081    /**
    082     * Constructs an instance allocating memory for the specified dimensions.
    083     *
    084     * @param width          a value of 1 or greater
    085     * @param height         a value of 1 or greater
    086     * @param samplesPerCell the number of samples per pixel
    087     * @param data           the data to be stored in the raster.
    088     */
    089    public TiffRasterDataFloat(final int width, final int height, final int samplesPerCell, final float[] data) {
    090        super(width, height, samplesPerCell);
    091        if (data == null || data.length < nCells) {
    092            throw new IllegalArgumentException("Specified data does not contain sufficient elements");
    093        }
    094        this.data = data;
    095    }
    096
    097    /**
    098     * Returns a reference to the data array stored in this instance. Note that the array returned is <strong>not</strong> a safe copy and that modifying it
    099     * directly affects the content of the instance. While this design approach carries some risk in terms of data security, it was chosen for reasons of
    100     * performance and memory conservation. TIFF images that contain floating-point data are often quite large. Sizes of 100 million raster cells are common.
    101     * Making a redundant copy of such a large in-memory object might exceed the resources available to a Java application.
    102     * <p>
    103     * See the class API documentation above for notes on accessing array elements.
    104     *
    105     * @return a direct reference to the data array stored in this instance.
    106     */
    107    @Override
    108    public float[] getData() {
    109        return data;
    110    }
    111
    112    /**
    113     * Gets the raster data type from the instance.
    114     *
    115     * @return a value of TiffRasterDataType&#46;FLOAT.
    116     */
    117    @Override
    118    public TiffRasterDataType getDataType() {
    119        return TiffRasterDataType.FLOAT;
    120    }
    121
    122    /**
    123     * Returns an array of integer approximations for the floating-point content stored as an array in this instance.
    124     * <p>
    125     * See the class API documentation above for notes on accessing array elements.
    126     *
    127     * @return the integer equivalents to the data content stored in this instance.
    128     */
    129    @Override
    130    public int[] getIntData() {
    131        return IntStream.range(0, nCells).map(i -> (int) data[i]).toArray();
    132    }
    133
    134    /**
    135     * Gets the value stored at the specified raster coordinates.
    136     *
    137     * @param x integer coordinate in the columnar direction
    138     * @param y integer coordinate in the row direction
    139     * @return the value stored at the specified location
    140     */
    141    @Override
    142    public int getIntValue(final int x, final int y) {
    143        return (int) data[checkCoordinatesAndComputeIndex(x, y, 0)];
    144    }
    145
    146    /**
    147     * Gets the value stored at the specified raster coordinates.
    148     *
    149     * @param x integer coordinate in the columnar direction
    150     * @param y integer coordinate in the row direction
    151     * @param i integer sample index (for data sets giving multiple samples per raster cell).
    152     * @return the value stored at the specified location
    153     */
    154    @Override
    155    public int getIntValue(final int x, final int y, final int i) {
    156        return (int) data[checkCoordinatesAndComputeIndex(x, y, 0)];
    157    }
    158
    159    /**
    160     * Tabulates simple statistics for the raster and returns an instance containing general metadata.
    161     *
    162     * @return a valid instance containing a safe copy of the current simple statistics for the raster.
    163     */
    164    @Override
    165    public TiffRasterStatistics getSimpleStatistics() {
    166        return new TiffRasterStatistics(this, Float.NaN);
    167    }
    168
    169    /**
    170     * Tabulates simple statistics for the raster excluding the specified value and returns an instance containing general metadata.
    171     *
    172     * @param valueToExclude exclude samples with this specified value.
    173     * @return a valid instance.
    174     */
    175    @Override
    176    public TiffRasterStatistics getSimpleStatistics(final float valueToExclude) {
    177        return new TiffRasterStatistics(this, valueToExclude);
    178    }
    179
    180    /**
    181     * Gets the value stored at the specified raster coordinates.
    182     *
    183     * @param x integer coordinate in the columnar direction
    184     * @param y integer coordinate in the row direction
    185     * @return the value stored at the specified location; potentially a Float&#46;NaN.
    186     */
    187    @Override
    188    public float getValue(final int x, final int y) {
    189        return data[checkCoordinatesAndComputeIndex(x, y, 0)];
    190    }
    191
    192    /**
    193     * Gets the value stored at the specified raster coordinates.
    194     *
    195     * @param x integer coordinate in the columnar direction
    196     * @param y integer coordinate in the row direction
    197     * @param i integer sample index (for data sets giving multiple samples per raster cell).
    198     * @return the value stored at the specified location; potentially a Float&#46;NaN.
    199     */
    200    @Override
    201    public float getValue(final int x, final int y, final int i) {
    202        return data[checkCoordinatesAndComputeIndex(x, y, i)];
    203    }
    204
    205    /**
    206     * Sets the value stored at the specified raster coordinates.
    207     *
    208     * @param x     integer coordinate in the columnar direction
    209     * @param y     integer coordinate in the row direction
    210     * @param value the value to be stored at the specified location
    211     */
    212    @Override
    213    public void setIntValue(final int x, final int y, final int value) {
    214        data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
    215    }
    216
    217    /**
    218     * Sets the value stored at the specified raster coordinates.
    219     *
    220     * @param x     integer coordinate in the columnar direction
    221     * @param y     integer coordinate in the row direction
    222     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
    223     * @param value the value to be stored at the specified location
    224     */
    225    @Override
    226    public void setIntValue(final int x, final int y, final int i, final int value) {
    227        data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
    228    }
    229
    230    /**
    231     * Sets the value stored at the specified raster coordinates.
    232     *
    233     * @param x     integer coordinate in the columnar direction
    234     * @param y     integer coordinate in the row direction
    235     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
    236     */
    237    @Override
    238    public void setValue(final int x, final int y, final float value) {
    239        data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
    240    }
    241
    242    /**
    243     * Sets the value stored at the specified raster coordinates.
    244     *
    245     * @param x     integer coordinate in the columnar direction
    246     * @param y     integer coordinate in the row direction
    247     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
    248     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
    249     */
    250    @Override
    251    public void setValue(final int x, final int y, final int i, final float value) {
    252        data[checkCoordinatesAndComputeIndex(x, y, i)] = value;
    253    }
    254
    255}