001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object; 016 017import java.util.Iterator; 018import java.util.List; 019import java.util.Vector; 020 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024/** 025 * A scalar dataset is a multiple dimension array of scalar points. The Datatype of a scalar dataset must be an atomic 026 * datatype. Common datatypes of scalar datasets include char, byte, short, int, long, float, double and string. 027 * 028 * A ScalarDS can be an image or spreadsheet data. ScalarDS defines methods to deal with both images and 029 * spreadsheets. 030 * 031 * ScalarDS is an abstract class. Current implementing classes are the H4SDS, H5GRImage and H5ScalarDS. 032 * 033 * @version 1.1 9/4/2007 034 * @author Peter X. Cao 035 */ 036public abstract class ScalarDS extends Dataset 037{ 038 private static final long serialVersionUID = 8925371455928203981L; 039 040 private static final Logger log = LoggerFactory.getLogger(ScalarDS.class); 041 042 /************************************************************ 043 * The following constant strings are copied from * 044 * https://support.hdfgroup.org/HDF5/doc/ADGuide/ImageSpec.html * 045 * to make the definition consistent with the image specs. * 046 ************************************************************/ 047 048 /** 049 * Indicates that the pixel RGB values are contiguous. 050 */ 051 public static final int INTERLACE_PIXEL = 0; 052 053 /** Indicates that each pixel component of RGB is stored as a scan line. */ 054 public static final int INTERLACE_LINE = 1; 055 056 /** Indicates that each pixel component of RGB is stored as a plane. */ 057 public static final int INTERLACE_PLANE = 2; 058 059 /** 060 * The interlace mode of the stored raster image data. Valid values are INTERLACE_PIXEL, INTERLACE_LINE and 061 * INTERLACE_PLANE. 062 */ 063 protected int interlace; 064 065 /** 066 * The min-max range of image data values. For example, [0, 255] indicates the min is 0, and the max is 255. 067 */ 068 protected double[] imageDataRange; 069 070 /** 071 * The indexed RGB color model with 256 colors. 072 * 073 * The palette values are stored in a two-dimensional byte array and arrange by color components of red, green and 074 * blue. palette[][] = byte[3][256], where, palette[0][], palette[1][] and palette[2][] are the red, green and blue 075 * components respectively. 076 */ 077 protected byte[][] palette; 078 079 /** 080 * True if this dataset is a true color image. 081 */ 082 protected boolean isTrueColor; 083 084 /** 085 * Flag to indicate is the original unsigned C data is converted. 086 */ 087 protected boolean unsignedConverted; 088 089 /** The fill value of the dataset. */ 090 protected Object fillValue = null; 091 092 /** The list of filtered image values. */ 093 private List<Number> filteredImageValues; 094 095 /** Flag to indicate if the dataset is displayed as an image. */ 096 protected boolean isImageDisplay; 097 098 /** 099 * Flag to indicate if the dataset is displayed as an image with default order of dimensions. 100 */ 101 protected boolean isDefaultImageOrder; 102 103 /** 104 * Flag to indicate if the FillValue is converted from unsigned C. 105 */ 106 public boolean isFillValueConverted; 107 108 /** 109 * Constructs an instance of a ScalarDS with specific name and path. An HDF data object must have a name. The path 110 * is the group path starting from the root. 111 * 112 * For example, in H5ScalarDS(h5file, "dset", "/arrays/"), "dset" is the name of the dataset, "/arrays" is the group 113 * path of the dataset. 114 * 115 * @param theFile 116 * the file that contains the data object. 117 * @param theName 118 * the name of the data object, e.g. "dset". 119 * @param thePath 120 * the full path of the data object, e.g. "/arrays/". 121 */ 122 public ScalarDS(FileFormat theFile, String theName, String thePath) { 123 this(theFile, theName, thePath, null); 124 } 125 126 /** 127 * @deprecated Not for public use in the future.<br> 128 * Using {@link #ScalarDS(FileFormat, String, String)} 129 * 130 * @param theFile 131 * the file that contains the data object. 132 * @param theName 133 * the name of the data object, e.g. "dset". 134 * @param thePath 135 * the full path of the data object, e.g. "/arrays/". 136 * @param oid 137 * the object id of the data object. 138 */ 139 @Deprecated 140 public ScalarDS(FileFormat theFile, String theName, String thePath, long[] oid) { 141 super(theFile, theName, thePath, oid); 142 143 palette = null; 144 isImage = false; 145 isTrueColor = false; 146 isText = false; 147 interlace = -1; 148 imageDataRange = null; 149 isImageDisplay = false; 150 isDefaultImageOrder = true; 151 isFillValueConverted = false; 152 filteredImageValues = new Vector<>(); 153 } 154 155 /** 156 * Clears the current data buffer in memory and forces the next read() to load 157 * the data from file. 158 * 159 * The function read() loads data from file into memory only if the data is not 160 * read. If data is already in memory, read() just returns the memory buffer. 161 * Sometimes we want to force read() to re-read data from file. For example, 162 * when the selection is changed, we need to re-read the data. 163 * 164 * @see #getData() 165 * @see #read() 166 */ 167 @Override 168 public void clearData() { 169 super.clearData(); 170 unsignedConverted = false; 171 } 172 173 /** 174 * Converts the data values of this dataset to appropriate Java integer if they are unsigned integers. 175 * 176 * @see hdf.object.Dataset#convertToUnsignedC(Object) 177 * @see hdf.object.Dataset#convertFromUnsignedC(Object, Object) 178 * 179 * @return the converted data buffer. 180 */ 181 @Override 182 public Object convertFromUnsignedC() { 183 // keep a copy of original buffer and the converted buffer 184 // so that they can be reused later to save memory 185 log.trace("convertFromUnsignedC(): unsigned={}", getDatatype().isUnsigned()); 186 if ((data != null) && getDatatype().isUnsigned() && !unsignedConverted) { 187 log.trace("convertFromUnsignedC(): convert"); 188 originalBuf = data; 189 convertedBuf = convertFromUnsignedC(originalBuf, convertedBuf); 190 data = convertedBuf; 191 unsignedConverted = true; 192 193 if (fillValue != null) { 194 if (!isFillValueConverted) { 195 fillValue = convertFromUnsignedC(fillValue, null); 196 isFillValueConverted = true; 197 } 198 } 199 } 200 201 return data; 202 } 203 204 /** 205 * Converts Java integer data of this dataset back to unsigned C-type integer data if they are unsigned integers. 206 * 207 * @see hdf.object.Dataset#convertToUnsignedC(Object) 208 * @see hdf.object.Dataset#convertToUnsignedC(Object, Object) 209 * @see #convertFromUnsignedC(Object data_in) 210 * 211 * @return the converted data buffer. 212 */ 213 @Override 214 public Object convertToUnsignedC() { 215 // keep a copy of original buffer and the converted buffer 216 // so that they can be reused later to save memory 217 log.trace("convertToUnsignedC(): unsigned={}", getDatatype().isUnsigned()); 218 if ((data != null) && getDatatype().isUnsigned()) { 219 log.trace("convertToUnsignedC(): convert"); 220 convertedBuf = data; 221 originalBuf = convertToUnsignedC(convertedBuf, originalBuf); 222 data = originalBuf; 223 } 224 225 return data; 226 } 227 228 /** 229 * Returns the palette of this scalar dataset or null if palette does not exist. 230 * 231 * A Scalar dataset can be displayed as spreadsheet data or an image. When a scalar dataset is displayed as an 232 * image, the palette or color table may be needed to translate a pixel value to color components (for example, red, 233 * green, and blue). Some scalar datasets have no palette and some datasets have one or more than one palettes. If 234 * an associated palette exists but is not loaded, this interface retrieves the palette from the file and returns the 235 * palette. If the palette is loaded, it returns the palette. It returns null if there is no palette associated with 236 * the dataset. 237 * 238 * Current implementation only supports palette model of indexed RGB with 256 colors. Other models such as 239 * YUV", "CMY", "CMYK", "YCbCr", "HSV will be supported in the future. 240 * 241 * The palette values are stored in a two-dimensional byte array and are arranges by color components of red, green and 242 * blue. palette[][] = byte[3][256], where, palette[0][], palette[1][] and palette[2][] are the red, green and blue 243 * components respectively. 244 * 245 * Sub-classes have to implement this interface. HDF4 and HDF5 images use different libraries to retrieve the 246 * associated palette. 247 * 248 * @return the 2D palette byte array. 249 */ 250 public byte[][] getPalette() { 251 return palette; 252 } 253 254 /** 255 * Sets the palette for this dataset. 256 * 257 * @param pal 258 * the 2D palette byte array. 259 */ 260 public final void setPalette(byte[][] pal) { 261 palette = pal; 262 } 263 264 /** 265 * Reads a specific image palette from file. 266 * 267 * A scalar dataset may have multiple palettes attached to it. readPalette(int idx) returns a specific palette 268 * identified by its index. 269 * 270 * @param idx 271 * the index of the palette to read. 272 * 273 * @return the image palette 274 */ 275 public byte[][] readPalette(int idx) { 276 return null; 277 } 278 279 /** 280 * Get the name of a specific image palette from file. 281 * 282 * A scalar dataset may have multiple palettes attached to it. getPaletteName(int idx) returns the name of a 283 * specific palette identified by its index. 284 * 285 * @param idx 286 * the index of the palette to retrieve the name. 287 * 288 * @return The name of the palette 289 */ 290 public String getPaletteName(int idx) { 291 String paletteName = "Default "; 292 if (idx != 0) 293 paletteName = "Default " + idx; 294 return paletteName; 295 } 296 297 /** 298 * Get the number of pallettes for this object. 299 * 300 * @return the number of palettes if it has any, 301 * 0 if there is no palette attribute attached to this dataset. 302 */ 303 public int getNumberOfPalettes() { 304 return 0; 305 } 306 307 /** 308 * Returns true if this dataset is an image. 309 * 310 * For all Images, they must have an attribute called "CLASS". The value of this attribute is "IMAGE". For more 311 * details, read <a href="https://support.hdfgroup.org/HDF5/doc/ADGuide/ImageSpec.html"> HDF5 Image and Palette Specification</a> 312 * 313 * @return true if the dataset is an image; otherwise, returns false. 314 */ 315 public final boolean isImage() { 316 return isImage; 317 } 318 319 /** 320 * Returns true if this dataset is displayed as an image. 321 * 322 * A ScalarDS can be displayed as an image or a spreadsheet in a table. 323 * 324 * @return true if this dataset is displayed as an image; otherwise, returns false. 325 */ 326 public final boolean isImageDisplay() { 327 328 return isImageDisplay; 329 } 330 331 /** 332 * Returns true if this dataset is displayed as an image with default image order. 333 * 334 * A ScalarDS can be displayed as an image with different orders of dimensions. 335 * 336 * @return true if this dataset is displayed as an image with default image order; otherwise, returns false. 337 */ 338 public final boolean isDefaultImageOrder() { 339 return isDefaultImageOrder; 340 } 341 342 /** 343 * Sets the flag to display the dataset as an image. 344 * 345 * @param b 346 * if b is true, display the dataset as an image 347 */ 348 public final void setIsImageDisplay(boolean b) { 349 isImageDisplay = b; 350 } 351 352 /** 353 * Sets the flag to indicate this dataset is an image. 354 * 355 * @param b 356 * if b is true, the dataset is an image. 357 */ 358 public final void setIsImage(boolean b) { 359 isImage = b; 360 } 361 362 /** 363 * Sets data range for an image. 364 * 365 * @param min 366 * the data range start. 367 * @param max 368 * the data range end. 369 */ 370 public final void setImageDataRange(double min, double max) { 371 if (max <= min) 372 return; 373 374 if (imageDataRange == null) 375 imageDataRange = new double[2]; 376 377 imageDataRange[0] = min; 378 imageDataRange[1] = max; 379 } 380 381 /** 382 * Add a value that will be filtered out in an image. 383 * 384 * @param x 385 * value to be filtered 386 */ 387 public void addFilteredImageValue(Number x) { 388 Iterator<Number> it = filteredImageValues.iterator(); 389 while (it.hasNext()) { 390 if (it.next().toString().equals(x.toString())) 391 return; 392 } 393 394 filteredImageValues.add(x); 395 } 396 397 /** 398 * Get a list of values that will be filtered out in an image. 399 * 400 * @return the list of Image values 401 */ 402 public List<Number> getFilteredImageValues() { 403 return filteredImageValues; 404 } 405 406 /** 407 * @return true if this dataset is a true color image. 408 * 409 */ 410 411 public final boolean isTrueColor() { 412 return isTrueColor; 413 } 414 415 /** 416 * Returns the interlace mode of a true color image (RGB). 417 * 418 * Valid values: 419 * 420 * <pre> 421 * INTERLACE_PIXEL -- RGB components are contiguous, i.e. rgb, rgb, rgb, ... 422 * INTERLACE_LINE -- each RGB component is stored as a scan line 423 * INTERLACE_PLANE -- each RGB component is stored as a plane 424 * </pre> 425 * 426 * @return the interlace mode of a true color image (RGB). 427 */ 428 public final int getInterlace() { 429 return interlace; 430 } 431 432 /** 433 * Returns the (min, max) pair of image data range. 434 * 435 * @return the (min, max) pair of image data range. 436 */ 437 public double[] getImageDataRange() { 438 return imageDataRange; 439 } 440 441 /** 442 * Returns the fill values for the dataset. 443 * 444 * @return the fill values for the dataset. 445 */ 446 @Override 447 public final Object getFillValue() { 448 return fillValue; 449 } 450}