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