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