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}