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}