001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.image.colormap; 020 021import icy.common.CollapsibleEvent; 022import icy.common.UpdateEventHandler; 023import icy.common.listener.ChangeListener; 024import icy.file.FileUtil; 025import icy.file.xml.XMLPersistent; 026import icy.file.xml.XMLPersistentHelper; 027import icy.image.colormap.IcyColorMapEvent.IcyColorMapEventType; 028import icy.util.ColorUtil; 029import icy.util.XMLUtil; 030 031import java.awt.Color; 032import java.io.File; 033import java.util.ArrayList; 034import java.util.List; 035 036import javax.swing.event.EventListenerList; 037 038import org.w3c.dom.Node; 039 040/** 041 * @author stephane 042 */ 043public class IcyColorMap implements ChangeListener, XMLPersistent 044{ 045 public enum IcyColorMapType 046 { 047 RGB, GRAY, ALPHA 048 }; 049 050 private static final String ID_TYPE = "type"; 051 private static final String ID_NAME = "name"; 052 private static final String ID_ENABLED = "enabled"; 053 private static final String ID_RED = "red"; 054 private static final String ID_GREEN = "green"; 055 private static final String ID_BLUE = "blue"; 056 private static final String ID_GRAY = "gray"; 057 private static final String ID_ALPHA = "alpha"; 058 059 /** 060 * define the wanted colormap bits resolution (never change it) 061 */ 062 public static final int COLORMAP_BITS = 8; 063 public static final int MAX_LEVEL = (1 << COLORMAP_BITS) - 1; 064 065 /** 066 * define colormap size 067 */ 068 public static final int SIZE = 256; 069 public static final int MAX_INDEX = SIZE - 1; 070 071 /** 072 * default colormap directory 073 */ 074 public static final String DEFAULT_COLORMAP_DIR = "colormap"; 075 076 /** 077 * Custom (user) colormap 078 */ 079 private static List<IcyColorMap> customMaps = null; 080 081 /** 082 * Returns the list of default linear colormap:<br/> 083 * GRAY, [GRAY_INV,] RED, GREEN, BLUE, MAGENTA, YELLOW, CYAN, [ALPHA] 084 * 085 * @param wantGrayInverse 086 * specify if we want the gray inverse colormap 087 * @param wantAlpha 088 * specify if we want the alpha colormap 089 */ 090 public static List<IcyColorMap> getLinearColorMaps(boolean wantGrayInverse, boolean wantAlpha) 091 { 092 final List<IcyColorMap> result = new ArrayList<IcyColorMap>(); 093 094 result.add(LinearColorMap.gray_); 095 if (wantGrayInverse) 096 result.add(LinearColorMap.gray_inv_); 097 result.add(LinearColorMap.red_); 098 result.add(LinearColorMap.green_); 099 result.add(LinearColorMap.blue_); 100 result.add(LinearColorMap.magenta_); 101 result.add(LinearColorMap.yellow_); 102 result.add(LinearColorMap.cyan_); 103 if (wantAlpha) 104 result.add(LinearColorMap.alpha_); 105 106 return result; 107 } 108 109 /** 110 * Returns the list of special colormap:<br/> 111 * ICE, FIRE, HSV, JET, GLOW 112 */ 113 public static List<IcyColorMap> getSpecialColorMaps() 114 { 115 final List<IcyColorMap> result = new ArrayList<IcyColorMap>(); 116 117 result.add(new IceColorMap()); 118 result.add(new FireColorMap()); 119 result.add(new HSVColorMap()); 120 result.add(new JETColorMap()); 121 result.add(new GlowColorMap(true)); 122 123 return result; 124 } 125 126 /** 127 * Returns the list of custom colormap available in the Icy "colormap" folder 128 */ 129 public static synchronized List<IcyColorMap> getCustomColorMaps() 130 { 131 if (customMaps == null) 132 { 133 // load custom maps 134 customMaps = new ArrayList<IcyColorMap>(); 135 136 // add saved colormap 137 for (File f : FileUtil.getFiles(new File(DEFAULT_COLORMAP_DIR), null, false, false, false)) 138 { 139 final IcyColorMap map = new IcyColorMap(); 140 if (XMLPersistentHelper.loadFromXML(map, f)) 141 customMaps.add(map); 142 } 143 } 144 145 return new ArrayList<IcyColorMap>(customMaps); 146 } 147 148 /** 149 * Returns the list of all available colormaps.<br/> 150 * The order of returned colormap map is Linear, Special and Custom. 151 * 152 * @param wantGrayInverse 153 * specify if we want the gray inverse colormap 154 * @param wantAlpha 155 * specify if we want the alpha colormap 156 */ 157 public static synchronized List<IcyColorMap> getAllColorMaps(boolean wantGrayInverse, boolean wantAlpha) 158 { 159 final List<IcyColorMap> result = new ArrayList<IcyColorMap>(); 160 161 result.addAll(getLinearColorMaps(false, false)); 162 result.addAll(getSpecialColorMaps()); 163 result.addAll(getCustomColorMaps()); 164 165 return result; 166 } 167 168 /** 169 * colormap name 170 */ 171 private String name; 172 173 /** 174 * enabled flag 175 */ 176 private boolean enabled; 177 178 /** 179 * RED band 180 */ 181 public final IcyColorMapComponent red; 182 /** 183 * GREEN band 184 */ 185 public final IcyColorMapComponent green; 186 /** 187 * BLUE band 188 */ 189 public final IcyColorMapComponent blue; 190 /** 191 * GRAY band 192 */ 193 public final IcyColorMapComponent gray; 194 /** 195 * ALPHA band 196 */ 197 public final IcyColorMapComponent alpha; 198 199 /** 200 * colormap type 201 */ 202 private IcyColorMapType type; 203 204 /** 205 * pre-multiplied RGB caches 206 */ 207 private final int premulRGB[][]; 208 private final float premulRGBNorm[][]; 209 210 /** 211 * listeners 212 */ 213 private final EventListenerList listeners; 214 215 /** 216 * internal updater 217 */ 218 private final UpdateEventHandler updater; 219 220 public IcyColorMap(String name, IcyColorMapType type) 221 { 222 this.name = name; 223 enabled = true; 224 225 listeners = new EventListenerList(); 226 updater = new UpdateEventHandler(this, false); 227 228 // colormap band 229 red = createColorMapBand((short) 0); 230 green = createColorMapBand((short) 0); 231 blue = createColorMapBand((short) 0); 232 gray = createColorMapBand((short) 0); 233 alpha = createColorMapBand((short) 255); 234 235 this.type = type; 236 237 // allocating and init RGB cache 238 premulRGB = new int[IcyColorMap.SIZE][3]; 239 premulRGBNorm = new float[IcyColorMap.SIZE][3]; 240 } 241 242 public IcyColorMap(String name) 243 { 244 this(name, IcyColorMapType.RGB); 245 } 246 247 public IcyColorMap(String name, Object maps) 248 { 249 this(name, IcyColorMapType.RGB); 250 251 if (maps instanceof byte[][]) 252 copyFrom((byte[][]) maps); 253 else if (maps instanceof short[][]) 254 copyFrom((short[][]) maps); 255 256 // try to define color map type from data 257 setTypeFromData(false); 258 } 259 260 /** 261 * Create a copy of specified colormap. 262 */ 263 public IcyColorMap(IcyColorMap colormap) 264 { 265 this(colormap.name, colormap.type); 266 267 copyFrom(colormap); 268 } 269 270 public IcyColorMap() 271 { 272 this(""); 273 } 274 275 protected IcyColorMapComponent createColorMapBand(short initValue) 276 { 277 return new IcyColorMapComponent(IcyColorMap.this, initValue); 278 } 279 280 /** 281 * Return true if this color map is RGB type 282 */ 283 public boolean isRGB() 284 { 285 return type == IcyColorMapType.RGB; 286 } 287 288 /** 289 * Return true if this color map is GRAY type 290 */ 291 public boolean isGray() 292 { 293 return type == IcyColorMapType.GRAY; 294 } 295 296 /** 297 * Return true if this color map is ALPHA type 298 */ 299 public boolean isAlpha() 300 { 301 return type == IcyColorMapType.ALPHA; 302 } 303 304 /** 305 * @return the type 306 */ 307 public IcyColorMapType getType() 308 { 309 return type; 310 } 311 312 /** 313 * @param value 314 * the type to set 315 */ 316 public void setType(IcyColorMapType value) 317 { 318 if (type != value) 319 { 320 type = value; 321 322 changed(IcyColorMapEventType.TYPE_CHANGED); 323 } 324 } 325 326 /** 327 * @see IcyColorMap#setTypeFromData() 328 */ 329 public void setTypeFromData(boolean notifyChange) 330 { 331 boolean grayColor = true; 332 boolean noColor = true; 333 boolean hasAlpha = false; 334 IcyColorMapType cmType; 335 336 for (int i = 0; i < MAX_INDEX; i++) 337 { 338 final short r = red.map[i]; 339 final short g = green.map[i]; 340 final short b = blue.map[i]; 341 final short a = alpha.map[i]; 342 343 grayColor &= (r == g) && (r == b); 344 noColor &= (r == 0) && (g == 0) && (b == 0); 345 hasAlpha |= (a != MAX_LEVEL); 346 } 347 348 if (noColor && hasAlpha) 349 cmType = IcyColorMapType.ALPHA; 350 else if (grayColor && !noColor) 351 { 352 // set gray map 353 gray.copyFrom(red.map, 0); 354 cmType = IcyColorMapType.GRAY; 355 } 356 else 357 cmType = IcyColorMapType.RGB; 358 359 if (notifyChange) 360 setType(cmType); 361 else 362 type = cmType; 363 } 364 365 /** 366 * Define the type of color map depending its RGBA data.<br> 367 * If map contains only alpha information then type = <code>IcyColorMapType.ALPHA</code><br> 368 * If map contains only grey level then type = <code>IcyColorMapType.GRAY</code><br> 369 * else type = <code>IcyColorMapType.RGB</code> 370 */ 371 public void setTypeFromData() 372 { 373 setTypeFromData(true); 374 } 375 376 /** 377 * Set a red control point to specified index and value 378 */ 379 public void setRedControlPoint(int index, int value) 380 { 381 // set control point 382 red.setControlPoint(index, value); 383 } 384 385 /** 386 * Set a green control point to specified index and value 387 */ 388 public void setGreenControlPoint(int index, int value) 389 { 390 green.setControlPoint(index, value); 391 } 392 393 /** 394 * Set a blue control point to specified index and value 395 */ 396 public void setBlueControlPoint(int index, int value) 397 { 398 blue.setControlPoint(index, value); 399 } 400 401 /** 402 * Set a gray control point to specified index and value 403 */ 404 public void setGrayControlPoint(int index, int value) 405 { 406 gray.setControlPoint(index, value); 407 } 408 409 /** 410 * Set a alpha control point to specified index and value 411 */ 412 public void setAlphaControlPoint(int index, int value) 413 { 414 alpha.setControlPoint(index, value); 415 } 416 417 /** 418 * Set RGB control point values to specified index 419 */ 420 public void setRGBControlPoint(int index, Color value) 421 { 422 red.setControlPoint(index, (short) value.getRed()); 423 green.setControlPoint(index, (short) value.getGreen()); 424 blue.setControlPoint(index, (short) value.getBlue()); 425 gray.setControlPoint(index, (short) ColorUtil.getGrayMix(value)); 426 } 427 428 /** 429 * Set ARGB control point values to specified index 430 */ 431 public void setARGBControlPoint(int index, Color value) 432 { 433 alpha.setControlPoint(index, (short) value.getAlpha()); 434 red.setControlPoint(index, (short) value.getRed()); 435 green.setControlPoint(index, (short) value.getGreen()); 436 blue.setControlPoint(index, (short) value.getBlue()); 437 gray.setControlPoint(index, (short) ColorUtil.getGrayMix(value)); 438 } 439 440 /** 441 * Returns the blue component map.<br> 442 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 443 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 444 */ 445 public short[] getBlueMap() 446 { 447 if (type == IcyColorMapType.RGB) 448 return blue.map; 449 if (type == IcyColorMapType.GRAY) 450 return gray.map; 451 452 return null; 453 } 454 455 /** 456 * Returns the green component map.<br> 457 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 458 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 459 */ 460 public short[] getGreenMap() 461 { 462 if (type == IcyColorMapType.RGB) 463 return green.map; 464 if (type == IcyColorMapType.GRAY) 465 return gray.map; 466 467 return null; 468 } 469 470 /** 471 * Returns the red component map.<br> 472 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 473 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 474 */ 475 public short[] getRedMap() 476 { 477 if (type == IcyColorMapType.RGB) 478 return red.map; 479 if (type == IcyColorMapType.GRAY) 480 return gray.map; 481 482 return null; 483 } 484 485 /** 486 * Returns the alpha component map. 487 */ 488 public short[] getAlphaMap() 489 { 490 return alpha.map; 491 } 492 493 /** 494 * Returns the normalized blue component map.<br> 495 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 496 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 497 */ 498 public float[] getNormalizedBlueMap() 499 { 500 if (type == IcyColorMapType.RGB) 501 return blue.mapf; 502 if (type == IcyColorMapType.GRAY) 503 return gray.mapf; 504 505 return null; 506 } 507 508 /** 509 * Returns the normalized green component map.<br> 510 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 511 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 512 */ 513 public float[] getNormalizedGreenMap() 514 { 515 if (type == IcyColorMapType.RGB) 516 return green.mapf; 517 if (type == IcyColorMapType.GRAY) 518 return gray.mapf; 519 520 return null; 521 } 522 523 /** 524 * Returns the normalized red component map.<br> 525 * If the color map type is {@link IcyColorMapType#GRAY} then it returns the gray map instead. 526 * If the color map type is {@link IcyColorMapType#ALPHA} then it returns <code>null</code>. 527 */ 528 public float[] getNormalizedRedMap() 529 { 530 if (type == IcyColorMapType.RGB) 531 return red.mapf; 532 if (type == IcyColorMapType.GRAY) 533 return gray.mapf; 534 535 return null; 536 } 537 538 /** 539 * Returns the normalized alpha component map. 540 */ 541 public float[] getNormalizedAlphaMap() 542 { 543 return alpha.mapf; 544 } 545 546 /** 547 * Get blue intensity from an input index 548 * 549 * @param index 550 * @return blue intensity ([0..255] range) 551 */ 552 public short getBlue(int index) 553 { 554 if (type == IcyColorMapType.RGB) 555 return blue.map[index]; 556 if (type == IcyColorMapType.GRAY) 557 return gray.map[index]; 558 559 return 0; 560 } 561 562 /** 563 * Get green intensity from an input index 564 * 565 * @param index 566 * @return green intensity ([0..255] range) 567 */ 568 public short getGreen(int index) 569 { 570 if (type == IcyColorMapType.RGB) 571 return green.map[index]; 572 if (type == IcyColorMapType.GRAY) 573 return gray.map[index]; 574 575 return 0; 576 } 577 578 /** 579 * Get red intensity from an input index 580 * 581 * @param index 582 * @return red intensity ([0..255] range) 583 */ 584 public short getRed(int index) 585 { 586 if (type == IcyColorMapType.RGB) 587 return red.map[index]; 588 if (type == IcyColorMapType.GRAY) 589 return gray.map[index]; 590 591 return 0; 592 } 593 594 /** 595 * Get alpha intensity from an input index 596 * 597 * @param index 598 * @return alpha intensity ([0..255] range) 599 */ 600 public short getAlpha(int index) 601 { 602 return alpha.map[index]; 603 } 604 605 /** 606 * Get normalized blue intensity from an input index 607 * 608 * @param index 609 * @return normalized blue intensity 610 */ 611 public float getNormalizedBlue(int index) 612 { 613 if (type == IcyColorMapType.RGB) 614 return blue.mapf[index]; 615 if (type == IcyColorMapType.GRAY) 616 return gray.mapf[index]; 617 618 return 0; 619 } 620 621 /** 622 * Get normalized green intensity from an input index 623 * 624 * @param index 625 * @return normalized green intensity 626 */ 627 public float getNormalizedGreen(int index) 628 { 629 if (type == IcyColorMapType.RGB) 630 return green.mapf[index]; 631 if (type == IcyColorMapType.GRAY) 632 return gray.mapf[index]; 633 634 return 0; 635 } 636 637 /** 638 * Get normalized red intensity from an input index 639 * 640 * @param index 641 * @return normalized red intensity 642 */ 643 public float getNormalizedRed(int index) 644 { 645 if (type == IcyColorMapType.RGB) 646 return red.mapf[index]; 647 if (type == IcyColorMapType.GRAY) 648 return gray.mapf[index]; 649 650 return 0; 651 } 652 653 /** 654 * Get alpha normalized intensity from an input index 655 * 656 * @param index 657 * @return normalized alpha intensity 658 */ 659 public float getNormalizedAlpha(int index) 660 { 661 return alpha.mapf[index]; 662 } 663 664 /** 665 * Get blue intensity from a normalized input index 666 * 667 * @param index 668 * @return blue intensity ([0..255] range) 669 */ 670 public short getBlue(float index) 671 { 672 return getBlue((int) (index * MAX_INDEX)); 673 } 674 675 /** 676 * Get green intensity from a normalized input index 677 * 678 * @param index 679 * @return green intensity ([0..255] range) 680 */ 681 public short getGreen(float index) 682 { 683 return getGreen((int) (index * MAX_INDEX)); 684 } 685 686 /** 687 * Get red intensity from a normalized input index 688 * 689 * @param index 690 * @return red intensity ([0..255] range) 691 */ 692 public short getRed(float index) 693 { 694 return getRed((int) (index * MAX_INDEX)); 695 } 696 697 /** 698 * Get alpha intensity from a normalized input index 699 * 700 * @param index 701 * @return alpha intensity ([0..255] range) 702 */ 703 public short getAlpha(float index) 704 { 705 return getAlpha((int) (index * MAX_INDEX)); 706 } 707 708 /** 709 * Get normalized blue intensity from a normalized input index 710 * 711 * @param index 712 * @return normalized blue intensity 713 */ 714 public float getNormalizedBlue(float index) 715 { 716 return getNormalizedBlue((int) (index * MAX_INDEX)); 717 } 718 719 /** 720 * Get normalized green intensity from a normalized input index 721 * 722 * @param index 723 * @return normalized green intensity 724 */ 725 public float getNormalizedGreen(float index) 726 { 727 return getNormalizedGreen((int) (index * MAX_INDEX)); 728 } 729 730 /** 731 * Get normalized red intensity from a normalized input index 732 * 733 * @param index 734 * @return normalized red intensity 735 */ 736 public float getNormalizedRed(float index) 737 { 738 return getNormalizedRed((int) (index * MAX_INDEX)); 739 } 740 741 /** 742 * Get normalized alpha intensity from a normalized input index 743 * 744 * @param index 745 * @return normalized alpha intensity 746 */ 747 public float getNormalizedAlpha(float index) 748 { 749 return getNormalizedAlpha((int) (index * MAX_INDEX)); 750 } 751 752 /** 753 * Set red intensity to specified index 754 */ 755 public void setRed(int index, short value) 756 { 757 red.setValue(index, value); 758 } 759 760 /** 761 * Set green intensity to specified index 762 */ 763 public void setGreen(int index, short value) 764 { 765 green.setValue(index, value); 766 } 767 768 /** 769 * Set blue intensity to specified index 770 */ 771 public void setBlue(int index, short value) 772 { 773 blue.setValue(index, value); 774 } 775 776 /** 777 * Set gray intensity to specified index 778 */ 779 public void setGray(int index, short value) 780 { 781 gray.setValue(index, value); 782 } 783 784 /** 785 * Set alpha intensity to specified index 786 */ 787 public void setAlpha(int index, short value) 788 { 789 alpha.setValue(index, value); 790 } 791 792 /** 793 * Set red intensity (normalized) to specified index 794 */ 795 public void setNormalizedRed(int index, float value) 796 { 797 red.setNormalizedValue(index, value); 798 } 799 800 /** 801 * Set green intensity (normalized) to specified index 802 */ 803 public void setNormalizedGreen(int index, float value) 804 { 805 green.setNormalizedValue(index, value); 806 } 807 808 /** 809 * Set blue intensity (normalized) to specified index 810 */ 811 public void setNormalizedBlue(int index, float value) 812 { 813 blue.setNormalizedValue(index, value); 814 } 815 816 /** 817 * Set gray intensity (normalized) to specified index 818 */ 819 public void setNormalizedGray(int index, float value) 820 { 821 gray.setNormalizedValue(index, value); 822 } 823 824 /** 825 * Set alpha intensity (normalized) to specified index 826 */ 827 public void setNormalizedAlpha(int index, float value) 828 { 829 alpha.setNormalizedValue(index, value); 830 } 831 832 /** 833 * Set RGB color to specified index 834 */ 835 public void setRGB(int index, int rgb) 836 { 837 alpha.setValue(index, MAX_LEVEL); 838 red.setValue(index, (rgb >> 16) & 0xFF); 839 green.setValue(index, (rgb >> 8) & 0xFF); 840 blue.setValue(index, (rgb >> 0) & 0xFF); 841 gray.setValue(index, ColorUtil.getGrayMix(rgb)); 842 } 843 844 /** 845 * Set RGB color to specified index 846 */ 847 public void setRGB(int index, Color value) 848 { 849 setRGB(index, value.getRGB()); 850 } 851 852 /** 853 * Set ARGB color to specified index 854 */ 855 public void setARGB(int index, int argb) 856 { 857 alpha.setValue(index, (argb >> 24) & 0xFF); 858 red.setValue(index, (argb >> 16) & 0xFF); 859 green.setValue(index, (argb >> 8) & 0xFF); 860 blue.setValue(index, (argb >> 0) & 0xFF); 861 gray.setValue(index, ColorUtil.getGrayMix(argb)); 862 } 863 864 /** 865 * Set ARGB color to specified index 866 */ 867 public void setARGB(int index, Color value) 868 { 869 setARGB(index, value.getRGB()); 870 } 871 872 /** 873 * Set the alpha channel to opaque 874 */ 875 public void setAlphaToOpaque() 876 { 877 alpha.beginUpdate(); 878 try 879 { 880 alpha.removeAllControlPoint(); 881 alpha.setControlPoint(0, 1f); 882 alpha.setControlPoint(255, 1f); 883 } 884 finally 885 { 886 alpha.endUpdate(); 887 } 888 } 889 890 /** 891 * Set the alpha channel to linear opacity (0 to 1) 892 */ 893 public void setAlphaToLinear() 894 { 895 alpha.beginUpdate(); 896 try 897 { 898 alpha.removeAllControlPoint(); 899 alpha.setControlPoint(0, 0f); 900 alpha.setControlPoint(255, 1f); 901 } 902 finally 903 { 904 alpha.endUpdate(); 905 } 906 } 907 908 /** 909 * Set the alpha channel to an optimized linear transparency for 3D volume display 910 */ 911 public void setAlphaToLinear3D() 912 { 913 alpha.beginUpdate(); 914 try 915 { 916 alpha.removeAllControlPoint(); 917 alpha.setControlPoint(0, 0f); 918 alpha.setControlPoint(32, 0f); 919 alpha.setControlPoint(255, 0.4f); 920 } 921 finally 922 { 923 alpha.endUpdate(); 924 } 925 } 926 927 /** 928 * @deprecated Use {@link #setAlphaToLinear3D()} instead 929 */ 930 @Deprecated 931 public void setDefaultAlphaFor3D() 932 { 933 setAlphaToLinear3D(); 934 } 935 936 /** 937 * @return the name 938 */ 939 public String getName() 940 { 941 return name; 942 } 943 944 /** 945 * @param name 946 * the name to set 947 */ 948 public void setName(String name) 949 { 950 this.name = name; 951 } 952 953 /** 954 * @return the enabled 955 */ 956 public boolean isEnabled() 957 { 958 return enabled; 959 } 960 961 /** 962 * Set enabled flag.<br> 963 * This flag is used to test if the color map is enabled or not.<br> 964 * It is up to the developer to implement it or not. 965 * 966 * @param enabled 967 * the enabled to set 968 */ 969 public void setEnabled(boolean enabled) 970 { 971 if (this.enabled != enabled) 972 { 973 this.enabled = enabled; 974 changed(IcyColorMapEventType.ENABLED_CHANGED); 975 } 976 } 977 978 /** 979 * Gets a Color object representing the color at the specified index 980 * 981 * @param index 982 * the index of the color map to retrieve 983 * @return a Color object 984 */ 985 public Color getColor(int index) 986 { 987 switch (type) 988 { 989 case RGB: 990 return new Color(red.map[index], green.map[index], blue.map[index], alpha.map[index]); 991 case GRAY: 992 return new Color(gray.map[index], gray.map[index], gray.map[index], alpha.map[index]); 993 case ALPHA: 994 return new Color(0, 0, 0, alpha.map[index]); 995 } 996 997 return Color.black; 998 } 999 1000 /** 1001 * Return the pre-multiplied RGB cache 1002 */ 1003 public int[][] getPremulRGB() 1004 { 1005 return premulRGB; 1006 } 1007 1008 /** 1009 * Return the pre-multiplied RGB cache (normalized) 1010 */ 1011 public float[][] getPremulRGBNorm() 1012 { 1013 return premulRGBNorm; 1014 } 1015 1016 /** 1017 * Copy data from specified source colormap. 1018 * 1019 * @param copyAlpha 1020 * Also copy the alpha information. 1021 */ 1022 public void copyFrom(IcyColorMap srcColorMap, boolean copyAlpha) 1023 { 1024 beginUpdate(); 1025 try 1026 { 1027 // copy colormap band 1028 red.copyFrom(srcColorMap.red); 1029 green.copyFrom(srcColorMap.green); 1030 blue.copyFrom(srcColorMap.blue); 1031 gray.copyFrom(srcColorMap.gray); 1032 // copy alpha information for alpha type colormap 1033 if (copyAlpha || isAlpha()) 1034 alpha.copyFrom(srcColorMap.alpha); 1035 // copy type 1036 setType(srcColorMap.type); 1037 // copy name 1038 setName(srcColorMap.getName()); 1039 } 1040 finally 1041 { 1042 endUpdate(); 1043 } 1044 } 1045 1046 /** 1047 * Copy data from specified source colormap 1048 */ 1049 public void copyFrom(IcyColorMap srcColorMap) 1050 { 1051 copyFrom(srcColorMap, true); 1052 } 1053 1054 /** 1055 * Copy data from specified 2D byte array. 1056 * 1057 * @param copyAlpha 1058 * Also copy the alpha information. 1059 */ 1060 public void copyFrom(byte[][] maps, boolean copyAlpha) 1061 { 1062 final int len = maps.length; 1063 1064 beginUpdate(); 1065 try 1066 { 1067 // red component 1068 if (len > 0) 1069 red.copyFrom(maps[0]); 1070 if (len > 1) 1071 green.copyFrom(maps[1]); 1072 if (len > 2) 1073 blue.copyFrom(maps[2]); 1074 if (copyAlpha && (len > 3)) 1075 alpha.copyFrom(maps[3]); 1076 } 1077 finally 1078 { 1079 endUpdate(); 1080 } 1081 } 1082 1083 /** 1084 * Copy data from specified 2D byte array 1085 */ 1086 public void copyFrom(byte[][] maps) 1087 { 1088 copyFrom(maps, true); 1089 } 1090 1091 /** 1092 * Copy data from specified 2D short array. 1093 * 1094 * @param copyAlpha 1095 * Also copy the alpha information. 1096 */ 1097 public void copyFrom(short[][] maps, boolean copyAlpha) 1098 { 1099 final int len = maps.length; 1100 1101 beginUpdate(); 1102 try 1103 { 1104 // red component 1105 if (len > 0) 1106 red.copyFrom(maps[0], 8); 1107 if (len > 1) 1108 green.copyFrom(maps[1], 8); 1109 if (len > 2) 1110 blue.copyFrom(maps[2], 8); 1111 if (copyAlpha && (len > 3)) 1112 alpha.copyFrom(maps[3], 8); 1113 } 1114 finally 1115 { 1116 endUpdate(); 1117 } 1118 } 1119 1120 /** 1121 * Copy data from specified 2D short array. 1122 */ 1123 public void copyFrom(short[][] maps) 1124 { 1125 copyFrom(maps, true); 1126 } 1127 1128 /** 1129 * Return true if this is a linear type colormap.<br> 1130 * Linear colormap are used to display plain gray or color image.<br> 1131 * A non linear colormap means you usually have an indexed color image or 1132 * you want to enhance contrast/color in display. 1133 */ 1134 public boolean isLinear() 1135 { 1136 switch (type) 1137 { 1138 default: 1139 return red.isLinear() && green.isLinear() && blue.isLinear(); 1140 case GRAY: 1141 return gray.isLinear(); 1142 case ALPHA: 1143 return alpha.isLinear(); 1144 } 1145 } 1146 1147 /** 1148 * Return true if this is a total black colormap. 1149 */ 1150 public boolean isBlack() 1151 { 1152 switch (type) 1153 { 1154 case RGB: 1155 for (int i = 0; i < MAX_INDEX; i++) 1156 if ((red.map[i] | green.map[i] | blue.map[i]) != 0) 1157 return false; 1158 return true; 1159 1160 case GRAY: 1161 for (int i = 0; i < MAX_INDEX; i++) 1162 if (gray.map[i] != 0) 1163 return false; 1164 return true; 1165 1166 default: 1167 return false; 1168 } 1169 } 1170 1171 /** 1172 * Returns the dominant color of this colormap.<br> 1173 * Warning: this need sometime to compute. 1174 */ 1175 public Color getDominantColor() 1176 { 1177 final Color colors[] = new Color[SIZE]; 1178 1179 for (int i = 0; i < colors.length; i++) 1180 colors[i] = getColor(i); 1181 1182 return ColorUtil.getDominantColor(colors); 1183 } 1184 1185 /** 1186 * Update internal RGB cache 1187 */ 1188 private void updateRGBCache() 1189 { 1190 for (int i = 0; i < SIZE; i++) 1191 { 1192 final float af = alpha.mapf[i]; 1193 final float rgbn[] = premulRGBNorm[i]; 1194 1195 switch (type) 1196 { 1197 case GRAY: 1198 final float grayValue = gray.mapf[i] * af; 1199 rgbn[0] = grayValue; 1200 rgbn[1] = grayValue; 1201 rgbn[2] = grayValue; 1202 break; 1203 1204 case RGB: 1205 rgbn[0] = blue.mapf[i] * af; 1206 rgbn[1] = green.mapf[i] * af; 1207 rgbn[2] = red.mapf[i] * af; 1208 break; 1209 1210 default: 1211 rgbn[0] = 0f; 1212 rgbn[1] = 0f; 1213 rgbn[2] = 0f; 1214 break; 1215 } 1216 1217 final int rgb[] = premulRGB[i]; 1218 1219 rgb[0] = (int) (rgbn[0] * MAX_LEVEL); 1220 rgb[1] = (int) (rgbn[1] * MAX_LEVEL); 1221 rgb[2] = (int) (rgbn[2] * MAX_LEVEL); 1222 } 1223 } 1224 1225 /** 1226 * Add a listener 1227 * 1228 * @param listener 1229 */ 1230 public void addListener(IcyColorMapListener listener) 1231 { 1232 listeners.add(IcyColorMapListener.class, listener); 1233 } 1234 1235 /** 1236 * Remove a listener 1237 * 1238 * @param listener 1239 */ 1240 public void removeListener(IcyColorMapListener listener) 1241 { 1242 listeners.remove(IcyColorMapListener.class, listener); 1243 } 1244 1245 /** 1246 * fire event 1247 */ 1248 public void fireEvent(IcyColorMapEvent e) 1249 { 1250 for (IcyColorMapListener listener : listeners.getListeners(IcyColorMapListener.class)) 1251 listener.colorMapChanged(e); 1252 } 1253 1254 /** 1255 * called when colormap data changed 1256 */ 1257 public void changed() 1258 { 1259 changed(IcyColorMapEventType.MAP_CHANGED); 1260 } 1261 1262 /** 1263 * called when colormap changed 1264 */ 1265 private void changed(IcyColorMapEventType type) 1266 { 1267 // handle changed via updater object 1268 updater.changed(new IcyColorMapEvent(this, type)); 1269 } 1270 1271 @Override 1272 public void onChanged(CollapsibleEvent e) 1273 { 1274 final IcyColorMapEvent event = (IcyColorMapEvent) e; 1275 1276 switch (event.getType()) 1277 { 1278 // refresh RGB cache 1279 case MAP_CHANGED: 1280 case TYPE_CHANGED: 1281 updateRGBCache(); 1282 break; 1283 1284 default: 1285 break; 1286 } 1287 1288 // notify listener we have changed 1289 fireEvent(event); 1290 } 1291 1292 /** 1293 * @see icy.common.UpdateEventHandler#beginUpdate() 1294 */ 1295 public void beginUpdate() 1296 { 1297 updater.beginUpdate(); 1298 1299 red.beginUpdate(); 1300 green.beginUpdate(); 1301 blue.beginUpdate(); 1302 gray.beginUpdate(); 1303 alpha.beginUpdate(); 1304 } 1305 1306 /** 1307 * @see icy.common.UpdateEventHandler#endUpdate() 1308 */ 1309 public void endUpdate() 1310 { 1311 alpha.endUpdate(); 1312 gray.endUpdate(); 1313 blue.endUpdate(); 1314 green.endUpdate(); 1315 red.endUpdate(); 1316 1317 updater.endUpdate(); 1318 } 1319 1320 /** 1321 * @see icy.common.UpdateEventHandler#isUpdating() 1322 */ 1323 public boolean isUpdating() 1324 { 1325 return updater.isUpdating(); 1326 } 1327 1328 @Override 1329 public String toString() 1330 { 1331 return name; 1332 } 1333 1334 /** 1335 * Return true if the colormap has the same type and same color intensities than specified one. 1336 */ 1337 @Override 1338 public boolean equals(Object obj) 1339 { 1340 if (obj == this) 1341 return true; 1342 1343 if (obj instanceof IcyColorMap) 1344 { 1345 final IcyColorMap colormap = (IcyColorMap) obj; 1346 1347 if (colormap.getType() != type) 1348 return false; 1349 1350 if (!red.equals(colormap.red)) 1351 return false; 1352 if (!green.equals(colormap.green)) 1353 return false; 1354 if (!blue.equals(colormap.blue)) 1355 return false; 1356 if (!gray.equals(colormap.gray)) 1357 return false; 1358 if (!alpha.equals(colormap.alpha)) 1359 return false; 1360 1361 return true; 1362 } 1363 1364 return super.equals(obj); 1365 } 1366 1367 @Override 1368 public int hashCode() 1369 { 1370 return red.map.hashCode() ^ green.map.hashCode() ^ blue.map.hashCode() ^ gray.map.hashCode() 1371 ^ alpha.map.hashCode() ^ type.ordinal(); 1372 } 1373 1374 @Override 1375 public boolean loadFromXML(Node node) 1376 { 1377 if (node == null) 1378 return false; 1379 1380 beginUpdate(); 1381 try 1382 { 1383 setName(XMLUtil.getElementValue(node, ID_NAME, "")); 1384 setEnabled(XMLUtil.getElementBooleanValue(node, ID_ENABLED, true)); 1385 setType(IcyColorMapType.valueOf(XMLUtil.getElementValue(node, ID_TYPE, IcyColorMapType.RGB.toString()))); 1386 1387 boolean result = true; 1388 1389 result = result && red.loadFromXML(XMLUtil.getElement(node, ID_RED)); 1390 result = result && green.loadFromXML(XMLUtil.getElement(node, ID_GREEN)); 1391 result = result && blue.loadFromXML(XMLUtil.getElement(node, ID_BLUE)); 1392 result = result && gray.loadFromXML(XMLUtil.getElement(node, ID_GRAY)); 1393 result = result && alpha.loadFromXML(XMLUtil.getElement(node, ID_ALPHA)); 1394 1395 return result; 1396 } 1397 finally 1398 { 1399 endUpdate(); 1400 } 1401 } 1402 1403 @Override 1404 public boolean saveToXML(Node node) 1405 { 1406 if (node == null) 1407 return false; 1408 1409 XMLUtil.setElementValue(node, ID_NAME, getName()); 1410 XMLUtil.setElementBooleanValue(node, ID_ENABLED, isEnabled()); 1411 XMLUtil.setElementValue(node, ID_TYPE, getType().toString()); 1412 1413 boolean result = true; 1414 1415 result = result && red.saveToXML(XMLUtil.setElement(node, ID_RED)); 1416 result = result && green.saveToXML(XMLUtil.setElement(node, ID_GREEN)); 1417 result = result && blue.saveToXML(XMLUtil.setElement(node, ID_BLUE)); 1418 result = result && gray.saveToXML(XMLUtil.setElement(node, ID_GRAY)); 1419 result = result && alpha.saveToXML(XMLUtil.setElement(node, ID_ALPHA)); 1420 1421 return result; 1422 } 1423 1424}