ImageColormap.java 7.68 KB
/*
 * ESO Archive
 *
 * $Id: ImageColormap.java,v 1.2 2009/02/20 23:10:11 abrighto Exp $
 *
 * who             when        what
 * --------------  ----------  ----------------------------------------
 * Allan Brighton  1999/12/09  Created
 */


package jsky.image;

import javax.media.jai.*;


/**
 * Manages the colormap for an image and provides methods to select a
 * predefined colormap and perform operations on it, such as rotate, shift, and
 * stretch.
 *
 * @version $Revision: 1.2 $
 * @author Allan Brighton
 */
public class ImageColormap implements Cloneable {

    /** Default color lookup table to use */
    public static final String DEFAULT_COLOR_LUT = "Real";

    /** The number of colors in the display image */
    protected static final int NUM_COLORS = 256;


    /** Used to make a color image froma grayscale image using a selected colormap */
    protected LookupTableJAI colorLookupTable;

    /** Name of the current color lookup table */
    protected String colorLookupTableName = "Ramp";

    /** Copy of current color lookup table data to use for shift, rotate, scale ops */
    protected byte[][] colorLut;

    /** Used to modify the order of the colors in the color lookup table */
    protected float[] intensityLookupTable;

    /** Name of the current intensity lookup table */
    protected String intensityLookupTableName = "Ramp";

    /**
     * Default constructor: Initialize with the default colormap.
     */
    public ImageColormap() {
        setColorLookupTable(DEFAULT_COLOR_LUT);
    }


    /**
     * Create a color RGB lookup table that can be added to the image processing chain,
     * so that we can manipulate the image colors.
     *
     * @param name the name of the colormap table to use. This is currently
     * One of: 	"Background", "Blue", "Heat", "Isophot", "Light", "Pastel",
     * "Ramp", "Real", "Smooth", "Staircase", "Standard".
     * User defined maps will be implemented in a later release.
     */
    public void setColorLookupTable(String name) {
        colorLookupTableName = name;
        int maxLut = NUM_COLORS - 1;
        byte[][] blut = new byte[3][NUM_COLORS];
        float[][] flut = ImageColorLUTs.getLUT(name);

        if (intensityLookupTable == null || intensityLookupTableName.equals("Ramp")) {
            // don't use intensity table
            for (int i = 0; i < NUM_COLORS; i++) {
                blut[0][i] = (byte) (flut[i][0] * maxLut);
                blut[1][i] = (byte) (flut[i][1] * maxLut);
                blut[2][i] = (byte) (flut[i][2] * maxLut);
            }
        } else {
            // use intensity table
            for (int i = 0; i < NUM_COLORS; i++) {
                int index = (int) ((intensityLookupTable[i] * maxLut) + 0.5);
                blut[0][i] = (byte) (flut[index][0] * maxLut);
                blut[1][i] = (byte) (flut[index][1] * maxLut);
                blut[2][i] = (byte) (flut[index][2] * maxLut);
            }
        }

        // save a copy for manipulation
        colorLut = blut.clone();
        colorLookupTable = new LookupTableJAI(blut, 0);
    }


    /**
     * Create an intensity lookup table that can be added to the image processing chain
     * to rearrange the order of the colors in the colormap.
     *
     * @param name the name of the intensity lookup table to use. This is currently
     * One of: 	"Equal", "Exponential",	"Gamma", "Jigsaw", "Lasritt", "Logarithmic",
     * "Negative", "Negative Log", "Ramp", "Staircase".
     *
     * User defined intensity lookup tables will be implemented in a later release.
     */
    public void setIntensityLookupTable(String name) {
        intensityLookupTableName = name;
        intensityLookupTable = ImageColorITTs.getITT(name);
        setColorLookupTable(colorLookupTableName);
    }


    /**
     * Save the current colormap state for the next shift, rotate or scale operation.
     */
    public void saveColormap() {
        colorLut = colorLookupTable.getByteData().clone();
    }


    /**
     * Rotate the colormap by the given amount.
     */
    public void rotateColormap(int amount) {
        byte[][] newLut = new byte[3][NUM_COLORS];
        for (int i = 0; i < NUM_COLORS; i++) {
            int index = (i - amount) % NUM_COLORS;
            if (index < 0)
                index += NUM_COLORS;
            newLut[0][i] = colorLut[0][index];
            newLut[1][i] = colorLut[1][index];
            newLut[2][i] = colorLut[2][index];
        }
        colorLut = newLut.clone();
        colorLookupTable = new LookupTableJAI(newLut, 0);
    }


    /**
     * Shift the colormap by the given amount.
     */
    public void shiftColormap(int amount) {
        byte[][] newLut = new byte[3][NUM_COLORS];

        for (int i = 0; i < NUM_COLORS; i++) {
            int index = (i - amount);
            if (index < 0)
                index = 0;
            else if (index >= NUM_COLORS)
                index = NUM_COLORS - 1;
            newLut[0][i] = colorLut[0][index];
            newLut[1][i] = colorLut[1][index];
            newLut[2][i] = colorLut[2][index];
        }
        colorLookupTable = new LookupTableJAI(newLut, 0);
    }


    /**
     * Scale the colormap by the given amount.
     */
    public void scaleColormap(int amount) {
        byte[][] newLut = new byte[3][NUM_COLORS];

        int n = NUM_COLORS - 1;
        int index;
        int start = Math.min(amount, NUM_COLORS / 2);
        int end = NUM_COLORS - start;
        if (end <= start)
            end = start + 1;
        int dist = end - start + 1;

        for (int i = 0; i < NUM_COLORS; i++) {
            if (i >= start && i <= end) {
                index = ((i - start) * n) / dist;
                if (index < 0)
                    index = 0;
                else if (index > n)
                    index = n;
            } else if (i < start) {
                index = 0;
            } else {
                index = n;
            }
            if (intensityLookupTable == null)
                index = (byte) ((index / 256.) * n) & 0xff;
            else
                index = (byte) (intensityLookupTable[index] * n) & 0xff;

            newLut[0][i] = colorLut[0][index];
            newLut[1][i] = colorLut[1][index];
            newLut[2][i] = colorLut[2][index];
        }
        colorLookupTable = new LookupTableJAI(newLut, 0);
    }


    /**
     * Reset the colormap to the default.
     */
    public void setDefaultColormap() {
        intensityLookupTableName = "Ramp";
        setColorLookupTable(DEFAULT_COLOR_LUT);
    }


    /**
     * Reset the colormap shift, rotate and scale settings to 0.
     */
    public void resetColormap() {
        setColorLookupTable(colorLookupTableName);
    }


    /** Return the current lookup table used to add color to a grayscale image. */
    public LookupTableJAI getColorLookupTable() {
        return colorLookupTable;
    }


    /** Return the name of the current color lookup table */
    public String getColorLookupTableName() {
        return colorLookupTableName;
    }

    /** Return the name of the current intensity lookup table */
    public String getIntensityLookupTableName() {
        return intensityLookupTableName;
    }

    /**
     * Return true if this object is equivalent to the given one.
     */
    public boolean equals(ImageColormap colormap) {
        return (colorLookupTable == colormap.colorLookupTable
                && colorLookupTableName.equals(colormap.colorLookupTableName)
                && colorLut == colormap.colorLut
                && intensityLookupTable == colormap.intensityLookupTable
                && intensityLookupTableName.equals(colormap.intensityLookupTableName));
    }


    /** Return a shallow copy */
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}