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 byte[][] getPalette() { 248 return palette; 249 } 250 251 /** 252 * Sets the palette for this dataset. 253 * 254 * @param pal 255 * the 2D palette byte array. 256 */ 257 public final void setPalette(byte[][] pal) { 258 palette = pal; 259 } 260 261 /** 262 * Reads a specific image palette from file. 263 * 264 * A scalar dataset may have multiple palettes attached to it. readPalette(int idx) returns a specific palette 265 * identified by its index. 266 * 267 * @param idx 268 * the index of the palette to read. 269 * 270 * @return the image palette 271 */ 272 public byte[][] readPalette(int idx) { 273 return null; 274 } 275 276 /** 277 * Get the name of a specific image palette from file. 278 * 279 * A scalar dataset may have multiple palettes attached to it. getPaletteName(int idx) returns the name of a 280 * specific palette identified by its index. 281 * 282 * @param idx 283 * the index of the palette to retrieve the name. 284 * 285 * @return The name of the palette 286 */ 287 public String getPaletteName(int idx) { 288 String paletteName = "Default "; 289 if (idx != 0) 290 paletteName = "Default " + idx; 291 return paletteName; 292 } 293 294 /** 295 * Get the number of pallettes for this object. 296 * 297 * @return the number of palettes if it has any, 298 * 0 if there is no palette attribute attached to this dataset. 299 */ 300 public int getNumberOfPalettes() { 301 return 0; 302 } 303 304 /** 305 * Returns true if this dataset is an image. 306 * 307 * For all Images, they must have an attribute called "CLASS". The value of this attribute is "IMAGE". For more 308 * details, read <a href="https://support.hdfgroup.org/HDF5/doc/ADGuide/ImageSpec.html"> HDF5 Image and Palette Specification</a> 309 * 310 * @return true if the dataset is an image; otherwise, returns false. 311 */ 312 public final boolean isImage() { 313 return isImage; 314 } 315 316 /** 317 * Returns true if this dataset is displayed as an image. 318 * 319 * A ScalarDS can be displayed as an image or a spreadsheet in a table. 320 * 321 * @return true if this dataset is displayed as an image; otherwise, returns false. 322 */ 323 public final boolean isImageDisplay() { 324 325 return isImageDisplay; 326 } 327 328 /** 329 * Returns true if this dataset is displayed as an image with default image order. 330 * 331 * A ScalarDS can be displayed as an image with different orders of dimensions. 332 * 333 * @return true if this dataset is displayed as an image with default image order; otherwise, returns false. 334 */ 335 public final boolean isDefaultImageOrder() { 336 return isDefaultImageOrder; 337 } 338 339 /** 340 * Sets the flag to display the dataset as an image. 341 * 342 * @param b 343 * if b is true, display the dataset as an image 344 */ 345 public final void setIsImageDisplay(boolean b) { 346 isImageDisplay = b; 347 } 348 349 /** 350 * Sets the flag to indicate this dataset is an image. 351 * 352 * @param b 353 * if b is true, the dataset is an image. 354 */ 355 public final void setIsImage(boolean b) { 356 isImage = b; 357 } 358 359 /** 360 * Sets data range for an image. 361 * 362 * @param min 363 * the data range start. 364 * @param max 365 * the data range end. 366 */ 367 public final void setImageDataRange(double min, double max) { 368 if (max <= min) 369 return; 370 371 if (imageDataRange == null) 372 imageDataRange = new double[2]; 373 374 imageDataRange[0] = min; 375 imageDataRange[1] = max; 376 } 377 378 /** 379 * Add a value that will be filtered out in an image. 380 * 381 * @param x 382 * value to be filtered 383 */ 384 public void addFilteredImageValue(Number x) { 385 Iterator<Number> it = filteredImageValues.iterator(); 386 while (it.hasNext()) { 387 if (it.next().toString().equals(x.toString())) 388 return; 389 } 390 391 filteredImageValues.add(x); 392 } 393 394 /** 395 * Get a list of values that will be filtered out in an image. 396 * 397 * @return the list of Image values 398 */ 399 public List<Number> getFilteredImageValues() { 400 return filteredImageValues; 401 } 402 403 /** 404 * @return true if this dataset is a true color image. 405 * 406 */ 407 408 public final boolean isTrueColor() { 409 return isTrueColor; 410 } 411 412 /** 413 * Returns the interlace mode of a true color image (RGB). 414 * 415 * Valid values: 416 * 417 * <pre> 418 * INTERLACE_PIXEL -- RGB components are contiguous, i.e. rgb, rgb, rgb, ... 419 * INTERLACE_LINE -- each RGB component is stored as a scan line 420 * INTERLACE_PLANE -- each RGB component is stored as a plane 421 * </pre> 422 * 423 * @return the interlace mode of a true color image (RGB). 424 */ 425 public final int getInterlace() { 426 return interlace; 427 } 428 429 /** 430 * Returns the (min, max) pair of image data range. 431 * 432 * @return the (min, max) pair of image data range. 433 */ 434 public double[] getImageDataRange() { 435 return imageDataRange; 436 } 437 438 /** 439 * Returns the fill values for the dataset. 440 * 441 * @return the fill values for the dataset. 442 */ 443 @Override 444 public final Object getFillValue() { 445 return fillValue; 446 } 447}