    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 org.apache.commons.imaging.common.Allocator;
    020
    021/**
    022 * 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
    023 * support access to those TIFF files.
    024 * <p>
    025 * <strong>Note:</strong> The getData() and getIntData() methods can return direct references to the internal arrays stored in instances of this class. Because
    026 * 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.
    027 * This approach is used for purposes of efficiency when dealing with very large TIFF images.
    028 * <p>
    029 * <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
    030 * 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
    031 * 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
    032 *
    033 * <pre>
    034 * index = y * width + x + iSample * width * height;
    035 * </pre>
    036 */
    037public final class TiffRasterDataInt extends AbstractTiffRasterData {
    038
    039    private final int[] data;
    040
    041    /**
    042     * Constructs an instance allocating memory for the specified dimensions.
    043     *
    044     * @param width  a value of 1 or greater
    045     * @param height a value of 1 or greater
    046     */
    047    public TiffRasterDataInt(final int width, final int height) {
    048        super(width, height, 1);
    049        data = Allocator.intArray(nCells);
    050    }
    051
    052    /**
    053     * Constructs an instance allocating memory for the specified dimensions.
    054     *
    055     * @param width           a value of 1 or greater
    056     * @param height          a value of 1 or greater
    057     * @param samplesPerPixel a value of 1 or greater
    058     */
    059    public TiffRasterDataInt(final int width, final int height, final int samplesPerPixel) {
    060        super(width, height, samplesPerPixel);
    061        data = Allocator.intArray(nCells);
    062    }
    063
    064    /**
    065     * Constructs an instance allocating memory for the specified dimensions.
    066     *
    067     * @param width           a value of 1 or greater
    068     * @param height          a value of 1 or greater
    069     * @param samplesPerPixel a value of 1 or greater
    070     * @param data            the data to be stored in the raster.
    071     */
    072    public TiffRasterDataInt(final int width, final int height, final int samplesPerPixel, final int[] data) {
    073        super(width, height, samplesPerPixel);
    074        if (data == null || data.length < nCells) {
    075            throw new IllegalArgumentException("Specified data does not contain sufficient elements");
    076        }
    077        this.data = data;
    078    }
    079
    080    /**
    081     * Constructs an instance allocating memory for the specified dimensions.
    082     *
    083     * @param width  a value of 1 or greater
    084     * @param height a value of 1 or greater
    085     * @param data   the data to be stored in the raster.
    086     */
    087    public TiffRasterDataInt(final int width, final int height, final int[] data) {
    088        super(width, height, 1);
    089        if (data == null || data.length < nCells) {
    090            throw new IllegalArgumentException("Specified data does not contain sufficient elements");
    091        }
    092        this.data = data;
    093    }
    094
    095    /**
    096     * Returns an array of floating-point equivalents to the integer values stored in this instance. To do so, a float array is allocated and each integer value
    097     * in the source data is cast to a float.
    098     *
    099     * @return the floating-point equivalents of the content stored in this instance.
    100     */
    101    @Override
    102    public float[] getData() {
    103        final float[] result = Allocator.floatArray(nCells);
    104        for (int i = 0; i < nCells; i++) {
    105            result[i] = data[i];
    106        }
    107        return result;
    108    }
    109
    110    /**
    111     * Gets the raster data type from the instance.
    112     *
    113     * @return a value of TiffRasterDataType&#46;FLOAT.
    114     */
    115    @Override
    116    public TiffRasterDataType getDataType() {
    117        return TiffRasterDataType.INTEGER;
    118    }
    119
    120    /**
    121     * 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
    122     * 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
    123     * performance and memory conservation. TIFF images that contain floating-point data are often quite large. Sizes of 100 million raster cells are common.
    124     * Making a redundant copy of such a large in-memory object might exceed the resources available to a Java application.
    125     *
    126     * @return a direct reference to the data array stored in this instance.
    127     */
    128    @Override
    129    public int[] getIntData() {
    130        return data;
    131    }
    132
    133    /**
    134     * Gets the value stored at the specified raster coordinates.
    135     *
    136     * @param x integer coordinate in the columnar direction
    137     * @param y integer coordinate in the row direction
    138     * @return the value stored at the specified location
    139     */
    140    @Override
    141    public int getIntValue(final int x, final int y) {
    142        return data[checkCoordinatesAndComputeIndex(x, y, 0)];
    143    }
    144
    145    /**
    146     * Gets the value stored at the specified raster coordinates.
    147     *
    148     * @param x integer coordinate in the columnar direction
    149     * @param y integer coordinate in the row direction
    150     * @param i integer sample index (for data sets giving multiple samples per raster cell).
    151     * @return the value stored at the specified location
    152     */
    153    @Override
    154    public int getIntValue(final int x, final int y, final int i) {
    155        return data[checkCoordinatesAndComputeIndex(x, y, i)];
    156    }
    157
    158    /**
    159     * Tabulates simple statistics for the raster and returns an instance containing general metadata.
    160     *
    161     * @return a valid instance containing a safe copy of the current simple statistics for the raster.
    162     */
    163    @Override
    164    public TiffRasterStatistics getSimpleStatistics() {
    165        return new TiffRasterStatistics(this, Float.NaN);
    166    }
    167
    168    /**
    169     * Tabulates simple statistics for the raster excluding the specified value and returns an instance containing general metadata.
    170     *
    171     * @param valueToExclude exclude samples with this specified value.
    172     * @return a valid instance.
    173     */
    174    @Override
    175    public TiffRasterStatistics getSimpleStatistics(final float valueToExclude) {
    176        return new TiffRasterStatistics(this, valueToExclude);
    177    }
    178
    179    /**
    180     * Gets the value stored at the specified raster coordinates.
    181     *
    182     * @param x integer coordinate in the columnar direction
    183     * @param y integer coordinate in the row direction
    184     * @return the value stored at the specified location; potentially a Float&#46;NaN.
    185     */
    186    @Override
    187    public float getValue(final int x, final int y) {
    188        return data[checkCoordinatesAndComputeIndex(x, y, 0)];
    189    }
    190
    191    /**
    192     * Gets the value stored at the specified raster coordinates.
    193     *
    194     * @param x integer coordinate in the columnar direction
    195     * @param y integer coordinate in the row direction
    196     * @param i integer sample index (for data sets giving multiple samples per raster cell.
    197     * @return the value stored at the specified location; potentially a Float&#46;NaN.
    198     */
    199    @Override
    200    public float getValue(final int x, final int y, final int i) {
    201        return data[checkCoordinatesAndComputeIndex(x, y, i)];
    202    }
    203
    204    /**
    205     * Sets the value stored at the specified raster coordinates.
    206     *
    207     * @param x     integer coordinate in the columnar direction
    208     * @param y     integer coordinate in the row direction
    209     * @param value the value to be stored at the specified location
    210     */
    211    @Override
    212    public void setIntValue(final int x, final int y, final int value) {
    213        data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
    214    }
    215
    216    /**
    217     * Sets the value stored at the specified raster coordinates.
    218     *
    219     * @param x     integer coordinate in the columnar direction
    220     * @param y     integer coordinate in the row direction
    221     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
    222     * @param value the value to be stored at the specified location
    223     */
    224    @Override
    225    public void setIntValue(final int x, final int y, final int i, final int value) {
    226        data[checkCoordinatesAndComputeIndex(x, y, i)] = value;
    227    }
    228
    229    /**
    230     * Sets the value stored at the specified raster coordinates.
    231     *
    232     * @param x     integer coordinate in the columnar direction
    233     * @param y     integer coordinate in the row direction
    234     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
    235     */
    236    @Override
    237    public void setValue(final int x, final int y, final float value) {
    238        data[checkCoordinatesAndComputeIndex(x, y, 0)] = (int) value;
    239    }
    240
    241    /**
    242     * Sets the value stored at the specified raster coordinates.
    243     *
    244     * @param x     integer coordinate in the columnar direction
    245     * @param y     integer coordinate in the row direction
    246     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
    247     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
    248     */
    249    @Override
    250    public void setValue(final int x, final int y, final int i, final float value) {
    251        data[checkCoordinatesAndComputeIndex(x, y, i)] = (int) value;
    252    }
    253}