Package com.bbn.openmap.layer.rpf

Source Code of com.bbn.openmap.layer.rpf.RpfFrame$Image

// **********************************************************************
//
// <copyright>
//
//  BBN Technologies
//  10 Moulton Street
//  Cambridge, MA 02138
//  (617) 873-8000
//
//  Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/rpf/RpfFrame.java,v $
// $RCSfile: RpfFrame.java,v $
// $Revision: 1.3.2.7 $
// $Date: 2006/08/17 15:18:16 $
// $Author: dietrick $
//
// **********************************************************************

/*
* Some of the ideas for this code is based on source code provided by
* The MITRE Corporation, through the browse application source code.
* Many thanks to Nancy Markuson who provided BBN with the software,
* to Theron Tock, who wrote the software, and Daniel Scholten, who
* revised it - (c) 1994 The MITRE Corporation for those parts, and
* used/distributed with permission.  Namely, the frame file reading
* mechanism is the part that has been modified.
*/

package com.bbn.openmap.layer.rpf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import com.bbn.openmap.io.BinaryBufferedFile;
import com.bbn.openmap.io.BinaryFile;
import com.bbn.openmap.io.FormatException;
import com.bbn.openmap.layer.nitf.NitfHeader;
import com.bbn.openmap.omGraphics.OMRaster;
import com.bbn.openmap.omGraphics.OMRasterObject;
import com.bbn.openmap.util.Debug;

/**
* The object that organizes the information found within the RPF frame file.
* The RpfFrame handles reading through the different sections, and holds on to
* the compressed subframe data. The cache handler gets the compressed subframe
* data and decompresses it before storing the uncompressed subframe in the
* cache.
*/
public class RpfFrame {

    boolean valid = false;

    protected NitfHeader nitfHeader;
    protected RpfHeader header;
    protected RpfFileSections fileSections;
    protected RpfAttributes attributes;
    protected RpfFileSections.RpfCoverageSection coverage;
    protected RpfColortable colortable;
    String report;

    byte[][][] compressedSubframe = new byte[6][6][];
    byte[][][] table = new byte[4][4096][4];
    /* DKS NEW for CHUMMED subfr info. [y][x] */
    boolean[][] chummed = new boolean[6][6];
    /* DKS NEW for masked subfr info: WAS EXTERNAL. */
    boolean[][] masked = new boolean[6][6];

    /** Want to bother with Dchum? */
    boolean Dchum = false;
    int chumVersion; /* Chum version: 2,3,etc. */

    int numCharsInDesc; // ushort, # chars in DCHUM descriptor string
    // */
    int descCount; /* # descriptors */
    /** Array of descriptor strings */
    String[] descriptors; // char
    // desc_str[MAX_NUM_DESC][MAX_DESC_LEN];
    /** Array of descriptor dates */
    String[] descriptorDates; // char desc_date[MAX_NUM_DESC][9];

    protected boolean DEBUG_RPFDETAIL = false;
    protected boolean DEBUG_RPFFRAME = false;

    /** Loads the RpfFrame, given a complete path to the file. */
    public RpfFrame(String framePath) {
        DEBUG_RPFDETAIL = Debug.debugging("rpfdetail");
        DEBUG_RPFFRAME = Debug.debugging("rpfframe");
        initFile(framePath);
    }

    /**
     * Loads the RpfFrame, given the RpfFrameEntry that the RpfCacheHandler got
     * from the RpfTocHandler.
     */
    public RpfFrame(RpfFrameEntry rfe) {
        this(rfe.framePath);

        if (!isValid() && rfe.exists && rfe.rpfdirIndex != -1) {
            // Check lower case, if we think it exists and the rpf dir
            // is not null. If it is null, then the path we tried is
            // a complete file path (not a relative one) and should be
            // right.

            String lowerCaseFramePath = rfe.framePath.substring(rfe.rpfdirIndex + 3);
            lowerCaseFramePath = lowerCaseFramePath.toLowerCase();

            String rpfDir = rfe.framePath.substring(0, rfe.rpfdirIndex + 3);

            if (DEBUG_RPFFRAME) {
                Debug.output("RpfFrame " + rfe.framePath
                        + " not found, checking " + rpfDir + lowerCaseFramePath);
            }

            if (initFile(rpfDir + lowerCaseFramePath)) {
                // Update it for the next time we check
                rfe.framePath = rpfDir + lowerCaseFramePath;
            } else {
                // Update check so we don't keep looking again.
                rfe.exists = false;
            }
        }

        Dchum = true;
    }

    // public void finalize() {
    // Debug.message("gc", "RpfFrame: getting GC'd");
    // }

    protected boolean initFile(String framePath) {
        try {
            BinaryFile binFile = new BinaryBufferedFile(framePath);
            read(binFile);
            binFile.close();
        } catch (FileNotFoundException e) {
            Debug.error("RpfFrame: file " + framePath + " not found");
            valid = false;
        } catch (IOException ioe) {
            Debug.error("RpfFrame: File IO Error while handling NITF header:\n"
                    + ioe);
            valid = false;
        } catch (NullPointerException npe) {
            Debug.error("RpfFrame: File IO Error NPE:\n" + npe);
            npe.printStackTrace();
            valid = false;
        }
        return valid;
    }

    public boolean isValid() {
        return valid;
    }

    /**
     * Create the screen text used on a subframe. The internal string is set.
     *
     * @param Cib whether the frame is a Cib frame. The report is different if
     *        it is.
     */
    protected void setReport(boolean Cib) {
        if (attributes != null) {
            StringBuffer s = new StringBuffer();
            s.append("\nRPF Currency Date: " + attributes.currencyDate);
            s.append("\nRPF Production Date: " + attributes.productionDate);
            s.append("\nSource Significant Date: " + attributes.significantDate);
            if (Cib) {
                s.append("\nMap Source: " + attributes.dataSource);
            } else {
                s.append("\nMap Designation: " + attributes.mapDesignationCode);
                s.append("\nMap Series: " + attributes.chartSeriesCode);
                s.append("\nMap Edition: " + attributes.edition);
            }
            report = s.toString();
        }
    }

    /**
     * Get the attribute text to display on the screen. This goes to the
     * RpfSubframe object. The RpfCacheHandler knows about the four variables.
     *
     * @param x subframe index within the array from the TocEntry.
     * @param y subframe index within the array from the TocEntry
     * @param entry the RpfFrameEntry describing the frame.
     * @param Cib whether the frame is an imagery frame.
     */
    public String getReport(int x, int y, RpfFrameEntry entry, boolean Cib) {
        StringBuffer s = new StringBuffer();

        x = x % 6;
        y = y % 6;
        s.append("Subframe " + x + ", " + y + "\n");
        if (entry != null) {
            s.append("\nFrame Name: ");
            // s.append(entry.filename);
            s.append(entry.framePath.substring(entry.filenameIndex));
        } else {
            s.append("\nFrame Name: Unavailable.");
        }

        if (report == null)
            setReport(Cib); // preset the attribute part of the info.
        if (report != null)
            s.append(report);

        s.append("\nFrom Frame Dir: ");

        String actualFilePath = entry.framePath.substring(0,
                entry.filenameIndex);

        if (actualFilePath.length() > 20) {
            int start = 0;
            int index = actualFilePath.indexOf("/", 15);
            while (index != -1) {
                s.append(actualFilePath.substring(start, index));
                s.append("/\n    ");
                start = index + 1;
                index = actualFilePath.indexOf("/", start + 15);
            }
            s.append(actualFilePath.substring(start));
        }

        else
            s.append(actualFilePath);
        return s.toString().trim();
    }

    /**
     * Get the NitfFile header.
     */
    public NitfHeader getNitfHeader() {
        return nitfHeader;
    }

    /**
     * Get the RpfFrame header.
     */
    public RpfHeader getHeader() {
        return header;
    }

    /**
     * Get the different file sections.
     */
    public RpfFileSections getFileSections() {
        return fileSections;
    }

    /**
     * Get the attributes for the RpfFrame.
     */
    public RpfAttributes getAttributes() {
        return attributes;
    }

    /**
     * Get the coverage section.
     */
    public RpfFileSections.RpfCoverageSection getCoverage() {
        return coverage;
    }

    /**
     * The only reason to call this is to read the colortable that is within the
     * frame file, and set the colors that you will be using for all the frames
     * accordingly. The RpfColortable is passed in so you can set the
     * opaqueness, number of colors, and other colortable variables inside your
     * own colortable object, and then read the color conversion tables as they
     * apply (inside the frame file). Since the frame file is read when the
     * RpfFrame is created, the fileSections object will (should) be valid.
     */
    public Color[] getColors(BinaryFile binFile, RpfColortable ct) {

        fileSections.parseColorSection(binFile, ct);
        return ct.colors;
    }

    /**
     * Load the colortable with the colors from a particular frame file. Not
     * needed, really, since the frame file is now loading it's own colortable
     * at loadtime.
     */
    public static Color[] getColors(String framePath, RpfColortable ct) {
        BinaryFile binFile = null;
        try {
            binFile = new BinaryBufferedFile(framePath);
            // binFile = new BinaryFile(framePath);
            RpfFileSections rfs = new RpfFileSections();
            RpfHeader head = new RpfHeader();

            head.read(binFile);
            binFile.seek(head.locationSectionLocation);
            rfs.parse(binFile);

            Color[] ret = rfs.parseColorSection(binFile, ct);

            binFile.close();
            return ret;
        } catch (FileNotFoundException e) {
            Debug.error("RpfFrame: getColortable(): file " + framePath
                    + " not found");
        } catch (IOException ioe) {
            Debug.error("RpfFrame: getColortable(); File IO Error!\n" + ioe);
        }
        return null;
    }

    /**
     * Get the colortable stored inside this RpfFrame.
     *
     * @return RpfColortable
     */
    public RpfColortable getColortable() {
        return colortable;
    }

    /** Read the RPF frame. */
    public boolean read(BinaryFile binFile) {

        Compression compression;
        LookupTable[] lookupTable = new LookupTable[4];
        Image image;

        int[][] indices = new int[6][6]; // ushort
        int i, j;

        /* bool (uchar) */
        /* all subframes present indicator */
        boolean allSubframes;
        long currentPos; // uint
        long lookupOffsetTableOffset; // uint
        int lookupTableOffsetRecLen; // ushort

        long subframeMaskTableOffset; // uint
        /* subframe offset (mask section) */
        long[][] subframeOffset = new long[6][6];// uint[][]

        /* for DCHUM */
        long fsave; /* saved file loc */
        int chummedSubframe; // uint
        int attributeId; // ushort
        int attributeParamId; // uchar
        long attributeRecOffset; // uint
        int numAttributeOffsetRecs; // ushort
        int numSubframesChummed; // ushort

        if (DEBUG_RPFDETAIL) {
            Debug.output("ENTER RPFFRAME.READ");
        }

        try {
            // Let's start at the beginning, shall we?
            binFile.seek(0);

            // Read the NITF part of the file...
            nitfHeader = new NitfHeader();
            // If false, it might not be a NITF file, start over...
            if (!nitfHeader.read(binFile))
                binFile.seek(0);

            header = new RpfHeader();
            // Now, read the RPF header...
            if (!header.readHeader(binFile))
                return false;

            /* Check date for validity: date should be "1993xxxx" */
            if (!header.standardDate.startsWith("199")
                    && !header.standardDate.startsWith("20")) {
                Debug.output("RpfFrame.read: Invalid date in header: "
                        + header.standardDate);
                return false;
            }

            // Need to do this right after the header...
            binFile.seek(header.locationSectionLocation);
            fileSections = new RpfFileSections(binFile);

            RpfFileSections.RpfLocationRecord[] loc = fileSections.getLocations(RpfFileSections.FRAME_LOCATION_KEY);

            attributes = fileSections.parseAttributes(binFile);
            coverage = fileSections.parseCoverageSection(binFile);

            colortable = new RpfColortable();
            getColors(binFile, colortable);

            /* DKS: from index to componentLocation */
            if (loc[0] == null) {
                Debug.output("RpfFrame: No compression section!");
                return false;
            }

            /* Read the compression tables */
            binFile.seek(loc[0].componentLocation);
            compression = new Compression(binFile);
            if (DEBUG_RPFDETAIL)
                Debug.output(compression.toString());

            if (loc[2] == null) {
                Debug.output("Warning: Can't find compr. lookup subsection in FrameFile:");
                Debug.output("   Using alternate computation");
                /* length of compr. sect. subhdr = 10 */
                binFile.seek(loc[0].componentLocation + 10);
            } else {
                /*
                 * DKS: Position at start of compression lookup table offset
                 * record
                 */
                if (DEBUG_RPFDETAIL) {
                    Debug.output("Comp lkup subsect: loc[2].componentLocation(264?): "
                            + loc[2].componentLocation);
                }
                binFile.seek(loc[2].componentLocation);
            }

            /* 2 new hdr fields */

            lookupOffsetTableOffset = (long) binFile.readInteger();
            lookupTableOffsetRecLen = (int) binFile.readShort();

            if (DEBUG_RPFDETAIL) {
                Debug.output("lookupOffsetTableOffset(6): "
                        + lookupOffsetTableOffset);
                Debug.output("lookupTableOffsetRecLen(14): "
                        + lookupTableOffsetRecLen);
            }

            /* For each compression table */
            for (i = 0; i < 4; i++) {
                lookupTable[i] = new LookupTable(binFile);
                if (DEBUG_RPFDETAIL) {
                    Debug.output("Compression lookup table offset record " + i);
                    Debug.output(lookupTable[i].toString());
                }

                if (lookupTable[i].records != 4096
                        || lookupTable[i].values != 4
                        || lookupTable[i].bitLength != 8) {
                    Debug.output("RpfFrame: Bad VQ info in compression record");
                    return false;
                }
            } /* for i */

            for (i = 0; i < 4; i++) { /* Read compression lookup table */
                /*
                 * new position from compression lookup subsection: loc[2]
                 */
                binFile.seek(loc[2].componentLocation + lookupTable[i].offset);
                if (DEBUG_RPFDETAIL) {
                    currentPos = binFile.getFilePointer();
                    Debug.output("Read compr. lookup table (4x4096) at position: "
                            + currentPos);
                }
                for (j = 0; j < 4096; j++)
                    table[i][j] = binFile.readBytes(4, false);

            } /*
                 * for i=1 to 4 (# compression tables, 1 for each pixel row)
                 */

            /* seek to LOC_ATTRIB_SUBHEADER, ID=141 */
            if ((Dchum) && (chumVersion > 1)) { /*
                                                 * Chum selected and file
                                                 * version > 1
                                                 */
                if (loc[6] == null) {
                    Debug.output("RpfFrame: Can't find ATTRIBUTE_SUBHEADER section!");
                    return false;
                }
                if (DEBUG_RPFDETAIL)
                    Debug.output("ATTRIBUTE SUBHEADER location: "
                            + loc[6].componentLocation);

                binFile.seek(loc[6].componentLocation);

                numAttributeOffsetRecs = (int) binFile.readShort();
                if (DEBUG_RPFDETAIL)
                    Debug.output("numAttributeOffsetRecs: "
                            + numAttributeOffsetRecs);

                /* Go to Attrib subsection */
                if (loc[7] == null) {
                    Debug.output("RpfFrame: Can't find ATTRIBUTE_SECTION in Frame file");
                    return false;
                }

                if (DEBUG_RPFDETAIL)
                    Debug.output("ATTRIBUTE SECTION location: "
                            + loc[7].componentLocation);

                binFile.seek(loc[7].componentLocation);

                descCount = 0; /* # descriptor strings so far */

                for (i = 0; i < numAttributeOffsetRecs; i++) {
                    attributeId = (int) binFile.readShort();
                    attributeParamId = binFile.read();
                    /* tempc = */binFile.read();
                    attributeRecOffset = (long) binFile.readInteger();

                    /* # subframes impacted */
                    if ((attributeId == 24) && (attributeParamId == 4)) {
                        /* save file loc */
                        fsave = binFile.getFilePointer();
                        /* Go to proper spot in attrib section */
                        binFile.seek(loc[7].componentLocation
                                + attributeRecOffset);
                        /* read # subframes impacted */
                        numSubframesChummed = (int) binFile.readShort();

                        if (DEBUG_RPFDETAIL) {
                            Debug.output("n_attrib_chummedSubframe: "
                                    + numSubframesChummed);
                        }
                        /* Read list of subframes chummed */
                        /* Assume these are next in file */
                        for (j = 0; j < numSubframesChummed; j++) {
                            chummedSubframe = (int) binFile.readShort();

                            if (DEBUG_RPFDETAIL) {
                                Debug.output("chummedSubframe: "
                                        + chummedSubframe);
                            }

                            /* y,x */
                            chummed[chummedSubframe / 6][chummedSubframe % 6] = true;
                        } /* for j */
                        binFile.seek(fsave); /* restore file pos */
                    } /* if 24,4 */

                    /* Update date */
                    if ((attributeId == 24) && (attributeParamId == 3)) {
                        /* save file loc */
                        fsave = binFile.getFilePointer();
                        /* Go to proper spot in attrib section */
                        binFile.seek(loc[7].componentLocation
                                + attributeRecOffset);
                        /* read date */
                        descriptorDates[descCount] = binFile.readFixedLengthString(8);

                        if (DEBUG_RPFDETAIL)
                            Debug.output("descriptorDate: "
                                    + descriptorDates[descCount]);

                        binFile.seek(fsave); /* restore file pos */
                    } /* if 24,3 */

                    /* # chars in descriptor */
                    if ((attributeId == 24) && (attributeParamId == 6)) {
                        /* save file loc */
                        fsave = binFile.getFilePointer();
                        /* Go to proper spot in attrib section */
                        binFile.seek(loc[7].componentLocation
                                + attributeRecOffset);
                        /* read # chars in descriptor */

                        numCharsInDesc = (int) binFile.readShort();

                        if (DEBUG_RPFDETAIL) {
                            Debug.output("Prepare to fread descriptors[descCount]");
                            Debug.output("RpfFrame.read: descCount: "
                                    + descCount);
                        }

                        descriptors[descCount] = binFile.readFixedLengthString(numCharsInDesc);

                        /* Array of strings, not 2-d array !!!!???? */
                        if (DEBUG_RPFDETAIL) {
                            Debug.output("descriptors[descCount]: "
                                    + descriptors[descCount]);
                        }
                        descCount++; /* string number */

                        binFile.seek(fsave); /* restore file pos */
                    } /* if 24,6 */
                } /* for i */
            } /* if Dchum */

            /* READ THE IMAGE DATA */
            if (DEBUG_RPFDETAIL) {
                Debug.output("Image descr. subheader location: loc[1].componentLocation(68576?): "
                        + loc[1].componentLocation);
            }
            binFile.seek(loc[1].componentLocation);
            image = new Image(binFile);

            /* New, DKS. NULL (FF) if no subfr mask table */
            subframeMaskTableOffset = binFile.readInteger();

            if (DEBUG_RPFDETAIL) {
                Debug.output(image.toString());
                Debug.output("subframeMaskTableOffset: "
                        + subframeMaskTableOffset);
            }

            if (subframeMaskTableOffset == 0) { /* ERROR Check */
                Debug.error("RpfFrame.read(): subframeMaskTableOffset==0.");
                return false;
            }

            if (subframeMaskTableOffset == 0xFFFFFFFF)
                allSubframes = true;
            else
                allSubframes = false;

            if (Debug.debugging("rpfframe")) {
                Debug.output("allSubframes: " + allSubframes);
            }

            if (!allSubframes) { /* Read mask data */
                /* fseek to LOC_MASK_SUBSECTION, ID=138 */
                if (loc[5] == null) {
                    Debug.error("RpfFrame.read(): Can't find MASK_SUBSECTION section in Frame file");
                    return false;
                }
                if (DEBUG_RPFDETAIL) {
                    Debug.output("MASK SUBSECTION location: "
                            + loc[5].componentLocation);
                }

                binFile.seek(loc[5].componentLocation + subframeMaskTableOffset);

                for (i = 0; i < 6; i++) { /* y */
                    for (j = 0; j < 6; j++) {
                        subframeOffset[i][j] = (long) binFile.readInteger();
                        if (subframeOffset[i][j] == 0xFFFFFFFF)
                            masked[i][j] = true; /* subfr masked */

                        if (DEBUG_RPFDETAIL) {
                            Debug.output("i:" + i + ", j:" + j
                                    + ", masked[i][j]: " + masked[i][j]);
                        }

                    } /* for j */
                } /* for i */
            } /* if !allSubframes */

            if (image.vertSubframes != 6 || image.horizSubframes != 6) {
                Debug.output("Not 6x6 subframes per frame: must be masked.");
            }

            // rowBytes = 256 / 4 * 3 / 2;

            // Is this section needed??
            /* fseek to LOC_IMAGE_DISPLAY_PARAM_SUBHEADER, ID=137 */
            if (loc[4] == null) {
                Debug.error("RpfFrame.read(): Can't find IMAGE_DISPLAY_PARAM_SUBHEADER section!");
                return false;
            }

            /* Image Display Parameters Subheader */
            if (DEBUG_RPFDETAIL) {
                Debug.output("IMAGE Display params subheader location: "
                        + loc[4].componentLocation);
            }
            binFile.seek(loc[4].componentLocation);

            /* Go to start of image spatial data subsection */
            if (loc[3] == null) {
                Debug.output("WARNING: Can't find Image spatial data subsection in FrameFile:");
                Debug.output("   Using alternate computation");
                /*
                 * DKS. skip 14 bytes of image display parameters subheader
                 * instead
                 */
                binFile.seek(loc[4].componentLocation + 14);
            } else {
                /*
                 * DKS: Position at start of image spatial data subsection
                 */
                currentPos = binFile.getFilePointer();
                if (DEBUG_RPFDETAIL) {
                    Debug.output("Current frame file position(68595?): "
                            + currentPos);
                    Debug.output("Image spatial data subsect: loc[3](68609?): "
                            + loc[3].componentLocation);
                }

                binFile.seek(loc[3].componentLocation);
            } /* else */

            /* Read subframes from top left, row-wise */
            for (i = 0; i < 6; i++) { /* row */
                for (j = 0; j < 6; j++) { /* col */
                    /* DKS. New: init indices to valid subframes */
                    indices[i][j] = i * 6 + j;
                    /* (256/4)=64. 64*64 * 12bits / 8bits = 6144 bytes */
                    if (!masked[i][j]) {
                        compressedSubframe[i][j] = binFile.readBytes(6144,
                                false);
                        if (DEBUG_RPFDETAIL)
                            Debug.output(" i:" + i + ", j:" + j
                                    + ", read image data. rc(6144):"
                                    + compressedSubframe[i][j].length);
                    } else
                        compressedSubframe[i][j] = new byte[6144];
                }
            }

        } catch (IOException e) {
            Debug.error("RpfFrame: read(): File IO Error!\n" + e);
            return false;
        } catch (FormatException f) {
            Debug.error("RpfFrame: read(): File IO Format error!" + f);
            return false;
        }

        if (DEBUG_RPFDETAIL) {
            Debug.output("LEAVE RPFFRAME.READ");
        }

        valid = true;
        return valid;
    } /* read */

    static public class Compression {
        public int algorithm;// ushort
        /* New, dks */
        public int numOffsetRecs;// ushort
        public int numParmOffRecs;// ushort

        public Compression(BinaryFile binFile) {
            try {
                algorithm = (int) binFile.readShort();
                numOffsetRecs = (int) binFile.readShort();
                numParmOffRecs = (int) binFile.readShort();
            } catch (IOException e) {
                Debug.error("Compression: File IO Error!\n" + e);
            } catch (FormatException f) {
                Debug.error("Compression: File IO Format error!\n" + f);
            }
        }

        public String toString() {
            StringBuffer s = new StringBuffer();
            s.append("Compression.algorithm: " + algorithm + "\n");
            s.append("Compression.numOffsetRecs: " + numOffsetRecs + "\n");
            s.append("Compression.numParmOffRecs: " + numParmOffRecs + "\n");
            return s.toString();
        }
    }

    static public class LookupTable {
        int id; // ushort
        long records; // uint
        int values; // ushort
        int bitLength; // ushort
        long offset; // uint

        public LookupTable(BinaryFile binFile) {
            try {
                id = (int) binFile.readShort();
                records = (long) binFile.readInteger();
                values = (int) binFile.readShort();
                bitLength = (int) binFile.readShort();
                offset = (long) binFile.readInteger();
            } catch (IOException e) {
                Debug.error("Compression: File IO Error!\n" + e);
            } catch (FormatException f) {
                Debug.error("Compression: File IO Format error!\n" + f);
            }
        }

        public String toString() {
            StringBuffer s = new StringBuffer();
            s.append("LookupTable.id: " + id + "\n");
            s.append("LookupTable.records: " + records + "\n");
            s.append("LookupTable.values: " + values + "\n");
            s.append("LookupTable.bitLength: " + bitLength + "\n");
            s.append("LookupTable.offset: " + offset + "\n");
            return s.toString();
        }
    }

    static public class Image {
        int spectralGroups; // ushort
        int subframeTables;// ushort
        int spectralTables;// ushort
        int spectralLines;// ushort
        int horizSubframes, vertSubframes;// ushort
        long outputColumns, outputRows;// uint

        public Image(BinaryFile binFile) {
            try {
                spectralGroups = (int) binFile.readShort();
                subframeTables = (int) binFile.readShort();
                spectralTables = (int) binFile.readShort();
                spectralLines = (int) binFile.readShort();
                horizSubframes = (int) binFile.readShort();
                vertSubframes = (int) binFile.readShort();
                outputColumns = (long) binFile.readInteger();
                outputRows = (long) binFile.readInteger();
            } catch (IOException e) {
                Debug.error("Compression: File IO Error!\n" + e);
            } catch (FormatException f) {
                Debug.error("Compression: File IO Format error!\n" + f);
            }
        }

        public String toString() {
            StringBuffer s = new StringBuffer();
            s.append("Image.spectralGroups: " + spectralGroups + "\n");
            s.append("Image.subframeTables: " + subframeTables + "\n");
            s.append("Image.spectralTables: " + spectralTables + "\n");
            s.append("Image.spectralLines: " + spectralLines + "\n");
            s.append("Image.horizSubframes: " + horizSubframes + "\n");
            s.append("Image.vertSubframes: " + vertSubframes + "\n");
            s.append("Image.outputColumns: " + outputColumns + "\n");
            s.append("Image.outputRows: " + outputRows + "\n");
            return s.toString();
        }
    }

    /**
     * Decompress a subframe into a cache entry OMRaster (RpfSubframe). The
     * RpfSubframe is returned, too, to emphasize what's happening.
     *
     * @param x the x coord for the subframe
     * @param y the y coord for the subframe
     * @param subframe the subframe to create the image for. The resulting image
     *        will be loaded into the RpfSubframe. If null, a new RpfSubframe
     *        will be created.
     * @param colortable the colortable to use with this image. If null, the
     *        colortable from this RpfFrame will be used.
     * @param viewAttributes our image generation parameters.
     * @return RpfSubframe containing the image data.
     */
    public RpfSubframe decompressSubframe(int x, int y, RpfSubframe subframe,
                                          RpfColortable colortable,
                                          RpfViewAttributes viewAttributes) {

        boolean isDirectColorModel = (viewAttributes.colorModel == OMRasterObject.COLORMODEL_DIRECT);

        if (subframe == null) {
            subframe = new RpfSubframe();
        }

        if (viewAttributes != null) {
            subframe.setColorModel(viewAttributes.colorModel);
        }

        if (colortable == null) {
            colortable = this.colortable;
        }

        if (!isDirectColorModel) {
            if (DEBUG_RPFDETAIL) {
                Debug.output("RpfFrame: decompress to byte[]");
            }
            byte[] pixels = decompressSubframe(x, y);
            OMRaster image = subframe.image;
            image.setBits(pixels);
            image.setColors(colortable.colors);
        } else {
            int[] pixels = decompressSubframe(x, y, colortable);
            OMRaster image = subframe.image;
            image.setPixels(pixels);
        }
        return subframe;
    }

    /**
     * Decompress a subframe into an array of bytes suitable for in indexed
     * color model image.
     *
     * @param x the x coord for the subframe
     * @param y the y coord for the subframe
     */
    public byte[] decompressSubframe(int x, int y) {
        // Convert x,y to the subframe index in the frame - they come
        // in as
        // cache subframe indexes
        x = x % 6;
        y = y % 6;

        // used to keep track of location into compressedSubframe
        // array.
        int readptr = 0;

        // and the compressedSubframe array
        byte[] compressedSubframe = this.compressedSubframe[y][x];

        /*
         * This should never occur since all subframes should be present
         */
        /*
         * But if it does occur, just put up black pixels on the screen
         */
        if ((compressedSubframe == null) || masked[y][x]) {
            return null;
        } else { // Normal pixel */
            byte[] pixels = new byte[256 * 256];
            for (int i = 0; i < 256; i += 4) {
                for (int j = 0; j < 256; j += 8) {
                    int firstByte = compressedSubframe[readptr++] & 0xff;
                    int secondByte = compressedSubframe[readptr++] & 0xff;
                    int thirdByte = compressedSubframe[readptr++] & 0xff;

                    // because dealing with half-bytes is hard, we
                    // uncompress two 4x4 tiles at the same time. (a
                    // 4x4 tile compressed is 12 bits )

                    /* Get first 12-bit value as index into VQ table */
                    int val1 = (firstByte << 4) | (secondByte >> 4);
                    /* Get second 12-bit value as index into VQ table */
                    int val2 = ((secondByte & 0x000F) << 8) | thirdByte;
                    for (int t = 0; t < 4; t++) {
                        for (int e = 0; e < 4; e++) {
                            int tableVal1 = table[t][val1][e] & 0xff;
                            int tableVal2 = table[t][val2][e] & 0xff;
                            if (tableVal1 >= RpfColortable.CADRG_COLORS) {
                                tableVal1 = RpfColortable.CADRG_COLORS - 1;
                            }
                            if (tableVal2 >= RpfColortable.CADRG_COLORS) {
                                tableVal2 = RpfColortable.CADRG_COLORS - 1;
                            }
                            int pixindex = (i + t) * 256 + j + e;
                            pixels[pixindex] = (byte) tableVal1;
                            pixels[pixindex + 4] = (byte) tableVal2;
                        } // for e
                    } // for t
                } /* for j */
            } // for i
            return pixels;
        } /* else */
    }

    /**
     * Decompress a subframe into an array of ints suitable for a direct color
     * model image. (argb format)
     *
     * @param x the x coord for the subframe
     * @param y the y coord for the subframe
     * @param colortable the colortable to use with this image. If null, the
     *        RpfColortable from the frame will be used.
     */
    public int[] decompressSubframe(int x, int y, RpfColortable colortable) {
        // Convert x,y to the subframe index in the frame - they come
        // in as
        // cache subframe indexes
        x = x % 6;
        y = y % 6;

        // used to keep track of location into compressedSubframe
        // array.
        int readptr = 0;

        // and the compressedSubframe array
        byte[] compressedSubframe = this.compressedSubframe[y][x];

        if (colortable == null) {
            colortable = this.colortable;
        }

        /*
         * This should never occur since all subframes should be present
         */
        /*
         * But if it does occur, just put up black pixels on the screen
         */
        if ((compressedSubframe == null) || masked[y][x]) {
            return null;
        } else { // Normal pixel */
            int[] pixels = new int[256 * 256];
            for (int i = 0; i < 256; i += 4) {
                for (int j = 0; j < 256; j += 8) {
                    int firstByte = compressedSubframe[readptr++] & 0xff;
                    int secondByte = compressedSubframe[readptr++] & 0xff;
                    int thirdByte = compressedSubframe[readptr++] & 0xff;

                    // because dealing with half-bytes is hard, we
                    // uncompress two 4x4 tiles at the same time. (a
                    // 4x4 tile compressed is 12 bits )

                    /* Get first 12-bit value as index into VQ table */
                    int val1 = (firstByte << 4) | (secondByte >> 4);
                    /* Get second 12-bit value as index into VQ table */
                    int val2 = ((secondByte & 0x000F) << 8) | thirdByte;
                    for (int t = 0; t < 4; t++) {
                        for (int e = 0; e < 4; e++) {
                            int tableVal1 = table[t][val1][e] & 0xff;
                            int tableVal2 = table[t][val2][e] & 0xff;
                            if (tableVal1 >= RpfColortable.CADRG_COLORS) {
                                tableVal1 = RpfColortable.CADRG_COLORS - 1;
                            }
                            if (tableVal2 >= RpfColortable.CADRG_COLORS) {
                                tableVal2 = RpfColortable.CADRG_COLORS - 1;
                            }
                            int pixindex = (i + t) * 256 + j + e;
                            pixels[pixindex] = colortable.colors[tableVal1].getRGB();
                            pixels[pixindex + 4] = colortable.colors[tableVal2].getRGB();
                        } // for e
                    } // for t
                } /* for j */
            } // for i
            return pixels;
        } /* else */
    }

    public static void main(String[] argv) {
        Debug.init();

        com.bbn.openmap.util.ArgParser ap = new com.bbn.openmap.util.ArgParser("RpfFrame");

        ap.add("attributes", "Only write out the attributes for this frame.");
        ap.add("view", "Only bring up a window with the frame image.");
        ap.add("frame",
                "Path to the frame to view. \"-frame\" only needed if other arguments are used.",
                1);

        if (!ap.parse(argv)) {
            ap.printUsage();
            System.exit(0);
        }

        String arg[];
        boolean viewAttributes = false;
        arg = ap.getArgValues("attributes");
        if (arg != null) {
            viewAttributes = true;
            Debug.put("rpfframe");
            Debug.put("rpfdetail");
        }

        boolean viewFrame = false;
        arg = ap.getArgValues("view");
        if (arg != null) {
            viewFrame = true;
        }

        RpfFrame rpfFrame;

        arg = ap.getArgValues("frame");
        if (arg != null) {
            rpfFrame = new RpfFrame(arg[0]);
            if (viewFrame) {
                rpfFrame.view();
            }
        } else {
            if (viewAttributes == false) {
                Debug.put("rpfframe");
                Debug.put("rpfdetail");
            }
            rpfFrame = new RpfFrame(argv[0]);
            rpfFrame.view();
        }
    }

    /**
     * A quick hack to pop up a window that displays the entire frame image.
     */
    public void view() {
        int height = 256;
        int width = 256;

        BufferedImage bigImage = new BufferedImage(width * 6, height * 6, BufferedImage.TYPE_INT_RGB);
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Graphics g = ge.createGraphics(bigImage);
        Toolkit tk = Toolkit.getDefaultToolkit();

        for (int x = 0; x < 6; x++) {
            for (int y = 0; y < 6; y++) {
                int[] pixels = decompressSubframe(x, y, colortable);

                java.awt.Image bitmap = tk.createImage(new MemoryImageSource(width, height, pixels, 0, width));

                g.drawImage(bitmap, x * 256, y * 256, null);
            }
        }

        JLabel picture = new JLabel(new ImageIcon(bigImage));
        JFrame frame = com.bbn.openmap.util.PaletteHelper.getPaletteWindow(picture,
                "RPF Frame",
                null);
        frame.setSize(new Dimension(500, 500));
        frame.setVisible(true);
    }
}
TOP

Related Classes of com.bbn.openmap.layer.rpf.RpfFrame$Image

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.