    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 final static 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, dstdid=-1;
    200        String path=null;
    201        int[] count=null;
    202
    203        if (pgroup == null) {
    204            log.debug("copy(): Parent group is null");
    205            log.trace("copy(): finish");
    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");
    219            log.trace("copy(): finish");
    220            return null;
    221        }
    222
    223        if (dims != null) {
    224            count = new int[2];
    225            count[0] = (int)dims[0];
    226            count[1] = (int)dims[1];
    227        }
    228
    229        int[] grInfo = new int[4]; //ncomp, data_type, interlace and num_attrs
    230        try {
    231            String[] tmpName = {""};
    232            int[] tmpDims = new int[2];
    233            HDFLibrary.GRgetiminfo(srcdid, tmpName, grInfo, tmpDims);
    234            if (count == null) {
    235                count = tmpDims;
    236            }
    237        }
    238        catch (HDFException ex) {
    239            log.debug("copy(): GRgetiminfo failure: ", ex);
    240        }
    241
    242        int ncomp = grInfo[0];
    243        long tid = grInfo[1];
    244        int interlace = grInfo[2];
    245        int numberOfAttributes = grInfo[3];
    246        dstdid = HDFLibrary.GRcreate(
    247                ((H4File)pgroup.getFileFormat()).getGRAccessID(),
    248                dname, ncomp, tid, interlace, count);
    249        if (dstdid < 0) {
    250            log.debug("copy(): Invalid dest dataset ID");
    251            log.trace("copy(): finish");
    252            return null;
    253        }
    254
    255        int ref = HDFLibrary.GRidtoref(dstdid);
    256        if (!pgroup.isRoot()) {
    257            long vgid = pgroup.open();
    258            HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_RIG, ref);
    259            pgroup.close(vgid);
    260        }
    261
    262        // read data from the source dataset
    263        int[] start = {0, 0};
    264        if (buff == null) {
    265            buff = new byte[count[0]*count[1] * HDFLibrary.DFKNTsize(tid)];
    266            HDFLibrary.GRreadimage(srcdid, start, null, count, buff);
    267        }
    268
    269        // write the data into the destination dataset
    270        HDFLibrary.GRwriteimage(dstdid, start, null, count, buff);
    271
    272        // copy palette
    273        long pid = HDFLibrary.GRgetlutid(srcdid, 0);
    274        int[] palInfo = new int[4];
    275
    276        HDFLibrary.GRgetlutinfo(pid, palInfo);
    277        palInfo[1] = HDFConstants.DFNT_UINT8; // support unsigned byte only. Other type does not work
    278        int palSize = palInfo[0]*palInfo[3];
    279        byte[] palBuff = new byte[palSize];
    280        HDFLibrary.GRreadlut(pid, palBuff);
    281        pid = HDFLibrary.GRgetlutid(dstdid, 0);
    282        HDFLibrary.GRwritelut(pid, palInfo[0], palInfo[1], palInfo[2], palInfo[3], palBuff);
    283
    284        // copy attributes from one object to the new object
    285        log.trace("copy(): copyAttributes: numAttributes={}", numberOfAttributes);
    286        copyAttribute(srcdid, dstdid, numberOfAttributes);
    287
    288        long[] oid = {HDFConstants.DFTAG_RIG, ref};
    289        dataset = new H4GRImage(pgroup.getFileFormat(), dname, path, oid);
    290
    291        pgroup.addToMemberList(dataset);
    292
    293        close(srcdid);
    294
    295        try {
    296            HDFLibrary.GRendaccess(dstdid);
    297        }
    298        catch (HDFException ex) {
    299            log.debug("copy(): GRendaccess failure: ", ex);
    300        }
    301
    302        log.trace("copy(): finish");
    303        return dataset;
    304    }
    305
    306    // ***** need to implement from ScalarDS *****
    307    @Override
    308    public byte[][] readPalette(int idx) { return null;}
    309
    310    // ***** need to implement from ScalarDS *****
    311    @Override
    312    public byte[] getPaletteRefs() { return null;}
    313
    314    // implementing ScalarDS
    315    @Override
    316    public Datatype getDatatype()
    317    {
    318        if (datatype == null) {
    319            datatype = new H4Datatype(datatypeID);
    320        }
    321
    322        return datatype;
    323    }
    324
    325    // Implementing Dataset
    326    @Override
    327    public byte[] readBytes() throws HDFException
    328    {
    329        log.trace("readBytes(): start");
    330
    331        byte[] theData = null;
    332
    333        if (!isInited()) init();
    334
    335        long id = open();
    336        if (id < 0) {
    337            log.debug("readBytes(): Invalid ID");
    338            log.trace("readBytes(): finish");
    339            return null;
    340        }
    341
    342        try {
    343            // set the interlacing scheme for reading image data
    344            HDFLibrary.GRreqimageil(id, interlace);
    345            int datasize = (int)(getWidth()*getHeight()*ncomp);
    346            int size = HDFLibrary.DFKNTsize(datatypeID)*datasize;
    347            theData = new byte[size];
    348            int[] start = {(int)startDims[0], (int)startDims[1]};
    349            int[] select = {(int)selectedDims[0], (int)selectedDims[1]};
    350
    351            int[] stride = null;
    352            if (selectedStride != null) {
    353                stride = new int[rank];
    354                for (int i=0; i<rank; i++) {
    355                    stride[i] = (int)selectedStride[i];
    356                }
    357            }
    358
    359            HDFLibrary.GRreadimage(id, start, stride, select, theData);
    360        }
    361        catch (Exception ex) {
    362            log.debug("readBytes(): failure: ", ex);
    363        }
    364        finally {
    365            close(id);
    366        }
    367
    368        log.trace("readBytes(): finish");
    369        return theData;
    370    }
    371
    372    // ***** need to implement from DataFormat *****
    373    @Override
    374    public Object read() throws HDFException
    375    {
    376        log.trace("read(): start");
    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            log.trace("read(): finish");
    386            return null;
    387        }
    388
    389        try {
    390            // set the interlacing scheme for reading image data
    391            HDFLibrary.GRreqimageil(id, interlace);
    392            int datasize = (int)(getWidth()*getHeight()*ncomp);
    393
    394            theData = H4Datatype.allocateArray(datatypeID, datasize);
    395
    396            if (theData != null) {
    397                // assume external data files are located in the same directory as the main file.
    398                HDFLibrary.HXsetdir(getFileFormat().getParent());
    399
    400                int[] start = {(int)startDims[0], (int)startDims[1]};
    401                int[] select = {(int)selectedDims[0], (int)selectedDims[1]};
    402
    403                int[] stride = null;
    404                if (selectedStride != null) {
    405                    stride = new int[rank];
    406                    for (int i=0; i<rank; i++) {
    407                        stride[i] = (int)selectedStride[i];
    408                    }
    409                }
    410
    411                HDFLibrary.GRreadimage(id, start, stride, select, theData);
    412            }
    413        }
    414        catch (Exception ex) {
    415            log.debug("read(): failure: ", ex);
    416        }
    417        finally {
    418            close(id);
    419        }
    420
    421        if ( (rank >1) && (selectedIndex[1]>selectedIndex[0]))
    422            isDefaultImageOrder = false;
    423        else
    424            isDefaultImageOrder = true;
    425
    426        log.trace("read(): isDefaultImageOrder={}", isDefaultImageOrder);
    427        log.trace("read(): finish");
    428        return theData;
    429    }
    430
    431    // Implementing DataFormat
    432    @SuppressWarnings("deprecation")
    433    @Override
    434    public void write(Object buf) throws HDFException
    435    {
    436        log.trace("write(): start");
    437
    438        if (buf == null) {
    439            log.debug("write(): buf is null");
    440            log.trace("write(): finish");
    441            return;
    442        }
    443
    444        long id = open();
    445        if (id < 0) {
    446            log.debug("write(): Invalid ID");
    447            log.trace("write(): finish");
    448            return;
    449        }
    450
    451        int[] select = new int[rank];
    452        int[] start = new int[rank];
    453        for (int i=0; i<rank; i++) {
    454            select[i] = (int)selectedDims[i];
    455            start[i] = (int)startDims[i];
    456        }
    457
    458        int[] stride = null;
    459        if (selectedStride != null) {
    460            stride = new int[rank];
    461            for (int i=0; i<rank; i++) {
    462                stride[i] = (int)selectedStride[i];
    463            }
    464        }
    465
    466        Object tmpData = buf;
    467        try {
    468            if (getDatatype().isUnsigned() && unsignedConverted) {
    469                tmpData = convertToUnsignedC(buf);
    470            }
    471            // assume external data files are located in the same directory as the main file.
    472            HDFLibrary.HXsetdir(getFileFormat().getParent());
    473
    474            HDFLibrary.GRwriteimage(id, start, stride, select, tmpData);
    475        }
    476        catch (Exception ex) {
    477            log.debug("write(): failure: ", ex);
    478        }
    479        finally {
    480            tmpData = null;
    481            close(id);
    482        }
    483
    484        log.trace("write(): finish");
    485    }
    486
    487    // ***** need to implement from DataFormat *****
    488    @Override
    489    @SuppressWarnings({"rawtypes", "unchecked"})
    490    public List getMetadata() throws HDFException
    491    {
    492        log.trace("getMetadata(): start");
    493
    494        if (attributeList != null) {
    495            log.trace("getMetadata(): attributeList != null");
    496            log.trace("getMetadata(): finish");
    497            return attributeList;
    498        }
    499
    500        long id = open();
    501        String[] objName = {""};
    502        int[] grInfo = new int[4]; //ncomp, data_type, interlace, and num_attrs
    503        int[] idims = new int[2];
    504        try {
    505            HDFLibrary.GRgetiminfo(id, objName, grInfo, idims);
    506            // mask off the litend bit
    507            grInfo[1] = grInfo[1] & (~HDFConstants.DFNT_LITEND);
    508            int n = grInfo[3];
    509
    510            if ((attributeList == null) && (n>0)) {
    511                attributeList = new Vector(n, 5);
    512            }
    513
    514            boolean b = false;
    515            String[] attrName = new String[1];
    516            int[] attrInfo = {0, 0}; // data_type, length
    517            for (int i=0; i<n; i++) {
    518                attrName[0] = "";
    519                try {
    520                    b = HDFLibrary.GRattrinfo(id, i, attrName, attrInfo);
    521                    // mask off the litend bit
    522                    attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND);
    523                }
    524                catch (HDFException ex) {
    525                    log.debug("getMetadata(): GRattrinfo failure: ", ex);
    526                    b = false;
    527                }
    528
    529                if (!b) {
    530                    continue;
    531                }
    532
    533                long[] attrDims = {attrInfo[1]};
    534                Attribute attr = new Attribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims);
    535                attributeList.add(attr);
    536
    537                Object buf = null;
    538                try {
    539                    buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]);
    540                }
    541                catch (OutOfMemoryError e) {
    542                    log.debug("getMetadata(): out of memory: ", e);
    543                    buf = null;
    544                }
    545
    546                try {
    547                    HDFLibrary.GRgetattr(id, i, buf);
    548                }
    549                catch (HDFException ex) {
    550                    log.debug("getMetadata(): GRgetattr failure: ", ex);
    551                    buf = null;
    552                }
    553
    554                if (buf != null) {
    555                    if ((attrInfo[0] == HDFConstants.DFNT_CHAR) ||
    556                        (attrInfo[0] ==  HDFConstants.DFNT_UCHAR8)) {
    557                        buf = Dataset.byteToString((byte[])buf, attrInfo[1]);
    558                    }
    559
    560                    attr.setData(buf);
    561                }
    562            } // for (int i=0; i<n; i++)
    563        }
    564        catch (Exception ex) {
    565            log.debug("getMetadata(): failure: ", ex);
    566        }
    567        finally {
    568            close(id);
    569        }
    570
    571        log.trace("getMetadata(): finish");
    572        return attributeList;
    573    }
    574
    575    // ***** need to implement from DataFormat *****
    576    @Override
    577    @SuppressWarnings({"rawtypes", "unchecked"})
    578    public void writeMetadata(Object info) throws Exception
    579    {
    580        log.trace("writeMetadata(): start");
    581
    582        // only attribute metadata is supported.
    583        if (!(info instanceof Attribute)) {
    584            log.debug("writeMetadata(): Object not an Attribute");
    585            log.trace("writeMetadata(): finish");
    586            return;
    587        }
    588
    589        try {
    590            getFileFormat().writeAttribute(this, (Attribute)info, true);
    591
    592            if (attributeList == null) {
    593                attributeList = new Vector();
    594            }
    595
    596            attributeList.add(info);
    597            nAttributes = attributeList.size();
    598        }
    599        catch (Exception ex) {
    600            log.debug("writeMetadata(): failure: ", ex);
    601        }
    602
    603        log.trace("writeMetadata(): finish");
    604    }
    605
    606    // ***** need to implement from DataFormat *****
    607    @Override
    608    public void removeMetadata(Object info) throws HDFException {
    609        log.trace("removeMetadata(): disabled");
    610    }
    611
    612    // implementing DataFormat
    613    @Override
    614    public void updateMetadata(Object info) throws Exception {
    615        log.trace("updateMetadata(): disabled");
    616    }
    617
    618    // Implementing HObject.
    619    @Override
    620    public long open()
    621    {
    622        log.trace("open(): start: for file={} with ref={}", getFID(), (short) oid[1]);
    623
    624        long id = -1;
    625        try {
    626            int index = HDFLibrary.GRreftoindex(grid, (short)oid[1]);
    627            id = HDFLibrary.GRselect(grid, index);
    628        }
    629        catch (HDFException ex) {
    630            log.debug("open(): failure: ", ex);
    631            id = -1;
    632        }
    633
    634        log.trace("open(): finish");
    635        return id;
    636    }
    637
    638    // Implementing HObject.
    639    @Override
    640    public void close(long grid)
    641    {
    642        try { HDFLibrary.GRendaccess(grid); }
    643        catch (HDFException ex) {log.debug("close(): failure: ", ex);}
    644    }
    645
    646    // Implementing Dataset.
    647    @Override
    648    public void init()
    649    {
    650        log.trace("init(): start");
    651
    652        if (inited) {
    653            log.trace("init(): Already initialized");
    654            log.trace("init(): finish");
    655            return; // already called. Initialize only once
    656        }
    657
    658        long id = open();
    659        String[] objName = {""};
    660        int[] grInfo = new int[4]; //ncomp, data_type, interlace and num_attrs
    661        int[] idims = new int[2];
    662        try {
    663            HDFLibrary.GRgetiminfo(id, objName, grInfo, idims);
    664            // mask off the litend bit
    665            grInfo[1] = grInfo[1] & (~HDFConstants.DFNT_LITEND);
    666            datatypeID = grInfo[1];
    667
    668            // get compression information
    669            try {
    670                HDFCompInfo compInfo = new HDFCompInfo();
    671                HDFLibrary.GRgetcompinfo(id, compInfo);
    672                if (compInfo.ctype == HDFConstants.COMP_CODE_DEFLATE) {
    673                    compression = "GZIP";
    674                }
    675                else if (compInfo.ctype == HDFConstants.COMP_CODE_SZIP) {
    676                    compression = "SZIP";
    677                }
    678                else if (compInfo.ctype == HDFConstants.COMP_CODE_JPEG) {
    679                    compression = "JPEG";
    680                }
    681                else if (compInfo.ctype == HDFConstants.COMP_CODE_SKPHUFF) {
    682                    compression = "SKPHUFF";
    683                }
    684                else if (compInfo.ctype == HDFConstants.COMP_CODE_RLE) {
    685                    compression = "RLE";
    686                }
    687                else if (compInfo.ctype == HDFConstants.COMP_CODE_NBIT) {
    688                    compression = "NBIT";
    689                }
    690            }
    691            catch (Exception ex) {
    692                log.debug("init(): get compression information failure: ", ex);
    693            }
    694
    695            // get chunk information
    696            try {
    697                HDFChunkInfo chunkInfo = new HDFChunkInfo();
    698                int[] cflag = {HDFConstants.HDF_NONE};
    699                HDFLibrary.GRgetchunkinfo(id, chunkInfo, cflag);
    700                if (cflag[0] == HDFConstants.HDF_NONE) {
    701                    chunkSize = null;
    702                    storage_layout = "NONE";
    703                }
    704                else {
    705                    chunkSize = new long[rank];
    706                    for (int i=0; i<rank; i++) {
    707                        chunkSize[i] = chunkInfo.chunk_lengths[i];
    708                    }
    709                    storage_layout = "CHUNKED: " + String.valueOf(chunkSize[0]);
    710                    for (int i = 1; i < rank; i++) {
    711                        storage_layout += " X " + chunkSize[i];
    712                    }
    713                }
    714            }
    715            catch (Exception ex) {
    716                log.debug("init(): get chunk information failure: ", ex);
    717            }
    718
    719            inited = true;
    720        }
    721        catch (HDFException ex) {
    722            log.debug("init(): failure: ", ex);
    723        }
    724        finally {
    725            close(id);
    726        }
    727
    728        ncomp = grInfo[0];
    729        isTrueColor = (ncomp >= 3);
    730        interlace = grInfo[2];
    731        rank = 2; // support only two dimensional raster image
    732
    733        // data in HDF4 GR image is arranged as dim[0]=width, dim[1]=height.
    734        // other image data is arranged as dim[0]=height, dim[1]=width.
    735        selectedIndex[0] = 1;
    736        selectedIndex[1] = 0;
    737
    738        dims = new long[rank];
    739        startDims = new long[rank];
    740        selectedDims = new long[rank];
    741        for (int i=0; i<rank; i++) {
    742            startDims[i] = 0;
    743            selectedDims[i] = idims[i];
    744            dims[i] = idims[i];
    745        }
    746
    747        log.trace("init(): finish");
    748    }
    749
    750    // ***** need to implement from ScalarDS *****
    751    @Override
    752    public byte[][] getPalette()
    753    {
    754        log.trace("getPalette(): start");
    755
    756        if (palette != null) {
    757            log.trace("getPalette(): palette != null");
    758            log.trace("getPalette(): finish");
    759            return palette;
    760        }
    761
    762        long id = open();
    763        if (id < 0) {
    764            log.debug("getPalette(): Invalid ID");
    765            log.trace("getPalette(): finish");
    766            return null;
    767        }
    768
    769        // get palette info.
    770        long lutid  = -1;
    771        int[] lutInfo = new int[4]; //ncomp, datatype, interlace, num_entries
    772        try {
    773            // find the first palette.
    774            // Todo: get all the palettes
    775            lutid = HDFLibrary.GRgetlutid(id, 0);
    776            HDFLibrary.GRgetlutinfo(lutid, lutInfo);
    777        }
    778        catch (HDFException ex) {
    779            log.debug("getPalette(): failure: ", ex);
    780            close(id);
    781            log.trace("getPalette(): finish");
    782            return null;
    783        }
    784
    785        // check if there is palette data. HDFLibrary.GRgetlutinfo() sometimes
    786        // return true even if there is no palette data, and check if it is a
    787        // RGB with 256 colors
    788        if ((lutInfo[0] != 3) || (lutInfo[2] < 0) | (lutInfo[3] != 256)) {
    789            close(id);
    790            log.debug("getPalette(): no palette data");
    791            log.trace("getPalette(): finish");
    792            return null;
    793        }
    794
    795        // read palette data
    796        boolean b = false;
    797        byte[] pal = new byte[3*256];
    798        try
    799        {
    800            HDFLibrary.GRreqlutil(id, lutInfo[2]);
    801            b = HDFLibrary.GRreadlut(lutid, pal);
    802        }
    803        catch (HDFException ex) {
    804            log.debug("getPalette(): failure: ", ex);
    805            b = false;
    806        }
    807
    808        if (!b) {
    809            close(id);
    810            log.debug("getPalette(): no palette data");
    811            log.trace("getPalette(): finish");
    812            return null;
    813        }
    814
    815        palette = new byte[3][256];
    816        if (lutInfo[2] == HDFConstants.MFGR_INTERLACE_PIXEL) {
    817            // color conponents are arranged in RGB, RGB, RGB, ...
    818            for (int i=0; i<256; i++) {
    819                palette[0][i] = pal[i*3];
    820                palette[1][i] = pal[i*3+1];
    821                palette[2][i] = pal[i*3+2];
    822            }
    823        }
    824        else {
    825            for (int i=0; i<256; i++) {
    826                palette[0][i] = pal[i];
    827                palette[1][i] = pal[256+i];
    828                palette[2][i] = pal[512+i];
    829            }
    830        }
    831
    832        close(id);
    833
    834        log.trace("getPalette(): finish");
    835        return palette;
    836    }
    837
    838    /**
    839     * Returns the number of components of this image data.
    840     *
    841     * @return the number of components
    842     */
    843    public int getComponentCount()
    844    {
    845        return ncomp;
    846    }
    847
    848    /**
    849     * Creates a new image.
    850     *
    851     * @param name the name of the dataset to create.
    852     * @param pgroup the parent group of the new dataset.
    853     * @param type the datatype of the dataset.
    854     * @param dims the dimension size of the dataset.
    855     * @param maxdims the max dimension size of the dataset.
    856     * @param chunks the chunk size of the dataset.
    857     * @param gzip the level of the gzip compression.
    858     * @param ncomp number of components of the image data.
    859     * @param interlace the interlace mode.
    860     * @param data the array of data values.
    861     *
    862     * @return the new image if successful. Otherwise returns null.
    863     *
    864     * @throws Exception if the image can not be created
    865     */
    866    public static H4GRImage create(
    867        String name,
    868        Group pgroup,
    869        Datatype type,
    870        long[] dims,
    871        long[] maxdims,
    872        long[] chunks,
    873        int gzip,
    874        int ncomp,
    875        int interlace,
    876        Object data) throws Exception
    877    {
    878        log.trace("create(): start: name={} parentGroup={} type={} gzip={} ncomp={} interlace={}", name, pgroup, type, gzip, ncomp, interlace);
    879
    880        H4GRImage dataset = null;
    881        if ((name == null) ||
    882            (pgroup == null) ||
    883            (dims == null) ||
    884            ((gzip>0) && (chunks==null))) {
    885            log.debug("create(): one or more parameters are null");
    886            log.trace("create(): finish");
    887            return null;
    888        }
    889
    890        H4File file = (H4File)pgroup.getFileFormat();
    891        if (file == null) {
    892            log.debug("create(): Parent group FileFormat is null");
    893            log.trace("create(): finish");
    894            return null;
    895        }
    896
    897        String path = HObject.separator;
    898        if (!pgroup.isRoot()) {
    899            path = pgroup.getPath()+pgroup.getName()+HObject.separator;
    900        }
    901        if (interlace == ScalarDS.INTERLACE_PLANE) {
    902            interlace = HDFConstants.MFGR_INTERLACE_COMPONENT;
    903        }
    904        else {
    905            interlace = HDFConstants.MFGR_INTERLACE_PIXEL;
    906        }
    907
    908        int rank = 2;
    909        int idims[] = new int[rank];
    910        int imaxdims[] = new int[rank];
    911        int start[] = new int [rank];
    912        for (int i=0; i<rank; i++) {
    913            idims[i] = (int)dims[i];
    914            if (maxdims != null) {
    915                imaxdims[i] = (int)maxdims[i];
    916            }
    917            else {
    918                imaxdims[i] = idims[i];
    919            }
    920            start[i] = 0;
    921        }
    922
    923        int ichunks[] = null;
    924        if (chunks != null) {
    925            ichunks = new int[rank];
    926            for (int i=0; i<rank; i++) {
    927                ichunks[i] = (int)chunks[i];
    928            }
    929        }
    930
    931        long grid = -1;
    932        long vgid = -1;
    933        long gid = (file).getGRAccessID();
    934        long tid = type.createNative();
    935
    936        if(tid >= 0) {
    937            try {
    938                grid = HDFLibrary.GRcreate(gid, name, ncomp, tid, interlace, idims);
    939            }
    940            catch (Exception ex) {
    941                log.debug("create(): failure: ", ex);
    942                log.trace("create(): finish");
    943                throw (ex);
    944            }
    945        }
    946
    947        if (grid < 0) {
    948            log.debug("create(): Invalid GR ID");
    949            log.trace("create(): finish");
    950            throw (new HDFException("Unable to create the new dataset."));
    951        }
    952
    953        if ((grid > 0) && (data != null)) {
    954            HDFLibrary.GRwriteimage(grid, start, null, idims, data);
    955        }
    956
    957        if (chunks != null) {
    958            // set chunk
    959            HDFChunkInfo chunkInfo = new HDFChunkInfo(ichunks);
    960            HDFLibrary.GRsetchunk(grid, chunkInfo, HDFConstants.HDF_CHUNK);
    961        }
    962
    963        if (gzip > 0) {
    964            // set compression
    965            int compType = HDFConstants.COMP_CODE_DEFLATE;
    966            HDFDeflateCompInfo compInfo = new HDFDeflateCompInfo();
    967            compInfo.level = gzip;
    968            HDFLibrary.GRsetcompress(grid, compType, compInfo);
    969        }
    970
    971        int ref = HDFLibrary.GRidtoref(grid);
    972
    973        if (!pgroup.isRoot()) {
    974            // add the dataset to the parent group
    975            vgid = pgroup.open();
    976            if (vgid < 0) {
    977                if (grid > 0) {
    978                    HDFLibrary.GRendaccess(grid);
    979                }
    980                log.debug("create(): Invalid VG ID");
    981                log.trace("create(): finish");
    982                throw (new HDFException("Unable to open the parent group."));
    983            }
    984
    985            HDFLibrary.Vaddtagref(vgid, HDFConstants.DFTAG_RI, ref);
    986
    987            pgroup.close(vgid);
    988        }
    989
    990        try {
    991            if (grid > 0) {
    992                HDFLibrary.GRendaccess(grid);
    993            }
    994        }
    995        catch (Exception ex) {
    996            log.debug("create(): GRendaccess failure: ", ex);
    997        }
    998
    999        long[] oid = {HDFConstants.DFTAG_NDG, ref};
    1000        dataset = new H4GRImage(file, name, path, oid);
    1001
    1002        if (dataset != null) {
    1003            pgroup.addToMemberList(dataset);
    1004        }
    1005
    1006        log.trace("create(): finish");
    1007        return dataset;
    1008    }
    1009
    1010    /**
    1011     * copy attributes from one GR image to another GR image
    1012     */
    1013    private void copyAttribute(long srcdid, long dstdid, int numberOfAttributes)
    1014    {
    1015        log.trace("copyAttribute(): start: srcdid={} dstdid={} numAttributes={}", srcdid, dstdid, numberOfAttributes);
    1016
    1017        if (numberOfAttributes <= 0) {
    1018            log.debug("copyAttribute(): numberOfAttributes={}", numberOfAttributes);
    1019            log.trace("copyAttribute(): finish");
    1020            return;
    1021        }
    1022
    1023        try {
    1024            boolean b = false;
    1025            String[] attrName = new String[1];
    1026            int[] attrInfo = {0, 0};
    1027            for (int i=0; i<numberOfAttributes; i++) {
    1028                attrName[0] = "";
    1029                try {
    1030                    b = HDFLibrary.GRattrinfo(srcdid, i, attrName, attrInfo);
    1031                }
    1032                catch (HDFException ex) {
    1033                    log.trace("copyAttribute(): attribute[{}] GRattrinfo failure: ", i, ex);
    1034                    b = false;
    1035                }
    1036
    1037                if (!b) {
    1038                    continue;
    1039                }
    1040
    1041                // read attribute data from source dataset
    1042                byte[] attrBuff = new byte[attrInfo[1] * HDFLibrary.DFKNTsize(attrInfo[0])];
    1043                try {
    1044                    HDFLibrary.GRgetattr(srcdid, i, attrBuff);
    1045                }
    1046                catch (Exception ex) {
    1047                    log.trace("copyAttribute(): attribute[{}] GRgetattr failure: ", i, ex);
    1048                    attrBuff = null;
    1049                }
    1050
    1051                if (attrBuff == null) {
    1052                    log.debug("copyAttribute(): attrBuff[{}] is null", i);
    1053                    log.trace("copyAttribute(): continue");
    1054                    continue;
    1055                }
    1056
    1057                // attach attribute to the destination dataset
    1058                HDFLibrary.GRsetattr(dstdid, attrName[0], attrInfo[0], attrInfo[1], attrBuff);
    1059            } // for (int i=0; i<numberOfAttributes; i++)
    1060        }
    1061        catch (Exception ex) {
    1062            log.debug("copyAttribute(): failure: ", ex);
    1063        }
    1064    }
    1065
    1066    //Implementing DataFormat
    1067    @SuppressWarnings("rawtypes")
    1068    public List getMetadata(int... attrPropList) throws Exception {
    1069        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    1070    }
    1071}