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