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