/* * 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; } }