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.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.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.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.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.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 }