/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.image.colormap;
import java.awt.Color;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.EventListenerList;
import org.w3c.dom.Node;
import icy.common.CollapsibleEvent;
import icy.common.UpdateEventHandler;
import icy.common.listener.ChangeListener;
import icy.file.FileUtil;
import icy.file.xml.XMLPersistent;
import icy.file.xml.XMLPersistentHelper;
import icy.image.colormap.IcyColorMapEvent.IcyColorMapEventType;
import icy.util.ColorUtil;
import icy.util.XMLUtil;
/**
* @author stephane
*/
public class IcyColorMap implements ChangeListener, XMLPersistent
{
public enum IcyColorMapType
{
RGB, GRAY, ALPHA
};
private static final String ID_TYPE = "type";
private static final String ID_NAME = "name";
private static final String ID_ENABLED = "enabled";
private static final String ID_RED = "red";
private static final String ID_GREEN = "green";
private static final String ID_BLUE = "blue";
private static final String ID_GRAY = "gray";
private static final String ID_ALPHA = "alpha";
/**
* define the wanted colormap bits resolution (never change it)
*/
public static final int COLORMAP_BITS = 8;
public static final int MAX_LEVEL = (1 << COLORMAP_BITS) - 1;
/**
* define colormap size
*/
public static final int SIZE = 256;
public static final int MAX_INDEX = SIZE - 1;
/**
* default colormap directory
*/
public static final String DEFAULT_COLORMAP_DIR = "colormap";
/**
* Custom (user) colormap
*/
private static List<IcyColorMap> customMaps = null;
/**
* Returns the list of default linear colormap:<br/>
* GRAY, [GRAY_INV,] RED, GREEN, BLUE, MAGENTA, YELLOW, CYAN, [ALPHA]
*
* @param wantGrayInverse
* specify if we want the gray inverse colormap
* @param wantAlpha
* specify if we want the alpha colormap
*/
public static List<IcyColorMap> getLinearColorMaps(boolean wantGrayInverse, boolean wantAlpha)
{
final List<IcyColorMap> result = new ArrayList<IcyColorMap>();
result.add(LinearColorMap.gray_);
if (wantGrayInverse)
result.add(LinearColorMap.gray_inv_);
result.add(LinearColorMap.red_);
result.add(LinearColorMap.green_);
result.add(LinearColorMap.blue_);
result.add(LinearColorMap.magenta_);
result.add(LinearColorMap.yellow_);
result.add(LinearColorMap.cyan_);
if (wantAlpha)
result.add(LinearColorMap.alpha_);
return result;
}
/**
* Returns the list of special colormap:<br/>
* ICE, FIRE, HSV, JET, GLOW
*/
public static List<IcyColorMap> getSpecialColorMaps()
{
final List<IcyColorMap> result = new ArrayList<IcyColorMap>();
result.add(new IceColorMap());
result.add(new FireColorMap());
result.add(new HSVColorMap());
result.add(new JETColorMap());
result.add(new GlowColorMap(true));
return result;
}
/**
* Returns the list of custom colormap available in the Icy "colormap" folder
*/
public static synchronized List<IcyColorMap> getCustomColorMaps()
{
if (customMaps == null)
{
// load custom maps
customMaps = new ArrayList<IcyColorMap>();
// add saved colormap
for (File f : FileUtil.getFiles(new File(DEFAULT_COLORMAP_DIR), null, false, false, false))
{
final IcyColorMap map = new IcyColorMap();
if (XMLPersistentHelper.loadFromXML(map, f))
customMaps.add(map);
}
}
return new ArrayList<IcyColorMap>(customMaps);
}
/**
* Returns the list of all available colormaps.<br/>
* The order of returned colormap map is Linear, Special and Custom.
*
* @param wantGrayInverse
* specify if we want the gray inverse colormap
* @param wantAlpha
* specify if we want the alpha colormap
*/
public static synchronized List<IcyColorMap> getAllColorMaps(boolean wantGrayInverse, boolean wantAlpha)
{
final List<IcyColorMap> result = new ArrayList<IcyColorMap>();
result.addAll(getLinearColorMaps(false, false));
result.addAll(getSpecialColorMaps());
result.addAll(getCustomColorMaps());
return result;
}
/**
* colormap name
*/
private String name;
/**
* enabled flag
*/
private boolean enabled;
/**
* RED band
*/
public final IcyColorMapComponent red;
/**
* GREEN band
*/
public final IcyColorMapComponent green;
/**
* BLUE band
*/
public final IcyColorMapComponent blue;
/**
* GRAY band
*/
public final IcyColorMapComponent gray;
/**
* ALPHA band
*/
public final IcyColorMapComponent alpha;
/**
* colormap type
*/
private IcyColorMapType type;
/**
* pre-multiplied RGB caches
*/
private final int premulRGB[][];
private final float premulRGBNorm[][];
/**
* listeners
*/
private final EventListenerList listeners;
/**
* internal updater
*/
private final UpdateEventHandler updater;
public IcyColorMap(String name, IcyColorMapType type)
{
this.name = name;
enabled = true;
listeners = new EventListenerList();
updater = new UpdateEventHandler(this, false);
// colormap band
red = createColorMapBand((short) 0);
green = createColorMapBand((short) 0);
blue = createColorMapBand((short) 0);
gray = createColorMapBand((short) 0);
alpha = createColorMapBand((short) 255);
this.type = type;
// allocating and init RGB cache
premulRGB = new int[IcyColorMap.SIZE][3];
premulRGBNorm = new float[IcyColorMap.SIZE][3];
}
public IcyColorMap(String name)
{
this(name, IcyColorMapType.RGB);
}
public IcyColorMap(String name, Object maps)
{
this(name, IcyColorMapType.RGB);
if (maps instanceof byte[][])
copyFrom((byte[][]) maps);
else if (maps instanceof short[][])
copyFrom((short[][]) maps);
// try to define color map type from data
setTypeFromData(false);
}
/**
* Create a copy of specified colormap.
*/
public IcyColorMap(IcyColorMap colormap)
{
this(colormap.name, colormap.type);
copyFrom(colormap);
}
public IcyColorMap()
{
this("");
}
protected IcyColorMapComponent createColorMapBand(short initValue)
{
return new IcyColorMapComponent(IcyColorMap.this, initValue);
}
/**
* Return true if this color map is RGB type
*/
public boolean isRGB()
{
return type == IcyColorMapType.RGB;
}
/**
* Return true if this color map is GRAY type
*/
public boolean isGray()
{
return type == IcyColorMapType.GRAY;
}
/**
* Return true if this color map is ALPHA type
*/
public boolean isAlpha()
{
return type == IcyColorMapType.ALPHA;
}
/**
* @return the type
*/
public IcyColorMapType getType()
{
return type;
}
/**
* @param value
* the type to set
*/
public void setType(IcyColorMapType value)
{
if (type != value)
{
type = value;
changed(IcyColorMapEventType.TYPE_CHANGED);
}
}
/**
* @see IcyColorMap#setTypeFromData()
*/
public void setTypeFromData(boolean notifyChange)
{
boolean grayColor = true;
boolean noColor = true;
boolean hasAlpha = false;
IcyColorMapType cmType;
for (int i = 0; i < MAX_INDEX; i++)
{
final short r = red.map[i];
final short g = green.map[i];
final short b = blue.map[i];
final short a = alpha.map[i];
grayColor &= (r == g) && (r == b);
noColor &= (r == 0) && (g == 0) && (b == 0);
hasAlpha |= (a != MAX_LEVEL);
}
if (noColor && hasAlpha)
cmType = IcyColorMapType.ALPHA;
else if (grayColor && !noColor)
{
// set gray map
gray.copyFrom(red.map, 0);
cmType = IcyColorMapType.GRAY;
}
else
cmType = IcyColorMapType.RGB;
if (notifyChange)
setType(cmType);
else
type = cmType;
}
/**
* Define the type of color map depending its RGBA data.<br>
* If map contains only alpha information then type = <code>IcyColorMapType.ALPHA</code><br>
* If map contains only grey level then type = <code>IcyColorMapType.GRAY</code><br>
* else type = <code>IcyColorMapType.RGB</code>
*/
public void setTypeFromData()
{
setTypeFromData(true);
}
/**
* Set a red control point to specified index and value
*/
public void setRedControlPoint(int index, int value)
{
// set control point
red.setControlPoint(index, value);
}
/**
* Set a green control point to specified index and value
*/
public void setGreenControlPoint(int index, int value)
{
green.setControlPoint(index, value);
}
/**
* Set a blue control point to specified index and value
*/
public void setBlueControlPoint(int index, int value)
{
blue.setControlPoint(index, value);
}
/**
* Set a gray control point to specified index and value
*/
public void setGrayControlPoint(int index, int value)
{
gray.setControlPoint(index, value);
}
/**
* Set a alpha control point to specified index and value
*/
public void setAlphaControlPoint(int index, int value)
{
alpha.setControlPoint(index, value);
}
/**
* Set RGB control point values to specified index
*/
public void setRGBControlPoint(int index, Color value)
{
red.setControlPoint(index, (short) value.getRed());
green.setControlPoint(index, (short) value.getGreen());
blue.setControlPoint(index, (short) value.getBlue());
gray.setControlPoint(index, (short) ColorUtil.getGrayMix(value));
}
/**
* Set ARGB control point values to specified index
*/
public void setARGBControlPoint(int index, Color value)
{
alpha.setControlPoint(index, (short) value.getAlpha());
red.setControlPoint(index, (short) value.getRed());
green.setControlPoint(index, (short) value.getGreen());
blue.setControlPoint(index, (short) value.getBlue());
gray.setControlPoint(index, (short) ColorUtil.getGrayMix(value));
}
/**
* Returns the blue component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public short[] getBlueMap()
{
if (type == IcyColorMapType.RGB)
return blue.map;
if (type == IcyColorMapType.GRAY)
return gray.map;
return null;
}
/**
* Returns the green component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public short[] getGreenMap()
{
if (type == IcyColorMapType.RGB)
return green.map;
if (type == IcyColorMapType.GRAY)
return gray.map;
return null;
}
/**
* Returns the red component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public short[] getRedMap()
{
if (type == IcyColorMapType.RGB)
return red.map;
if (type == IcyColorMapType.GRAY)
return gray.map;
return null;
}
/**
* Returns the alpha component map.
*/
public short[] getAlphaMap()
{
return alpha.map;
}
/**
* Returns the normalized blue component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public float[] getNormalizedBlueMap()
{
if (type == IcyColorMapType.RGB)
return blue.mapf;
if (type == IcyColorMapType.GRAY)
return gray.mapf;
return null;
}
/**
* Returns the normalized green component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public float[] getNormalizedGreenMap()
{
if (type == IcyColorMapType.RGB)
return green.mapf;
if (type == IcyColorMapType.GRAY)
return gray.mapf;
return null;
}
/**
* Returns the normalized red component map.<br>
* If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead.
* If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>.
*/
public float[] getNormalizedRedMap()
{
if (type == IcyColorMapType.RGB)
return red.mapf;
if (type == IcyColorMapType.GRAY)
return gray.mapf;
return null;
}
/**
* Returns the normalized alpha component map.
*/
public float[] getNormalizedAlphaMap()
{
return alpha.mapf;
}
/**
* Get blue intensity from an input index
*
* @param index
* @return blue intensity ([0..255] range)
*/
public short getBlue(int index)
{
if (type == IcyColorMapType.RGB)
return blue.map[index];
if (type == IcyColorMapType.GRAY)
return gray.map[index];
return 0;
}
/**
* Get green intensity from an input index
*
* @param index
* @return green intensity ([0..255] range)
*/
public short getGreen(int index)
{
if (type == IcyColorMapType.RGB)
return green.map[index];
if (type == IcyColorMapType.GRAY)
return gray.map[index];
return 0;
}
/**
* Get red intensity from an input index
*
* @param index
* @return red intensity ([0..255] range)
*/
public short getRed(int index)
{
if (type == IcyColorMapType.RGB)
return red.map[index];
if (type == IcyColorMapType.GRAY)
return gray.map[index];
return 0;
}
/**
* Get alpha intensity from an input index
*
* @param index
* @return alpha intensity ([0..255] range)
*/
public short getAlpha(int index)
{
return alpha.map[index];
}
/**
* Get normalized blue intensity from an input index
*
* @param index
* @return normalized blue intensity
*/
public float getNormalizedBlue(int index)
{
if (type == IcyColorMapType.RGB)
return blue.mapf[index];
if (type == IcyColorMapType.GRAY)
return gray.mapf[index];
return 0;
}
/**
* Get normalized green intensity from an input index
*
* @param index
* @return normalized green intensity
*/
public float getNormalizedGreen(int index)
{
if (type == IcyColorMapType.RGB)
return green.mapf[index];
if (type == IcyColorMapType.GRAY)
return gray.mapf[index];
return 0;
}
/**
* Get normalized red intensity from an input index
*
* @param index
* @return normalized red intensity
*/
public float getNormalizedRed(int index)
{
if (type == IcyColorMapType.RGB)
return red.mapf[index];
if (type == IcyColorMapType.GRAY)
return gray.mapf[index];
return 0;
}
/**
* Get alpha normalized intensity from an input index
*
* @param index
* @return normalized alpha intensity
*/
public float getNormalizedAlpha(int index)
{
return alpha.mapf[index];
}
/**
* Get blue intensity from a normalized input index
*
* @param index
* @return blue intensity ([0..255] range)
*/
public short getBlue(float index)
{
return getBlue((int) (index * MAX_INDEX));
}
/**
* Get green intensity from a normalized input index
*
* @param index
* @return green intensity ([0..255] range)
*/
public short getGreen(float index)
{
return getGreen((int) (index * MAX_INDEX));
}
/**
* Get red intensity from a normalized input index
*
* @param index
* @return red intensity ([0..255] range)
*/
public short getRed(float index)
{
return getRed((int) (index * MAX_INDEX));
}
/**
* Get alpha intensity from a normalized input index
*
* @param index
* @return alpha intensity ([0..255] range)
*/
public short getAlpha(float index)
{
return getAlpha((int) (index * MAX_INDEX));
}
/**
* Get normalized blue intensity from a normalized input index
*
* @param index
* @return normalized blue intensity
*/
public float getNormalizedBlue(float index)
{
return getNormalizedBlue((int) (index * MAX_INDEX));
}
/**
* Get normalized green intensity from a normalized input index
*
* @param index
* @return normalized green intensity
*/
public float getNormalizedGreen(float index)
{
return getNormalizedGreen((int) (index * MAX_INDEX));
}
/**
* Get normalized red intensity from a normalized input index
*
* @param index
* @return normalized red intensity
*/
public float getNormalizedRed(float index)
{
return getNormalizedRed((int) (index * MAX_INDEX));
}
/**
* Get normalized alpha intensity from a normalized input index
*
* @param index
* @return normalized alpha intensity
*/
public float getNormalizedAlpha(float index)
{
return getNormalizedAlpha((int) (index * MAX_INDEX));
}
/**
* Set red intensity to specified index
*/
public void setRed(int index, short value)
{
red.setValue(index, value);
}
/**
* Set green intensity to specified index
*/
public void setGreen(int index, short value)
{
green.setValue(index, value);
}
/**
* Set blue intensity to specified index
*/
public void setBlue(int index, short value)
{
blue.setValue(index, value);
}
/**
* Set gray intensity to specified index
*/
public void setGray(int index, short value)
{
gray.setValue(index, value);
}
/**
* Set alpha intensity to specified index
*/
public void setAlpha(int index, short value)
{
alpha.setValue(index, value);
}
/**
* Set red intensity (normalized) to specified index
*/
public void setNormalizedRed(int index, float value)
{
red.setNormalizedValue(index, value);
}
/**
* Set green intensity (normalized) to specified index
*/
public void setNormalizedGreen(int index, float value)
{
green.setNormalizedValue(index, value);
}
/**
* Set blue intensity (normalized) to specified index
*/
public void setNormalizedBlue(int index, float value)
{
blue.setNormalizedValue(index, value);
}
/**
* Set gray intensity (normalized) to specified index
*/
public void setNormalizedGray(int index, float value)
{
gray.setNormalizedValue(index, value);
}
/**
* Set alpha intensity (normalized) to specified index
*/
public void setNormalizedAlpha(int index, float value)
{
alpha.setNormalizedValue(index, value);
}
/**
* Set RGB color to specified index
*/
public void setRGB(int index, int rgb)
{
alpha.setValue(index, MAX_LEVEL);
red.setValue(index, (rgb >> 16) & 0xFF);
green.setValue(index, (rgb >> 8) & 0xFF);
blue.setValue(index, (rgb >> 0) & 0xFF);
gray.setValue(index, ColorUtil.getGrayMix(rgb));
}
/**
* Set RGB color to specified index
*/
public void setRGB(int index, Color value)
{
setRGB(index, value.getRGB());
}
/**
* Set ARGB color to specified index
*/
public void setARGB(int index, int argb)
{
alpha.setValue(index, (argb >> 24) & 0xFF);
red.setValue(index, (argb >> 16) & 0xFF);
green.setValue(index, (argb >> 8) & 0xFF);
blue.setValue(index, (argb >> 0) & 0xFF);
gray.setValue(index, ColorUtil.getGrayMix(argb));
}
/**
* Set ARGB color to specified index
*/
public void setARGB(int index, Color value)
{
setARGB(index, value.getRGB());
}
/**
* Set the alpha channel to opaque
*/
public void setAlphaToOpaque()
{
alpha.beginUpdate();
try
{
alpha.removeAllControlPoint();
alpha.setControlPoint(0, 1f);
alpha.setControlPoint(255, 1f);
}
finally
{
alpha.endUpdate();
}
}
/**
* Set the alpha channel to linear opacity (0 to 1)
*/
public void setAlphaToLinear()
{
alpha.beginUpdate();
try
{
alpha.removeAllControlPoint();
alpha.setControlPoint(0, 0f);
alpha.setControlPoint(255, 1f);
}
finally
{
alpha.endUpdate();
}
}
/**
* Set the alpha channel to an optimized linear transparency for 3D volume display
*/
public void setAlphaToLinear3D()
{
alpha.beginUpdate();
try
{
alpha.removeAllControlPoint();
alpha.setControlPoint(0, 0f);
alpha.setControlPoint(32, 0f);
alpha.setControlPoint(255, 0.4f);
}
finally
{
alpha.endUpdate();
}
}
/**
* @deprecated Use {@link #setAlphaToLinear3D()} instead
*/
@Deprecated
public void setDefaultAlphaFor3D()
{
setAlphaToLinear3D();
}
/**
* @return the name
*/
public String getName()
{
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return the enabled
*/
public boolean isEnabled()
{
return enabled;
}
/**
* Set enabled flag.<br>
* This flag is used to test if the color map is enabled or not.<br>
* It is up to the developer to implement it or not.
*
* @param enabled
* the enabled to set
*/
public void setEnabled(boolean enabled)
{
if (this.enabled != enabled)
{
this.enabled = enabled;
changed(IcyColorMapEventType.ENABLED_CHANGED);
}
}
/**
* Gets a Color object representing the color at the specified index
*
* @param index
* the index of the color map to retrieve
* @return a Color object
*/
public Color getColor(int index)
{
switch (type)
{
case RGB:
return new Color(red.map[index], green.map[index], blue.map[index], alpha.map[index]);
case GRAY:
return new Color(gray.map[index], gray.map[index], gray.map[index], alpha.map[index]);
case ALPHA:
return new Color(0, 0, 0, alpha.map[index]);
}
return Color.black;
}
/**
* Return the pre-multiplied RGB cache
*/
public int[][] getPremulRGB()
{
return premulRGB;
}
/**
* Return the pre-multiplied RGB cache (normalized)
*/
public float[][] getPremulRGBNorm()
{
return premulRGBNorm;
}
/**
* Copy data from specified source colormap.
*
* @param copyAlpha
* Also copy the alpha information.
*/
public void copyFrom(IcyColorMap srcColorMap, boolean copyAlpha)
{
beginUpdate();
try
{
// copy colormap band
red.copyFrom(srcColorMap.red);
green.copyFrom(srcColorMap.green);
blue.copyFrom(srcColorMap.blue);
gray.copyFrom(srcColorMap.gray);
if (copyAlpha)
alpha.copyFrom(srcColorMap.alpha);
// copy type
setType(srcColorMap.type);
// copy name
setName(srcColorMap.getName());
}
finally
{
endUpdate();
}
}
/**
* Copy data from specified source colormap
*/
public void copyFrom(IcyColorMap srcColorMap)
{
copyFrom(srcColorMap, true);
}
/**
* Copy data from specified 2D byte array.
*
* @param copyAlpha
* Also copy the alpha information.
*/
public void copyFrom(byte[][] maps, boolean copyAlpha)
{
final int len = maps.length;
beginUpdate();
try
{
// red component
if (len > 0)
red.copyFrom(maps[0]);
if (len > 1)
green.copyFrom(maps[1]);
if (len > 2)
blue.copyFrom(maps[2]);
if (copyAlpha && (len > 3))
alpha.copyFrom(maps[3]);
}
finally
{
endUpdate();
}
}
/**
* Copy data from specified 2D byte array
*/
public void copyFrom(byte[][] maps)
{
copyFrom(maps, true);
}
/**
* Copy data from specified 2D short array.
*
* @param copyAlpha
* Also copy the alpha information.
*/
public void copyFrom(short[][] maps, boolean copyAlpha)
{
final int len = maps.length;
beginUpdate();
try
{
// red component
if (len > 0)
red.copyFrom(maps[0], 8);
if (len > 1)
green.copyFrom(maps[1], 8);
if (len > 2)
blue.copyFrom(maps[2], 8);
if (copyAlpha && (len > 3))
alpha.copyFrom(maps[3], 8);
}
finally
{
endUpdate();
}
}
/**
* Copy data from specified 2D short array.
*/
public void copyFrom(short[][] maps)
{
copyFrom(maps, true);
}
/**
* Return true if this is a linear type colormap.<br>
* Linear colormap are used to display plain gray or color image.<br>
* A non linear colormap means you usually have an indexed color image or
* you want to enhance contrast/color in display.
*/
public boolean isLinear()
{
switch (type)
{
default:
return red.isLinear() && green.isLinear() && blue.isLinear();
case GRAY:
return gray.isLinear();
case ALPHA:
return alpha.isLinear();
}
}
/**
* Return true if this is a total black colormap.
*/
public boolean isBlack()
{
switch (type)
{
case RGB:
for (int i = 0; i < MAX_INDEX; i++)
if ((red.map[i] | green.map[i] | blue.map[i]) != 0)
return false;
return true;
case GRAY:
for (int i = 0; i < MAX_INDEX; i++)
if (gray.map[i] != 0)
return false;
return true;
default:
return false;
}
}
/**
* Returns the dominant color of this colormap.<br>
* Warning: this need sometime to compute.
*/
public Color getDominantColor()
{
final Color colors[] = new Color[SIZE];
for (int i = 0; i < colors.length; i++)
colors[i] = getColor(i);
return ColorUtil.getDominantColor(colors);
}
/**
* Update internal RGB cache
*/
private void updateRGBCache()
{
for (int i = 0; i < SIZE; i++)
{
final float af = alpha.mapf[i];
final float rgbn[] = premulRGBNorm[i];
switch (type)
{
case GRAY:
final float grayValue = gray.mapf[i] * af;
rgbn[0] = grayValue;
rgbn[1] = grayValue;
rgbn[2] = grayValue;
break;
case RGB:
rgbn[0] = blue.mapf[i] * af;
rgbn[1] = green.mapf[i] * af;
rgbn[2] = red.mapf[i] * af;
break;
default:
rgbn[0] = 0f;
rgbn[1] = 0f;
rgbn[2] = 0f;
break;
}
final int rgb[] = premulRGB[i];
rgb[0] = (int) (rgbn[0] * MAX_LEVEL);
rgb[1] = (int) (rgbn[1] * MAX_LEVEL);
rgb[2] = (int) (rgbn[2] * MAX_LEVEL);
}
}
/**
* Add a listener
*
* @param listener
*/
public void addListener(IcyColorMapListener listener)
{
listeners.add(IcyColorMapListener.class, listener);
}
/**
* Remove a listener
*
* @param listener
*/
public void removeListener(IcyColorMapListener listener)
{
listeners.remove(IcyColorMapListener.class, listener);
}
/**
* fire event
*/
public void fireEvent(IcyColorMapEvent e)
{
for (IcyColorMapListener listener : listeners.getListeners(IcyColorMapListener.class))
listener.colorMapChanged(e);
}
/**
* called when colormap data changed
*/
public void changed()
{
changed(IcyColorMapEventType.MAP_CHANGED);
}
/**
* called when colormap changed
*/
private void changed(IcyColorMapEventType type)
{
// handle changed via updater object
updater.changed(new IcyColorMapEvent(this, type));
}
@Override
public void onChanged(CollapsibleEvent e)
{
final IcyColorMapEvent event = (IcyColorMapEvent) e;
switch (event.getType())
{
// refresh RGB cache
case MAP_CHANGED:
case TYPE_CHANGED:
updateRGBCache();
break;
default:
break;
}
// notify listener we have changed
fireEvent(event);
}
/**
* @see icy.common.UpdateEventHandler#beginUpdate()
*/
public void beginUpdate()
{
updater.beginUpdate();
red.beginUpdate();
green.beginUpdate();
blue.beginUpdate();
gray.beginUpdate();
alpha.beginUpdate();
}
/**
* @see icy.common.UpdateEventHandler#endUpdate()
*/
public void endUpdate()
{
alpha.endUpdate();
gray.endUpdate();
blue.endUpdate();
green.endUpdate();
red.endUpdate();
updater.endUpdate();
}
/**
* @see icy.common.UpdateEventHandler#isUpdating()
*/
public boolean isUpdating()
{
return updater.isUpdating();
}
@Override
public String toString()
{
return name;
}
/**
* Return true if the colormap has the same type and same color intensities than specified one.
*/
@Override
public boolean equals(Object obj)
{
if (obj == this)
return true;
if (obj instanceof IcyColorMap)
{
final IcyColorMap colormap = (IcyColorMap) obj;
if (colormap.getType() != type)
return false;
if (!red.equals(colormap.red))
return false;
if (!green.equals(colormap.green))
return false;
if (!blue.equals(colormap.blue))
return false;
if (!gray.equals(colormap.gray))
return false;
if (!alpha.equals(colormap.alpha))
return false;
return true;
}
return super.equals(obj);
}
@Override
public int hashCode()
{
return red.map.hashCode() ^ green.map.hashCode() ^ blue.map.hashCode() ^ gray.map.hashCode()
^ alpha.map.hashCode() ^ type.ordinal();
}
@Override
public boolean loadFromXML(Node node)
{
if (node == null)
return false;
beginUpdate();
try
{
setName(XMLUtil.getElementValue(node, ID_NAME, ""));
setEnabled(XMLUtil.getElementBooleanValue(node, ID_ENABLED, true));
setType(IcyColorMapType.valueOf(XMLUtil.getElementValue(node, ID_TYPE, IcyColorMapType.RGB.toString())));
boolean result = true;
result = result && red.loadFromXML(XMLUtil.getElement(node, ID_RED));
result = result && green.loadFromXML(XMLUtil.getElement(node, ID_GREEN));
result = result && blue.loadFromXML(XMLUtil.getElement(node, ID_BLUE));
result = result && gray.loadFromXML(XMLUtil.getElement(node, ID_GRAY));
result = result && alpha.loadFromXML(XMLUtil.getElement(node, ID_ALPHA));
return result;
}
finally
{
endUpdate();
}
}
@Override
public boolean saveToXML(Node node)
{
if (node == null)
return false;
XMLUtil.setElementValue(node, ID_NAME, getName());
XMLUtil.setElementBooleanValue(node, ID_ENABLED, isEnabled());
XMLUtil.setElementValue(node, ID_TYPE, getType().toString());
boolean result = true;
result = result && red.saveToXML(XMLUtil.setElement(node, ID_RED));
result = result && green.saveToXML(XMLUtil.setElement(node, ID_GREEN));
result = result && blue.saveToXML(XMLUtil.setElement(node, ID_BLUE));
result = result && gray.saveToXML(XMLUtil.setElement(node, ID_GRAY));
result = result && alpha.saveToXML(XMLUtil.setElement(node, ID_ALPHA));
return result;
}
}