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 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&#46;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&#46;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&#46;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&#46;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&#46;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 }