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