1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.imaging.formats.tiff;
18
19 import java.util.stream.IntStream;
20
21 import org.apache.commons.imaging.common.Allocator;
22
23 /**
24 * 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
25 * support access to those TIFF files.
26 * <p>
27 * <strong>Note:</strong> The getData() and getIntData() methods can return direct references to the internal arrays stored in instances of this class. Because
28 * 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.
29 * This approach is used for purposes of efficiency when dealing with very large TIFF images.
30 * <p>
31 * <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
32 * 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
33 * 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
34 *
35 * <pre>
36 * index = y * width + x + iSample * width * height;
37 * </pre>
38 */
39 public final class TiffRasterDataFloat extends AbstractTiffRasterData {
40
41 private final float[] data;
42
43 /**
44 * Constructs an instance allocating memory for the specified dimensions.
45 *
46 * @param width a value of 1 or greater
47 * @param height a value of 1 or greater
48 */
49 public TiffRasterDataFloat(final int width, final int height) {
50 super(width, height, 1);
51 data = Allocator.floatArray(nCells);
52 }
53
54 /**
55 * Constructs an instance allocating memory for the specified dimensions.
56 *
57 * @param width a value of 1 or greater
58 * @param height a value of 1 or greater
59 * @param data the data to be stored in the raster.
60 */
61 public TiffRasterDataFloat(final int width, final int height, final float[] data) {
62 super(width, height, 1);
63 if (data == null || data.length < nCells) {
64 throw new IllegalArgumentException("Specified data does not contain sufficient elements");
65 }
66 this.data = data;
67 }
68
69 /**
70 * Constructs an instance allocating memory for the specified dimensions.
71 *
72 * @param width a value of 1 or greater
73 * @param height a value of 1 or greater
74 * @param samplesPerPixel a value of 1 or greater
75 */
76 public TiffRasterDataFloat(final int width, final int height, final int samplesPerPixel) {
77 super(width, height, samplesPerPixel);
78 data = Allocator.floatArray(nCells);
79 }
80
81 /**
82 * Constructs an instance allocating memory for the specified dimensions.
83 *
84 * @param width a value of 1 or greater
85 * @param height a value of 1 or greater
86 * @param samplesPerCell the number of samples per pixel
87 * @param data the data to be stored in the raster.
88 */
89 public TiffRasterDataFloat(final int width, final int height, final int samplesPerCell, final float[] data) {
90 super(width, height, samplesPerCell);
91 if (data == null || data.length < nCells) {
92 throw new IllegalArgumentException("Specified data does not contain sufficient elements");
93 }
94 this.data = data;
95 }
96
97 /**
98 * 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
99 * 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
100 * performance and memory conservation. TIFF images that contain floating-point data are often quite large. Sizes of 100 million raster cells are common.
101 * Making a redundant copy of such a large in-memory object might exceed the resources available to a Java application.
102 * <p>
103 * See the class API documentation above for notes on accessing array elements.
104 *
105 * @return a direct reference to the data array stored in this instance.
106 */
107 @Override
108 public float[] getData() {
109 return data;
110 }
111
112 /**
113 * Gets the raster data type from the instance.
114 *
115 * @return a value of TiffRasterDataType.FLOAT.
116 */
117 @Override
118 public TiffRasterDataType getDataType() {
119 return TiffRasterDataType.FLOAT;
120 }
121
122 /**
123 * Returns an array of integer approximations for the floating-point content stored as an array in this instance.
124 * <p>
125 * See the class API documentation above for notes on accessing array elements.
126 *
127 * @return the integer equivalents to the data content stored in this instance.
128 */
129 @Override
130 public int[] getIntData() {
131 return IntStream.range(0, nCells).map(i -> (int) data[i]).toArray();
132 }
133
134 /**
135 * Gets the value stored at the specified raster coordinates.
136 *
137 * @param x integer coordinate in the columnar direction
138 * @param y integer coordinate in the row direction
139 * @return the value stored at the specified location
140 */
141 @Override
142 public int getIntValue(final int x, final int y) {
143 return (int) data[checkCoordinatesAndComputeIndex(x, y, 0)];
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 * @param i integer sample index (for data sets giving multiple samples per raster cell).
152 * @return the value stored at the specified location
153 */
154 @Override
155 public int getIntValue(final int x, final int y, final int i) {
156 return (int) data[checkCoordinatesAndComputeIndex(x, y, 0)];
157 }
158
159 /**
160 * Tabulates simple statistics for the raster and returns an instance containing general metadata.
161 *
162 * @return a valid instance containing a safe copy of the current simple statistics for the raster.
163 */
164 @Override
165 public TiffRasterStatistics getSimpleStatistics() {
166 return new TiffRasterStatistics(this, Float.NaN);
167 }
168
169 /**
170 * Tabulates simple statistics for the raster excluding the specified value and returns an instance containing general metadata.
171 *
172 * @param valueToExclude exclude samples with this specified value.
173 * @return a valid instance.
174 */
175 @Override
176 public TiffRasterStatistics getSimpleStatistics(final float valueToExclude) {
177 return new TiffRasterStatistics(this, valueToExclude);
178 }
179
180 /**
181 * Gets the value stored at the specified raster coordinates.
182 *
183 * @param x integer coordinate in the columnar direction
184 * @param y integer coordinate in the row direction
185 * @return the value stored at the specified location; potentially a Float.NaN.
186 */
187 @Override
188 public float getValue(final int x, final int y) {
189 return data[checkCoordinatesAndComputeIndex(x, y, 0)];
190 }
191
192 /**
193 * Gets the value stored at the specified raster coordinates.
194 *
195 * @param x integer coordinate in the columnar direction
196 * @param y integer coordinate in the row direction
197 * @param i integer sample index (for data sets giving multiple samples per raster cell).
198 * @return the value stored at the specified location; potentially a Float.NaN.
199 */
200 @Override
201 public float getValue(final int x, final int y, final int i) {
202 return data[checkCoordinatesAndComputeIndex(x, y, i)];
203 }
204
205 /**
206 * Sets the value stored at the specified raster coordinates.
207 *
208 * @param x integer coordinate in the columnar direction
209 * @param y integer coordinate in the row direction
210 * @param value the value to be stored at the specified location
211 */
212 @Override
213 public void setIntValue(final int x, final int y, final int value) {
214 data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
215 }
216
217 /**
218 * Sets 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 raster cell).
223 * @param value the value to be stored at the specified location
224 */
225 @Override
226 public void setIntValue(final int x, final int y, final int i, final int value) {
227 data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
228 }
229
230 /**
231 * Sets the value stored at the specified raster coordinates.
232 *
233 * @param x integer coordinate in the columnar direction
234 * @param y integer coordinate in the row direction
235 * @param value the value to be stored at the specified location; potentially a Float.NaN.
236 */
237 @Override
238 public void setValue(final int x, final int y, final float value) {
239 data[checkCoordinatesAndComputeIndex(x, y, 0)] = value;
240 }
241
242 /**
243 * Sets the value stored at the specified raster coordinates.
244 *
245 * @param x integer coordinate in the columnar direction
246 * @param y integer coordinate in the row direction
247 * @param i integer sample index (for data sets giving multiple samples per raster cell).
248 * @param value the value to be stored at the specified location; potentially a Float.NaN.
249 */
250 @Override
251 public void setValue(final int x, final int y, final int i, final float value) {
252 data[checkCoordinatesAndComputeIndex(x, y, i)] = value;
253 }
254
255 }