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