    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.h4;
    016
    017import java.util.List;
    018import java.util.Vector;
    019
    020import hdf.hdflib.HDFChunkInfo;
    021import hdf.hdflib.HDFCompInfo;
    022import hdf.hdflib.HDFConstants;
    023import hdf.hdflib.HDFDeflateCompInfo;
    024import hdf.hdflib.HDFException;
    025import hdf.hdflib.HDFLibrary;
    026import hdf.object.Attribute;
    027import hdf.object.Dataset;
    028import hdf.object.Datatype;
    029import hdf.object.FileFormat;
    030import hdf.object.Group;
    031import hdf.object.HObject;
    032import hdf.object.ScalarDS;
    033
    034/**
    035 * H4GRImage describes an HDF4 general raster(GR) image and operations performed on
    036 * the GR image. An HDF4 raster image is a two-dimension array of pixel values.
    037 * <p>
    038 * Every GR data set must contain the following components: image array, name,
    039 * pixel type, and dimensions. The name, dimensions, and pixel type must be
    040 * supplied by the user at the time the GR data set is defined.
    041 * <p>
    042 * An image array is a two-dimensional array of pixels. Each element in an image
    043 * array corresponds to one pixel and each pixel can consist of a number of
    044 * color component values or pixel components, e.g., Red-Green-Blue or RGB,
    045 * Cyan-Magenta-Yellow-Black or CMYK, etc. Pixel components can be represented
    046 * by different methods (8-bit lookup table or 24-bit direct representation) and
    047 * may have different data types. The data type of pixel components and the number
    048 * of components in each pixel are collectively known as the pixel type.
    049 * <p>
    050 * <b>How to Select a Subset</b>
    051 * <p>
    052 * Dataset defines APIs for reading, writing and subsetting a dataset. No function is
    053 * defined to select a subset of a data array. The selection is done in an implicit way.
    054 * Function calls to dimension information such as getSelectedDims() return an array
    055 * of dimension values, which is a reference to the array in the dataset object.
    056 * Changes of the array outside the dataset object directly change the values of
    057 * the array in the dataset object. It is like pointers in C.
    058 * <p>
    059 *
    060 * The following is an example of how to make a subset. In the example, the dataset
    061 * is a 4-dimension with size of [200][100][50][10], i.e.
    062 * dims[0]=200; dims[1]=100; dims[2]=50; dims[3]=10; <br>
    063 * We want to select every other data point in dims[1] and dims[2]
    064 * <pre>
    065     int rank = dataset.getRank();   // number of dimensions of the dataset
    066     long[] dims = dataset.getDims(); // the dimension sizes of the dataset
    067     long[] selected = dataset.getSelectedDims(); // the selected size of the dataet
    068     long[] start = dataset.getStartDims(); // the offset of the selection
    069     long[] stride = dataset.getStride(); // the stride of the dataset
    070     int[]  selectedIndex = dataset.getSelectedIndex(); // the selected dimensions for display
    071
    072     // select dim1 and dim2 as 2D data for display, and slice through dim0
    073     selectedIndex[0] = 1;
    074     selectedIndex[1] = 2;
    075     selectedIndex[1] = 0;
    076
    077     // reset the selection arrays
    078     for (int i=0; i&lt;rank; i++) {
    079         start[i] = 0;
    080         selected[i] = 1;
    081         stride[i] = 1;
    082    }
    083
    084    // set stride to 2 on dim1 and dim2 so that every other data point is selected.
    085    stride[1] = 2;
    086    stride[2] = 2;
    087
    088    // set the selection size of dim1 and dim2
    089    selected[1] = dims[1]/stride[1];
    090    selected[2] = dims[1]/stride[2];
    091
    092    // when dataset.read() is called, the slection above will be used since
    093    // the dimension arrays are passed by reference. Changes of these arrays
    094    // outside the dataset object directly change the values of these array
    095    // in the dataset object.
    096
    097 * </pre>
    098 *
    099 * @version 1.1 9/4/2007
    100 * @author Peter X. Cao
    101 */
    102public class H4GRImage extends ScalarDS
    103{
    104    private static final long serialVersionUID = 1029672744963360976L;
    105
    106    private static final org.slf4j.Logger   log = org.slf4j.LoggerFactory.getLogger(H4GRImage.class);
    107
    108    /**
    109     * The list of attributes of this data object. Members of the list are
    110     * instance of Attribute.
    111     */
    112    @SuppressWarnings("rawtypes")
    113    private List                            attributeList;
    114
    115    /**
    116     * The GR interface identifier obtained from GRstart(fid)
    117     */
    118    private long                            grid;
    119
    120    /**
    121     * The number of components in the raster image
    122     */
    123    private int                             ncomp;
    124
    125    /** the datatype identifier */
    126    private long                            datatypeID = -1;
    127
    128    private int                             nAttributes = -1;
    129
    130
    131    public H4GRImage(FileFormat theFile, String name, String path)
    132    {
    133        this(theFile, name, path, null);
    134    }
    135
    136    /**
    137     * Creates a H4GRImage object with specific name, path, and object ID.
    138     *
    139     * @param theFile the HDF file.
    140     * @param name the name of this H4GRImage.
    141     * @param path the full path of this H4GRImage.
    142     * @param oid the unique identifier of this data object.
    143     */
    144    @SuppressWarnings("deprecation")
    145    public H4GRImage(
    146        FileFormat theFile,
    147        String name,
    148        String path,
    149        long[] oid)
    150    {
    151        super (theFile, name, path, oid);
    152        palette = null;
    153        isImage = isImageDisplay = true;
    154        unsignedConverted = false;
    155        grid = ((H4File)getFileFormat()).getGRAccessID();
    156    }
    157
    158    /*
    159     * (non-Javadoc)
    160     * @see hdf.object.DataFormat#hasAttribute()
    161     */
    162    @Override
    163    public boolean hasAttribute ()
    164    {
    165        if (nAttributes < 0) {
    166            grid = ((H4File)getFileFormat()).getGRAccessID();
    167
    168            long id = open();
    169
    170            if (id >= 0) {
    171                String[] objName = {""};
    172                int[] grInfo = new int[4]; //ncomp, data_type, interlace, and num_attrs
    173                int[] idims = new int[2];
    174                try {
    175                    HDFLibrary.GRgetiminfo(id, objName, grInfo, idims);
    176                    nAttributes = grInfo[3];
    177                }
    178                catch (Exception ex) {
    179                    log.trace("hasAttribute() failure: ", ex);
    180                    nAttributes = 0;
    181                }
    182
    183                log.trace("hasAttribute(): nAttributes={}", nAttributes);
    184
    185                close(id);
    186            }
    187        }
    188
    189        return (nAttributes > 0);
    190    }
    191
    192    // To do: Implementing Dataset
    193    @Override
    194    public Dataset copy(Group pgroup, String dname, long[] dims, Object buff) throws Exception
    195    {
    196        log.trace("copy(): start: parentGroup={} datasetName={}", pgroup, dname);
    197
    198        Dataset dataset = null;
    199        long srcdid = -1;
    200        long dstdid = -1;
    201        String path = null;
    202        int[] count = null;
    203
    204        if (pgroup == null) {
    205            log.debug("copy(): Parent group is null - exit");
    206            return null;
    207        }
    208
    209        if (pgroup.isRoot()) {
    210            path = HObject.SEPARATOR;
    211        }
    212        else {
    213            path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR;
    214        }
    215
    216        srcdid = open();
    217        if (srcdid < 0) {
    218            log.debug("copy(): Invalid source dataset ID - exit");
    219            return null;
    220        }
    221
    222        if (dims != null) {
    223            count = new int[2];
    224            count[0] = (int)dims[0];
    225            count[1] = (int)dims[1];
    226        }
    227
    228        int[] grInfo = new int[4]; //ncomp, data_type, interlace and num_attrs
    229        try {
    230            String[] tmpName = {""};
    231            int[] tmpDims = new int[2];
    232            HDFLibrary.GRgetiminfo(srcdid, tmpName, grInfo, tmpDims);
    233            if (count == null) {
    234                count = tmpDims;
    235            }
    236        }
    237        catch (HDFException ex) {
    238            log.debug("copy(): GRgetiminfo failure: ", ex);
    239        }
    240
    241        ncomp = grInfo[0];
    242        long tid = grInfo[1];
    243        int interlace = grInfo[2];
    244        int numberOfAttributes = grInfo[3];
    245        dstdid = HDFLibrary.GRcreate(
    246                ((H4File)pgroup.getFileFormat()).getGRAccessID(),
    247                dname, ncomp, tid, interlace, count);
    248        if (dstdid < 0) {
    249            log.debug("copy(): Invalid dest dataset ID - exit");
    250            return null;
    251        }
    252
    253        int ref = HDFLibrary.GRidtoref(dstdid);
    254        if (!pgroup.isRoot()) {
    255            long vgid = pgroup.open();
    256            HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_RIG, ref);
    257            pgroup.close(vgid);
    258        }
    259
    260        // read data from the source dataset
    261        int[] start = {0, 0};
    262        if ((buff == null) && (count != null)) {
    263            buff = new byte[count[0]*count[1] * HDFLibrary.DFKNTsize(tid)];
    264            HDFLibrary.GRreadimage(srcdid, start, null, count, buff);
    265        }
    266
    267        // write the data into the destination dataset
    268        HDFLibrary.GRwriteimage(dstdid, start, null, count, buff);
    269
    270        // copy palette
    271        long pid = HDFLibrary.GRgetlutid(srcdid, 0);
    272        int[] palInfo = new int[4];
    273
    274        HDFLibrary.GRgetlutinfo(pid, palInfo);
    275        palInfo[1] = HDFConstants.DFNT_UINT8; // support unsigned byte only. Other type does not work
    276        int palSize = palInfo[0]*palInfo[3];
    277        byte[] palBuff = new byte[palSize];
    278        HDFLibrary.GRreadlut(pid, palBuff);
    279        pid = HDFLibrary.GRgetlutid(dstdid, 0);
    280        HDFLibrary.GRwritelut(pid, palInfo[0], palInfo[1], palInfo[2], palInfo[3], palBuff);
    281
    282        // copy attributes from one object to the new object
    283        log.trace("copy(): copyAttributes: numAttributes={}", numberOfAttributes);
    284        copyAttribute(srcdid, dstdid, numberOfAttributes);
    285
    286        long[] oid = {HDFConstants.DFTAG_RIG, ref};
    287        dataset = new H4GRImage(pgroup.getFileFormat(), dname, path, oid);
    288
    289        pgroup.addToMemberList(dataset);
    290
    291        close(srcdid);
    292
    293        try {
    294            HDFLibrary.GRendaccess(dstdid);
    295        }
    296        catch (HDFException ex) {
    297            log.debug("copy(): GRendaccess failure: ", ex);
    298        }
    299
    300        return dataset;
    301    }
    302
    303    // ***** need to implement from ScalarDS *****
    304    @Override
    305    public byte[][] readPalette(int idx) { return null;}
    306
    307    // ***** need to implement from ScalarDS *****
    308    @Override
    309    public byte[] getPaletteRefs() { return null;}
    310
    311    // implementing ScalarDS
    312    @Override
    313    public Datatype getDatatype()
    314    {
    315        if (!inited)
    316            init();
    317
    318        if (datatype == null) {
    319            try {
    320                datatype = new H4Datatype(datatypeID);
    321            }
    322            catch (Exception ex) {
    323                log.debug("getDatatype(): failed to create datatype: ", ex);
    324                datatype = null;
    325            }
    326        }
    327
    328        return datatype;
    329    }
    330
    331    // Implementing Dataset
    332    @Override
    333    public byte[] readBytes() throws HDFException
    334    {
    335        byte[] theData = null;
    336
    337        if (!isInited()) init();
    338
    339        long id = open();
    340        if (id < 0) {
    341            log.debug("readBytes(): Invalid ID - exit");
    342            return null;
    343        }
    344
    345        try {
    346            // set the interlacing scheme for reading image data
    347            HDFLibrary.GRreqimageil(id, interlace);
    348            int datasize = (int)(getWidth()*getHeight()*ncomp);
    349            int size = HDFLibrary.DFKNTsize(datatypeID)*datasize;
    350            theData = new byte[size];
    351            int[] start = {(int)startDims[0], (int)startDims[1]};
    352            int[] select = {(int)selectedDims[0], (int)selectedDims[1]};
    353
    354            int[] stride = null;
    355            if (selectedStride != null) {
    356                stride = new int[rank];
    357                for (int i=0; i<rank; i++) {
    358                    stride[i] = (int)selectedStride[i];
    359                }
    360            }
    361
    362            HDFLibrary.GRreadimage(id, start, stride, select, theData);
    363        }
    364        catch (Exception ex) {
    365            log.debug("readBytes(): failure: ", ex);
    366        }
    367        finally {
    368            close(id);
    369        }
    370
    371        return theData;
    372    }
    373
    374    // ***** need to implement from DataFormat *****
    375    @Override
    376    public Object read() throws HDFException
    377    {
    378        Object theData = null;
    379
    380        if (!isInited()) init();
    381
    382        long id = open();
    383        if (id < 0) {
    384            log.debug("read(): Invalid ID");
    385            return null;
    386        }
    387
    388        try {
    389            // set the interlacing scheme for reading image data
    390            HDFLibrary.GRreqimageil(id, interlace);
    391            int datasize = (int)(getWidth()*getHeight()*ncomp);
    392
    393            theData = H4Datatype.allocateArray(datatypeID, datasize);
    394
    395            if (theData != null) {
    396                // assume external data files are located in the same directory as the main file.
    397                HDFLibrary.HXsetdir(getFileFormat().getParent());
    398
    399                int[] start = {(int)startDims[0], (int)startDims[1]};
    400                int[] select = {(int)selectedDims[0], (int)selectedDims[1]};
    401
    402                int[] stride = null;
    403                if (selectedStride != null) {
    404                    stride = new int[rank];
    405                    for (int i=0; i<rank; i++) {
    406                        stride[i] = (int)selectedStride[i];
    407                    }
    408                }
    409
    410                HDFLibrary.GRreadimage(id, start, stride, select, theData);
    411            }
    412        }
    413        catch (Exception ex) {
    414            log.debug("read(): failure: ", ex);
    415        }
    416        finally {
    417            close(id);
    418        }
    419
    420        if ( (rank >1) && (selectedIndex[1]>selectedIndex[0]))
    421            isDefaultImageOrder = false;
    422        else
    423            isDefaultImageOrder = true;
    424
    425        log.trace("read(): isDefaultImageOrder={}", isDefaultImageOrder);
    426        return theData;
    427    }
    428
    429    // Implementing DataFormat
    430    @SuppressWarnings("deprecation")
    431    @Override
    432    public void write(Object buf) throws HDFException
    433    {
    434        if (buf == null) {
    435            log.debug("write(): buf is null - exit");
    436            return;
    437        }
    438
    439        long id = open();
    440        if (id < 0) {
    441            log.debug("write(): Invalid ID - exit");
    442            return;
    443        }
    444
    445        int[] select = new int[rank];
    446        int[] start = new int[rank];
    447        for (int i=0; i<rank; i++) {
    448            select[i] = (int)selectedDims[i];
    449            start[i] = (int)startDims[i];
    450        }
    451
    452        int[] stride = null;
    453        if (selectedStride != null) {
    454            stride = new int[rank];
    455            for (int i=0; i<rank; i++) {
    456                stride[i] = (int)selectedStride[i];
    457            }
    458        }
    459
    460        Object tmpData = buf;
    461        try {
    462            if (getDatatype().isUnsigned() && unsignedConverted) {
    463                tmpData = convertToUnsignedC(buf);
    464            }
    465            // assume external data files are located in the same directory as the main file.
    466            HDFLibrary.HXsetdir(getFileFormat().getParent());
    467
    468            HDFLibrary.GRwriteimage(id, start, stride, select, tmpData);
    469        }
    470        catch (Exception ex) {
    471            log.debug("write(): failure: ", ex);
    472        }
    473        finally {
    474            tmpData = null;
    475            close(id);
    476        }
    477    }
    478
    479    // ***** need to implement from DataFormat *****
    480    @Override
    481    @SuppressWarnings({"rawtypes", "unchecked"})
    482    public List getMetadata() throws HDFException
    483    {
    484        if (attributeList != null) {
    485            log.trace("getMetadata(): attributeList != null - exit");
    486            return attributeList;
    487        }
    488
    489        long id = open();
    490        String[] objName = {""};
    491        int[] grInfo = new int[4]; //ncomp, data_type, interlace, and num_attrs
    492        int[] idims = new int[2];
    493        try {
    494            HDFLibrary.GRgetiminfo(id, objName, grInfo, idims);
    495            // mask off the litend bit
    496            grInfo[1] = grInfo[1] & (~HDFConstants.DFNT_LITEND);
    497            int n = grInfo[3];
    498
    499            if ((attributeList == null) && (n>0)) {
    500                attributeList = new Vector(n, 5);
    501            }
    502
    503            boolean b = false;
    504            String[] attrName = new String[1];
    505            int[] attrInfo = {0, 0}; // data_type, length
    506            for (int i=0; i<n; i++) {
    507                attrName[0] = "";
    508                try {
    509                    b = HDFLibrary.GRattrinfo(id, i, attrName, attrInfo);
    510                    // mask off the litend bit
    511                    attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND);
    512                }
    513                catch (HDFException ex) {
    514                    log.debug("getMetadata(): GRattrinfo failure: ", ex);
    515                    b = false;
    516                }
    517
    518                if (!b) {
    519                    continue;
    520                }
    521
    522                long[] attrDims = {attrInfo[1]};
    523                Attribute attr = new Attribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims);
    524                attributeList.add(attr);
    525
    526                Object buf = null;
    527                try {
    528                    buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]);
    529                }
    530                catch (OutOfMemoryError e) {
    531                    log.debug("getMetadata(): out of memory: ", e);
    532                    buf = null;
    533                }
    534
    535                try {
    536                    HDFLibrary.GRgetattr(id, i, buf);
    537                }
    538                catch (HDFException ex) {
    539                    log.debug("getMetadata(): GRgetattr failure: ", ex);
    540                    buf = null;
    541                }
    542
    543                if (buf != null) {
    544                    if ((attrInfo[0] == HDFConstants.DFNT_CHAR) ||
    545                        (attrInfo[0] ==  HDFConstants.DFNT_UCHAR8)) {
    546                        buf = Dataset.byteToString((byte[])buf, attrInfo[1]);
    547                    }
    548
    549                    attr.setData(buf);
    550                }
    551            } //  (int i=0; i<n; i++)
    552        }
    553        catch (Exception ex) {
    554            log.debug("getMetadata(): failure: ", ex);
    555        }
    556        finally {
    557            close(id);
    558        }
    559
    560        return attributeList;
    561    }
    562
    563    // ***** need to implement from DataFormat *****
    564    @Override
    565    @SuppressWarnings({"rawtypes", "unchecked"})
    566    public void writeMetadata(Object info) throws Exception
    567    {
    568        // only attribute metadata is supported.
    569        if (!(info instanceof Attribute)) {
    570            log.debug("writeMetadata(): Object not an Attribute - exit");
    571            return;
    572        }
    573
    574        try {
    575            getFileFormat().writeAttribute(this, (Attribute)info, true);
    576
    577            if (attributeList == null) {
    578                attributeList = new Vector();
    579            }
    580
    581            attributeList.add(info);
    582            nAttributes = attributeList.size();
    583        }
    584        catch (Exception ex) {
    585            log.debug("writeMetadata(): failure: ", ex);
    586        }
    587    }
    588
    589    // ***** need to implement from DataFormat *****
    590    @Override
    591    public void removeMetadata(Object info) throws HDFException {
    592        log.trace("removeMetadata(): disabled");
    593    }
    594
    595    // implementing DataFormat
    596    @Override
    597    public void updateMetadata(Object info) throws Exception {
    598        log.trace("updateMetadata(): disabled");
    599    }
    600
    601    // Implementing HObject.
    602    @Override
    603    public long open()
    604    {
    605        log.trace("open(): start: for file={} with ref={}", getFID(), (short) oid[1]);
    606
    607        long id = -1;
    608        try {
    609            int index = HDFLibrary.GRreftoindex(grid, (short)oid[1]);
    610            id = HDFLibrary.GRselect(grid, index);
    611        }
    612        catch (HDFException ex) {
    613            log.debug("open(): failure: ", ex);
    614            id = -1;
    615        }
    616
    617        return id;
    618    }
    619
    620    // Implementing HObject.
    621    @Override
    622    public void close(long grid)
    623    {
    624        try { HDFLibrary.GRendaccess(grid); }
    625        catch (HDFException ex) {log.debug("close(): failure: ", ex);}
    626    }
    627
    628    // Implementing Dataset.
    629    @Override
    630    public void init()
    631    {
    632        if (inited) {
    633            log.trace("init(): Already initialized");
    634            return; // already called. Initialize only once
    635        }
    636
    637        long id = open();
    638        String[] objName = {""};
    639        int[] grInfo = new int[4]; //ncomp, data_type, interlace and num_attrs
    640        int[] idims = new int[2];
    641        try {
    642            HDFLibrary.GRgetiminfo(id, objName, grInfo, idims);
    643            // mask off the litend bit
    644            grInfo[1] = grInfo[1] & (~HDFConstants.DFNT_LITEND);
    645            datatypeID = grInfo[1];
    646
    647            // get compression information
    648            try {
    649                HDFCompInfo compInfo = new HDFCompInfo();
    650                HDFLibrary.GRgetcompinfo(id, compInfo);
    651
    652                compression.setLength(0);
    653
    654                if (compInfo.ctype == HDFConstants.COMP_CODE_DEFLATE) {
    655                    compression.append("GZIP");
    656                }
    657                else if (compInfo.ctype == HDFConstants.COMP_CODE_SZIP) {
    658                    compression.append("SZIP");
    659                }
    660                else if (compInfo.ctype == HDFConstants.COMP_CODE_JPEG) {
    661                    compression.append("JPEG");
    662                }
    663                else if (compInfo.ctype == HDFConstants.COMP_CODE_SKPHUFF) {
    664                    compression.append("SKPHUFF");
    665                }
    666                else if (compInfo.ctype == HDFConstants.COMP_CODE_RLE) {
    667                    compression.append("RLE");
    668                }
    669                else if (compInfo.ctype == HDFConstants.COMP_CODE_NBIT) {
    670                    compression.append("NBIT");
    671                }
    672
    673                if (compression.length() == 0)
    674                    compression.append("NONE");
    675            }
    676            catch (Exception ex) {
    677                log.debug("init(): get compression information failure: ", ex);
    678            }
    679
    680            // get chunk information
    681            try {
    682                HDFChunkInfo chunkInfo = new HDFChunkInfo();
    683                int[] cflag = {HDFConstants.HDF_NONE};
    684                HDFLibrary.GRgetchunkinfo(id, chunkInfo, cflag);
    685
    686                storageLayout.setLength(0);
    687
    688                if (cflag[0] == HDFConstants.HDF_NONE) {
    689                    chunkSize = null;
    690                    storageLayout.append("NONE");
    691                }
    692                else {
    693                    chunkSize = new long[rank];
    694                    for (int i=0; i<rank; i++) {
    695                        chunkSize[i] = chunkInfo.chunk_lengths[i];
    696                    }
    697
    698                    storageLayout.append("CHUNKED: ").append(chunkSize[0]);
    699                    for (int i = 1; i < rank; i++) {
    700                        storageLayout.append(" X ").append(chunkSize[i]);
    701                    }
    702                }
    703            }
    704            catch (Exception ex) {
    705                log.debug("init(): get chunk information failure: ", ex);
    706            }
    707
    708            inited = true;
    709        }
    710        catch (HDFException ex) {
    711            log.debug("init(): failure: ", ex);
    712        }
    713        finally {
    714            close(id);
    715        }
    716
    717        ncomp = grInfo[0];
    718        isTrueColor = (ncomp >= 3);
    719        interlace = grInfo[2];
    720        rank = 2; // support only two dimensional raster image
    721
    722        // data in HDF4 GR image is arranged as dim[0]=width, dim[1]=height.
    723        // other image data is arranged as dim[0]=height, dim[1]=width.
    724        selectedIndex[0] = 1;
    725        selectedIndex[1] = 0;
    726
    727        dims = new long[rank];
    728        startDims = new long[rank];
    729        selectedDims = new long[rank];
    730        for (int i=0; i<rank; i++) {
    731            startDims[i] = 0;
    732            selectedDims[i] = idims[i];
    733            dims[i] = idims[i];
    734        }
    735    }
    736
    737    // ***** need to implement from ScalarDS *****
    738    @Override
    739    public byte[][] getPalette()
    740    {
    741        if (palette != null) {
    742            log.trace("getPalette(): palette != null - exit");
    743            return palette;
    744        }
    745
    746        long id = open();
    747        if (id < 0) {
    748            log.debug("getPalette(): Invalid ID - exit");
    749            return null;
    750        }
    751
    752        // get palette info.
    753        long lutid  = -1;
    754        int[] lutInfo = new int[4]; //ncomp, datatype, interlace, num_entries
    755        try {
    756            // find the first palette.
    757            // Todo: get all the palettes
    758            lutid = HDFLibrary.GRgetlutid(id, 0);
    759            HDFLibrary.GRgetlutinfo(lutid, lutInfo);
    760        }
    761        catch (HDFException ex) {
    762            log.debug("getPalette(): exit with failure: ", ex);
    763            close(id);
    764            return null;
    765        }
    766
    767        // check if there is palette data. HDFLibrary.GRgetlutinfo() sometimes
    768        // return true even if there is no palette data, and check if it is a
    769        // RGB with 256 colors
    770        if ((lutInfo[0] != 3) || (lutInfo[2] < 0) || (lutInfo[3] != 256)) {
    771            close(id);
    772            log.debug("getPalette(): no palette data - exit");
    773            return null;
    774        }
    775
    776        // read palette data
    777        boolean b = false;
    778        byte[] pal = new byte[3*256];
    779        try
    780        {
    781            HDFLibrary.GRreqlutil(id, lutInfo[2]);
    782            b = HDFLibrary.GRreadlut(lutid, pal);
    783        }
    784        catch (HDFException ex) {
    785            log.debug("getPalette(): failure: ", ex);
    786            b = false;
    787        }
    788
    789        if (!b) {
    790            close(id);
    791            log.debug("getPalette(): no palette data - exit");
    792            return null;
    793        }
    794
    795        palette = new byte[3][256];
    796        if (lutInfo[2] == HDFConstants.MFGR_INTERLACE_PIXEL) {
    797            // color conponents are arranged in RGB, RGB, RGB, ...
    798            for (int i=0; i<256; i++) {
    799                palette[0][i] = pal[i*3];
    800                palette[1][i] = pal[i*3+1];
    801                palette[2][i] = pal[i*3+2];
    802            }
    803        }
    804        else {
    805            for (int i=0; i<256; i++) {
    806                palette[0][i] = pal[i];
    807                palette[1][i] = pal[256+i];
    808                palette[2][i] = pal[512+i];
    809            }
    810        }
    811
    812        close(id);
    813
    814        return palette;
    815    }
    816
    817    /**
    818     * Returns the number of components of this image data.
    819     *
    820     * @return the number of components
    821     */
    822    public int getComponentCount()
    823    {
    824        return ncomp;
    825    }
    826
    827    /**
    828     * Creates a new image.
    829     *
    830     * @param name the name of the dataset to create.
    831     * @param pgroup the parent group of the new dataset.
    832     * @param type the datatype of the dataset.
    833     * @param dims the dimension size of the dataset.
    834     * @param maxdims the max dimension size of the dataset.
    835     * @param chunks the chunk size of the dataset.
    836     * @param gzip the level of the gzip compression.
    837     * @param ncomp number of components of the image data.
    838     * @param interlace the interlace mode.
    839     * @param data the array of data values.
    840     *
    841     * @return the new image if successful. Otherwise returns null.
    842     *
    843     * @throws Exception if the image can not be created
    844     */
    845    public static H4GRImage create(
    846        String name,
    847        Group pgroup,
    848        Datatype type,
    849        long[] dims,
    850        long[] maxdims,
    851        long[] chunks,
    852        int gzip,
    853        int ncomp,
    854        int interlace,
    855        Object data) throws Exception
    856    {
    857        log.trace("create(): start: name={} parentGroup={} type={} gzip={} ncomp={} interlace={}", name, pgroup, type, gzip, ncomp, interlace);
    858
    859        H4GRImage dataset = null;
    860        if ((name == null) ||
    861            (pgroup == null) ||
    862            (dims == null) ||
    863            ((gzip>0) && (chunks==null))) {
    864            log.debug("create(): one or more parameters are null - exit");
    865            return null;
    866        }
    867
    868        H4File file = (H4File)pgroup.getFileFormat();
    869        if (file == null) {
    870            log.debug("create(): Parent group FileFormat is null - exit");
    871            return null;
    872        }
    873
    874        String path = HObject.SEPARATOR;
    875        if (!pgroup.isRoot()) {
    876            path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR;
    877        }
    878        if (interlace == ScalarDS.INTERLACE_PLANE) {
    879            interlace = HDFConstants.MFGR_INTERLACE_COMPONENT;
    880        }
    881        else {
    882            interlace = HDFConstants.MFGR_INTERLACE_PIXEL;
    883        }
    884
    885        int rank = 2;
    886        int[] idims = new int[rank];
    887        int[] imaxdims = new int[rank];
    888        int[] start = new int[rank];
    889        for (int i=0; i<rank; i++) {
    890            idims[i] = (int)dims[i];
    891            if (maxdims != null) {
    892                imaxdims[i] = (int)maxdims[i];
    893            }
    894            else {
    895                imaxdims[i] = idims[i];
    896            }
    897            start[i] = 0;
    898        }
    899
    900        int[] ichunks = null;
    901        if (chunks != null) {
    902            ichunks = new int[rank];
    903            for (int i=0; i<rank; i++) {
    904                ichunks[i] = (int)chunks[i];
    905            }
    906        }
    907
    908        long grid = -1;
    909        long vgid = -1;
    910        long gid = (file).getGRAccessID();
    911        long tid = type.createNative();
    912
    913        if(tid >= 0) {
    914            try {
    915                grid = HDFLibrary.GRcreate(gid, name, ncomp, tid, interlace, idims);
    916            }
    917            catch (Exception ex) {
    918                log.debug("create(): exit with failure: ", ex);
    919                throw (ex);
    920            }
    921        }
    922
    923        if (grid < 0) {
    924            log.debug("create(): Invalid GR ID - exit");
    925            throw (new HDFException("Unable to create the new dataset."));
    926        }
    927
    928        if ((grid > 0) && (data != null)) {
    929            HDFLibrary.GRwriteimage(grid, start, null, idims, data);
    930        }
    931
    932        if (chunks != null) {
    933            // set chunk
    934            HDFChunkInfo chunkInfo = new HDFChunkInfo(ichunks);
    935            HDFLibrary.GRsetchunk(grid, chunkInfo, HDFConstants.HDF_CHUNK);
    936        }
    937
    938        if (gzip > 0) {
    939            // set compression
    940            int compType = HDFConstants.COMP_CODE_DEFLATE;
    941            HDFDeflateCompInfo compInfo = new HDFDeflateCompInfo();
    942            compInfo.level = gzip;
    943            HDFLibrary.GRsetcompress(grid, compType, compInfo);
    944        }
    945
    946        int ref = HDFLibrary.GRidtoref(grid);
    947
    948        if (!pgroup.isRoot()) {
    949            // add the dataset to the parent group
    950            vgid = pgroup.open();
    951            if (vgid < 0) {
    952                if (grid > 0) {
    953                    HDFLibrary.GRendaccess(grid);
    954                }
    955                log.debug("create(): Invalid VG ID - exit");
    956                throw (new HDFException("Unable to open the parent group."));
    957            }
    958
    959            HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_RI, ref);
    960
    961            pgroup.close(vgid);
    962        }
    963
    964        try {
    965            if (grid > 0) {
    966                HDFLibrary.GRendaccess(grid);
    967            }
    968        }
    969        catch (Exception ex) {
    970            log.debug("create(): GRendaccess failure: ", ex);
    971        }
    972
    973        long[] oid = {HDFConstants.DFTAG_NDG, ref};
    974        dataset = new H4GRImage(file, name, path, oid);
    975
    976        if (dataset != null) {
    977            pgroup.addToMemberList(dataset);
    978        }
    979
    980        return dataset;
    981    }
    982
    983    /**
    984     * copy attributes from one GR image to another GR image
    985     */
    986    private void copyAttribute(long srcdid, long dstdid, int numberOfAttributes)
    987    {
    988        log.trace("copyAttribute(): start: srcdid={} dstdid={} numAttributes={}", srcdid, dstdid, numberOfAttributes);
    989
    990        if (numberOfAttributes <= 0) {
    991            log.debug("copyAttribute(): numberOfAttributes={}", numberOfAttributes);
    992            return;
    993        }
    994
    995        try {
    996            boolean b = false;
    997            String[] attrName = new String[1];
    998            int[] attrInfo = {0, 0};
    999            for (int i=0; i<numberOfAttributes; i++) {
    1000                attrName[0] = "";
    1001                try {
    1002                    b = HDFLibrary.GRattrinfo(srcdid, i, attrName, attrInfo);
    1003                }
    1004                catch (HDFException ex) {
    1005                    log.trace("copyAttribute(): attribute[{}] GRattrinfo failure: ", i, ex);
    1006                    b = false;
    1007                }
    1008
    1009                if (!b) {
    1010                    continue;
    1011                }
    1012
    1013                // read attribute data from source dataset
    1014                byte[] attrBuff = new byte[attrInfo[1] * HDFLibrary.DFKNTsize(attrInfo[0])];
    1015                try {
    1016                    HDFLibrary.GRgetattr(srcdid, i, attrBuff);
    1017                }
    1018                catch (Exception ex) {
    1019                    log.trace("copyAttribute(): attribute[{}] GRgetattr failure: ", i, ex);
    1020                    attrBuff = null;
    1021                }
    1022
    1023                if (attrBuff == null) {
    1024                    log.debug("copyAttribute(): attrBuff[{}] is null continue", i);
    1025                    continue;
    1026                }
    1027
    1028                // attach attribute to the destination dataset
    1029                HDFLibrary.GRsetattr(dstdid, attrName[0], attrInfo[0], attrInfo[1], attrBuff);
    1030            } //  (int i=0; i<numberOfAttributes; i++)
    1031        }
    1032        catch (Exception ex) {
    1033            log.debug("copyAttribute(): failure: ", ex);
    1034        }
    1035    }
    1036
    1037    //Implementing DataFormat
    1038    @SuppressWarnings("rawtypes")
    1039    public List getMetadata(int... attrPropList) throws Exception {
    1040        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    1041    }
    1042}