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 class TiffRasterDataInt extends TiffRasterData {
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
075        if (data == null || data.length < nCells) {
076            throw new IllegalArgumentException("Specified data does not contain sufficient elements");
077        }
078        this.data = data;
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 data   the data to be stored in the raster.
087     */
088    public TiffRasterDataInt(final int width, final int height, final int[] data) {
089        super(width, height, 1);
090
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 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
099     * in the source data is cast to a float.
100     *
101     * @return the floating-point equivalents of the content stored in this instance.
102     */
103    @Override
104    public float[] getData() {
105        final float[] result = Allocator.floatArray(nCells);
106        for (int i = 0; i < nCells; i++) {
107            result[i] = data[i];
108        }
109        return result;
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.INTEGER;
120    }
121
122    /**
123     * 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
124     * 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
125     * performance and memory conservation. TIFF images that contain floating-point data are often quite large. Sizes of 100 million raster cells are common.
126     * Making a redundant copy of such a large in-memory object might exceed the resources available to a Java application.
127     *
128     * @return a direct reference to the data array stored in this instance.
129     */
130    @Override
131    public int[] getIntData() {
132        return data;
133    }
134
135    /**
136     * Gets the value stored at the specified raster coordinates.
137     *
138     * @param x integer coordinate in the columnar direction
139     * @param y integer coordinate in the row direction
140     * @return the value stored at the specified location
141     */
142    @Override
143    public int getIntValue(final int x, final int y) {
144        final int index = checkCoordinatesAndComputeIndex(x, y, 0);
145        return data[index];
146    }
147
148    /**
149     * Gets the value stored at the specified raster coordinates.
150     *
151     * @param x integer coordinate in the columnar direction
152     * @param y integer coordinate in the row direction
153     * @param i integer sample index (for data sets giving multiple samples per raster cell).
154     * @return the value stored at the specified location
155     */
156    @Override
157    public int getIntValue(final int x, final int y, final int i) {
158        final int index = checkCoordinatesAndComputeIndex(x, y, i);
159        return data[index];
160    }
161
162    /**
163     * Tabulates simple statistics for the raster and returns an instance containing general metadata.
164     *
165     * @return a valid instance containing a safe copy of the current simple statistics for the raster.
166     */
167    @Override
168    public TiffRasterStatistics getSimpleStatistics() {
169        return new TiffRasterStatistics(this, Float.NaN);
170    }
171
172    /**
173     * Tabulates simple statistics for the raster excluding the specified value and returns an instance containing general metadata.
174     *
175     * @param valueToExclude exclude samples with this specified value.
176     * @return a valid instance.
177     */
178    @Override
179    public TiffRasterStatistics getSimpleStatistics(final float valueToExclude) {
180        return new TiffRasterStatistics(this, valueToExclude);
181    }
182
183    /**
184     * Gets the value stored at the specified raster coordinates.
185     *
186     * @param x integer coordinate in the columnar direction
187     * @param y integer coordinate in the row direction
188     * @return the value stored at the specified location; potentially a Float&#46;NaN.
189     */
190    @Override
191    public float getValue(final int x, final int y) {
192        final int index = checkCoordinatesAndComputeIndex(x, y, 0);
193        return data[index];
194    }
195
196    /**
197     * Gets the value stored at the specified raster coordinates.
198     *
199     * @param x integer coordinate in the columnar direction
200     * @param y integer coordinate in the row direction
201     * @param i integer sample index (for data sets giving multiple samples per raster cell.
202     * @return the value stored at the specified location; potentially a Float&#46;NaN.
203     */
204    @Override
205    public float getValue(final int x, final int y, final int i) {
206        final int index = checkCoordinatesAndComputeIndex(x, y, i);
207        return data[index];
208    }
209
210    /**
211     * Sets the value stored at the specified raster coordinates.
212     *
213     * @param x     integer coordinate in the columnar direction
214     * @param y     integer coordinate in the row direction
215     * @param value the value to be stored at the specified location
216     */
217    @Override
218    public void setIntValue(final int x, final int y, final int value) {
219        final int index = checkCoordinatesAndComputeIndex(x, y, 0);
220        data[index] = value;
221    }
222
223    /**
224     * Sets the value stored at the specified raster coordinates.
225     *
226     * @param x     integer coordinate in the columnar direction
227     * @param y     integer coordinate in the row direction
228     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
229     * @param value the value to be stored at the specified location
230     */
231    @Override
232    public void setIntValue(final int x, final int y, final int i, final int value) {
233        final int index = checkCoordinatesAndComputeIndex(x, y, i);
234        data[index] = value;
235    }
236
237    /**
238     * Sets the value stored at the specified raster coordinates.
239     *
240     * @param x     integer coordinate in the columnar direction
241     * @param y     integer coordinate in the row direction
242     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
243     */
244    @Override
245    public void setValue(final int x, final int y, final float value) {
246        final int index = checkCoordinatesAndComputeIndex(x, y, 0);
247        data[index] = (int) value;
248    }
249
250    /**
251     * Sets the value stored at the specified raster coordinates.
252     *
253     * @param x     integer coordinate in the columnar direction
254     * @param y     integer coordinate in the row direction
255     * @param i     integer sample index (for data sets giving multiple samples per raster cell).
256     * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
257     */
258    @Override
259    public void setValue(final int x, final int y, final int i, final float value) {
260        final int index = checkCoordinatesAndComputeIndex(x, y, i);
261        data[index] = (int) value;
262    }
263}