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 021import org.apache.commons.imaging.common.Allocator; 022 023/** 024 * 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 025 * support access to those TIFF files. 026 * <p> 027 * <strong>Note:</strong> The getData() and getIntData() methods can return direct references to the internal arrays stored in instances of this class. Because 028 * 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. 029 * This approach is used for purposes of efficiency when dealing with very large TIFF images. 030 * <p> 031 * <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 032 * 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 033 * 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 034 * 035 * <pre> 036 * index = y * width + x + iSample * width * height; 037 * </pre> 038 */ 039public class TiffRasterDataFloat extends TiffRasterData { 040 041 private final float[] data; 042 043 /** 044 * Constructs an instance allocating memory for the specified dimensions. 045 * 046 * @param width a value of 1 or greater 047 * @param height a value of 1 or greater 048 */ 049 public TiffRasterDataFloat(final int width, final int height) { 050 super(width, height, 1); 051 data = Allocator.floatArray(nCells); 052 } 053 054 /** 055 * Constructs an instance allocating memory for the specified dimensions. 056 * 057 * @param width a value of 1 or greater 058 * @param height a value of 1 or greater 059 * @param data the data to be stored in the raster. 060 */ 061 public TiffRasterDataFloat(final int width, final int height, final float[] data) { 062 super(width, height, 1); 063 064 if (data == null || data.length < nCells) { 065 throw new IllegalArgumentException("Specified data does not contain sufficient elements"); 066 } 067 this.data = data; 068 } 069 070 /** 071 * Constructs an instance allocating memory for the specified dimensions. 072 * 073 * @param width a value of 1 or greater 074 * @param height a value of 1 or greater 075 * @param samplesPerPixel a value of 1 or greater 076 */ 077 public TiffRasterDataFloat(final int width, final int height, final int samplesPerPixel) { 078 super(width, height, samplesPerPixel); 079 data = Allocator.floatArray(nCells); 080 } 081 082 /** 083 * Constructs an instance allocating memory for the specified dimensions. 084 * 085 * @param width a value of 1 or greater 086 * @param height a value of 1 or greater 087 * @param samplesPerCell the number of samples per pixel 088 * @param data the data to be stored in the raster. 089 */ 090 public TiffRasterDataFloat(final int width, final int height, final int samplesPerCell, final float[] data) { 091 super(width, height, samplesPerCell); 092 093 if (data == null || data.length < nCells) { 094 throw new IllegalArgumentException("Specified data does not contain sufficient elements"); 095 } 096 this.data = data; 097 } 098 099 /** 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}