View Javadoc
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 class TiffRasterDataFloat extends TiffRasterData {
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  
64          if (data == null || data.length < nCells) {
65              throw new IllegalArgumentException("Specified data does not contain sufficient elements");
66          }
67          this.data = data;
68      }
69  
70      /**
71       * Constructs an instance allocating memory for the specified dimensions.
72       *
73       * @param width           a value of 1 or greater
74       * @param height          a value of 1 or greater
75       * @param samplesPerPixel a value of 1 or greater
76       */
77      public TiffRasterDataFloat(final int width, final int height, final int samplesPerPixel) {
78          super(width, height, samplesPerPixel);
79          data = Allocator.floatArray(nCells);
80      }
81  
82      /**
83       * Constructs an instance allocating memory for the specified dimensions.
84       *
85       * @param width          a value of 1 or greater
86       * @param height         a value of 1 or greater
87       * @param samplesPerCell the number of samples per pixel
88       * @param data           the data to be stored in the raster.
89       */
90      public TiffRasterDataFloat(final int width, final int height, final int samplesPerCell, final float[] data) {
91          super(width, height, samplesPerCell);
92  
93          if (data == null || data.length < nCells) {
94              throw new IllegalArgumentException("Specified data does not contain sufficient elements");
95          }
96          this.data = data;
97      }
98  
99      /**
100      * 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
101      * 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
102      * performance and memory conservation. TIFF images that contain floating-point data are often quite large. Sizes of 100 million raster cells are common.
103      * Making a redundant copy of such a large in-memory object might exceed the resources available to a Java application.
104      * <p>
105      * See the class API documentation above for notes on accessing array elements.
106      *
107      * @return a direct reference to the data array stored in this instance.
108      */
109     @Override
110     public float[] getData() {
111         return data;
112     }
113 
114     /**
115      * Gets the raster data type from the instance.
116      *
117      * @return a value of TiffRasterDataType&#46;FLOAT.
118      */
119     @Override
120     public TiffRasterDataType getDataType() {
121         return TiffRasterDataType.FLOAT;
122     }
123 
124     /**
125      * Returns an array of integer approximations for the floating-point content stored as an array in this instance.
126      * <p>
127      * See the class API documentation above for notes on accessing array elements.
128      *
129      * @return the integer equivalents to the data content stored in this instance.
130      */
131     @Override
132     public int[] getIntData() {
133         return IntStream.range(0, nCells).map(i -> (int) data[i]).toArray();
134     }
135 
136     /**
137      * Gets the value stored at the specified raster coordinates.
138      *
139      * @param x integer coordinate in the columnar direction
140      * @param y integer coordinate in the row direction
141      * @return the value stored at the specified location
142      */
143     @Override
144     public int getIntValue(final int x, final int y) {
145         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
146         return (int) data[index];
147     }
148 
149     /**
150      * Gets the value stored at the specified raster coordinates.
151      *
152      * @param x integer coordinate in the columnar direction
153      * @param y integer coordinate in the row direction
154      * @param i integer sample index (for data sets giving multiple samples per raster cell).
155      * @return the value stored at the specified location
156      */
157     @Override
158     public int getIntValue(final int x, final int y, final int i) {
159         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
160         return (int) data[index];
161     }
162 
163     /**
164      * Tabulates simple statistics for the raster and returns an instance containing general metadata.
165      *
166      * @return a valid instance containing a safe copy of the current simple statistics for the raster.
167      */
168     @Override
169     public TiffRasterStatistics getSimpleStatistics() {
170         return new TiffRasterStatistics(this, Float.NaN);
171     }
172 
173     /**
174      * Tabulates simple statistics for the raster excluding the specified value and returns an instance containing general metadata.
175      *
176      * @param valueToExclude exclude samples with this specified value.
177      * @return a valid instance.
178      */
179     @Override
180     public TiffRasterStatistics getSimpleStatistics(final float valueToExclude) {
181         return new TiffRasterStatistics(this, valueToExclude);
182     }
183 
184     /**
185      * Gets the value stored at the specified raster coordinates.
186      *
187      * @param x integer coordinate in the columnar direction
188      * @param y integer coordinate in the row direction
189      * @return the value stored at the specified location; potentially a Float&#46;NaN.
190      */
191     @Override
192     public float getValue(final int x, final int y) {
193         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
194         return data[index];
195     }
196 
197     /**
198      * Gets the value stored at the specified raster coordinates.
199      *
200      * @param x integer coordinate in the columnar direction
201      * @param y integer coordinate in the row direction
202      * @param i integer sample index (for data sets giving multiple samples per raster cell).
203      * @return the value stored at the specified location; potentially a Float&#46;NaN.
204      */
205     @Override
206     public float getValue(final int x, final int y, final int i) {
207         final int index = checkCoordinatesAndComputeIndex(x, y, i);
208         return data[index];
209     }
210 
211     /**
212      * Sets the value stored at the specified raster coordinates.
213      *
214      * @param x     integer coordinate in the columnar direction
215      * @param y     integer coordinate in the row direction
216      * @param value the value to be stored at the specified location
217      */
218     @Override
219     public void setIntValue(final int x, final int y, final int value) {
220         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
221         data[index] = value;
222     }
223 
224     /**
225      * Sets the value stored at the specified raster coordinates.
226      *
227      * @param x     integer coordinate in the columnar direction
228      * @param y     integer coordinate in the row direction
229      * @param i     integer sample index (for data sets giving multiple samples per raster cell).
230      * @param value the value to be stored at the specified location
231      */
232     @Override
233     public void setIntValue(final int x, final int y, final int i, final int value) {
234         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
235         data[index] = value;
236     }
237 
238     /**
239      * Sets the value stored at the specified raster coordinates.
240      *
241      * @param x     integer coordinate in the columnar direction
242      * @param y     integer coordinate in the row direction
243      * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
244      */
245     @Override
246     public void setValue(final int x, final int y, final float value) {
247         final int index = checkCoordinatesAndComputeIndex(x, y, 0);
248         data[index] = value;
249     }
250 
251     /**
252      * Sets the value stored at the specified raster coordinates.
253      *
254      * @param x     integer coordinate in the columnar direction
255      * @param y     integer coordinate in the row direction
256      * @param i     integer sample index (for data sets giving multiple samples per raster cell).
257      * @param value the value to be stored at the specified location; potentially a Float&#46;NaN.
258      */
259     @Override
260     public void setValue(final int x, final int y, final int i, final float value) {
261         final int index = checkCoordinatesAndComputeIndex(x, y, i);
262         data[index] = value;
263     }
264 
265 }