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