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.colorspace; 020 021import icy.common.CollapsibleEvent; 022import icy.common.UpdateEventHandler; 023import icy.common.listener.ChangeListener; 024import icy.image.colormap.FromRGBColorMap; 025import icy.image.colormap.IcyColorMap; 026import icy.image.colormap.IcyColorMap.IcyColorMapType; 027import icy.image.colormap.IcyColorMapEvent; 028import icy.image.colormap.IcyColorMapListener; 029import icy.image.colormap.LinearColorMap; 030import icy.image.colormodel.IcyColorModel; 031import icy.type.DataType; 032import icy.type.collection.array.ArrayUtil; 033import icy.util.ColorUtil; 034 035import java.awt.color.ColorSpace; 036import java.awt.image.ColorModel; 037import java.util.ArrayList; 038import java.util.List; 039 040/** 041 * @author stephane 042 */ 043public class IcyColorSpace extends ColorSpace implements ChangeListener, IcyColorMapListener 044{ 045 /** 046 * 047 */ 048 private static final long serialVersionUID = 6413334779215415163L; 049 050 /** 051 * toRGB colormaps 052 */ 053 private final IcyColorMap[] toRGBmaps; 054 /** 055 * fromRGB colormaps 056 */ 057 private final FromRGBColorMap[] fromRGBmaps; 058 059 /** 060 * use alpha 061 */ 062 // private boolean alphaEnabled; 063 064 /** 065 * listeners 066 */ 067 private final List<IcyColorSpaceListener> listeners; 068 069 /** 070 * internal updater 071 */ 072 private final UpdateEventHandler updater; 073 074 /** 075 * Create an icy colorspace object 076 * 077 * @param numComponents 078 * number of color component 079 */ 080 public IcyColorSpace(int numComponents) 081 { 082 super((numComponents > 1) ? 10 + numComponents : ColorSpace.TYPE_GRAY, numComponents); 083 084 if (numComponents == 0) 085 throw new IllegalArgumentException("numComponents must be > 0"); 086 087 // allocating toRGB colormaps 088 toRGBmaps = new IcyColorMap[numComponents]; 089 for (int i = 0; i < numComponents; i++) 090 { 091 final IcyColorMap colormap = new IcyColorMap("component " + i); 092 toRGBmaps[i] = colormap; 093 // add listener 094 colormap.addListener(this); 095 } 096 097 // allocating fromRGB colormaps 098 fromRGBmaps = new FromRGBColorMap[4]; 099 for (int i = 0; i < 4; i++) 100 fromRGBmaps[i] = new FromRGBColorMap(numComponents); 101 102 listeners = new ArrayList<IcyColorSpaceListener>(); 103 updater = new UpdateEventHandler(this, false); 104 105 beginUpdate(); 106 try 107 { 108 // single component: gray colormap 109 if (numComponents == 1) 110 setColorMap(0, LinearColorMap.white_, true); 111 else 112 { 113 // define default colormaps depending the number of component 114 for (int i = 0; i < numComponents; i++) 115 { 116 switch (i % 7) 117 { 118 case 0: 119 setColorMap(i, LinearColorMap.red_, true); 120 break; 121 case 1: 122 setColorMap(i, LinearColorMap.green_, true); 123 break; 124 case 2: 125 setColorMap(i, LinearColorMap.blue_, true); 126 break; 127 case 3: 128 setColorMap(i, LinearColorMap.cyan_, true); 129 break; 130 case 4: 131 setColorMap(i, LinearColorMap.magenta_, true); 132 break; 133 case 5: 134 setColorMap(i, LinearColorMap.yellow_, true); 135 break; 136 case 6: 137 setColorMap(i, LinearColorMap.white_, true); 138 break; 139 } 140 } 141 } 142 } 143 finally 144 { 145 endUpdate(); 146 } 147 148 // generate fromRGB maps 149 generateFromRGBColorMaps(); 150 } 151 152 /** 153 * Return true if the colorspace's colormap contains an alpha component<br> 154 * This is different from the isAlphaEnabled flag 155 */ 156 public boolean hasAlphaComponent() 157 { 158 for (int comp = 0; comp < toRGBmaps.length; comp++) 159 if (toRGBmaps[comp].getType() == IcyColorMapType.ALPHA) 160 return true; 161 162 return false; 163 } 164 165 /** 166 * Generate FromRGB colormaps from ToRGB ones 167 */ 168 private void generateFromRGBColorMaps() 169 { 170 for (int comp = 0; comp < toRGBmaps.length; comp++) 171 { 172 final IcyColorMap toRGBmap = toRGBmaps[comp]; 173 final float step = 1.0f / FromRGBColorMap.COLORMAP_MAX; 174 175 for (float intensity = 0.0f; intensity <= 1.0f; intensity += step) 176 { 177 // blue 178 fromRGBmaps[0].setFromRGBColor(comp, intensity, toRGBmap.getNormalizedBlue(intensity)); 179 // green 180 fromRGBmaps[1].setFromRGBColor(comp, intensity, toRGBmap.getNormalizedGreen(intensity)); 181 // red 182 fromRGBmaps[2].setFromRGBColor(comp, intensity, toRGBmap.getNormalizedRed(intensity)); 183 // alpha 184 fromRGBmaps[3].setFromRGBColor(comp, intensity, toRGBmap.getNormalizedAlpha(intensity)); 185 } 186 } 187 } 188 189 /** 190 * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) 191 */ 192 @Override 193 public float[] fromCIEXYZ(float[] colorvalue) 194 { 195 return fromRGB(ColorUtil.sRGB.fromCIEXYZ(colorvalue)); 196 } 197 198 /** 199 * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) 200 */ 201 @Override 202 public float[] toCIEXYZ(float[] colorvalue) 203 { 204 return ColorUtil.sRGB.toCIEXYZ(toRGB(colorvalue)); 205 } 206 207 /** 208 * @see java.awt.color.ColorSpace#fromRGB(float[]) 209 */ 210 @Override 211 public float[] fromRGB(float[] rgb) 212 { 213 final int numComponents = getNumComponents(); 214 final float[] result = new float[numComponents]; 215 216 final FromRGBColorMap blueMap = fromRGBmaps[0]; 217 final FromRGBColorMap greenMap = fromRGBmaps[1]; 218 final FromRGBColorMap redMap = fromRGBmaps[2]; 219 final FromRGBColorMap alphaMap = fromRGBmaps[3]; 220 221 final float blue = rgb[0]; 222 final float green = rgb[1]; 223 final float red = rgb[2]; 224 final float alpha; 225 if (rgb.length > 3) 226 alpha = rgb[3]; 227 else 228 alpha = 1.0f; 229 230 for (int comp = 0; comp < numComponents; comp++) 231 { 232 result[comp] = blueMap.getFromRGBColor(comp, blue); 233 result[comp] += greenMap.getFromRGBColor(comp, green); 234 result[comp] += redMap.getFromRGBColor(comp, red); 235 result[comp] *= alphaMap.getFromRGBColor(comp, alpha); 236 // limit 237 if (result[comp] > 1.0f) 238 result[comp] = 1.0f; 239 } 240 241 return result; 242 } 243 244 /** 245 * return normalized component values from ARGB packed integer values 246 * 247 * @param rgb 248 * @return float[] 249 */ 250 public float[] fromRGB(int rgb) 251 { 252 final int numComponents = getNumComponents(); 253 final float[] result = new float[numComponents]; 254 255 final FromRGBColorMap blueMap = fromRGBmaps[0]; 256 final FromRGBColorMap greenMap = fromRGBmaps[1]; 257 final FromRGBColorMap redMap = fromRGBmaps[2]; 258 final FromRGBColorMap alphaMap = fromRGBmaps[3]; 259 260 final int red, grn, blu, alp; 261 alp = (rgb >> 24) & 0xFF; 262 red = (rgb >> 16) & 0xFF; 263 grn = (rgb >> 8) & 0xFF; 264 blu = rgb & 0xFF; 265 266 for (int comp = 0; comp < numComponents; comp++) 267 { 268 result[comp] = blueMap.maps[comp][blu]; 269 result[comp] += greenMap.maps[comp][grn]; 270 result[comp] += redMap.maps[comp][red]; 271 result[comp] *= alphaMap.maps[comp][alp]; 272 // limit 273 if (result[comp] > 1.0f) 274 result[comp] = 1.0f; 275 } 276 277 return result; 278 } 279 280 /** 281 * return unnormalized ARGB values from colorMap scaled components values 282 * 283 * @param colorvalue 284 * @return ARGB as int 285 */ 286 public int toRGBUnnorm(final int[] colorvalue) 287 { 288 final int numComponents = Math.min(getNumComponents(), colorvalue.length); 289 290 // default alpha 291 float alpha = 1f; 292 // default max local alpha 293 float maxLocalAlpha = 0f; 294 // default RGB 295 int r = 0, g = 0, b = 0; 296 297 for (int comp = 0; comp < numComponents; comp++) 298 { 299 final IcyColorMap cm = toRGBmaps[comp]; 300 301 if (cm.isEnabled()) 302 { 303 final int value = colorvalue[comp]; 304 305 final float alphaValue = cm.alpha.mapf[value]; 306 307 // alpha channel ? 308 if (cm.getType() == IcyColorMapType.ALPHA) 309 alpha = alphaValue; 310 else if (alphaValue > maxLocalAlpha) 311 maxLocalAlpha = alphaValue; 312 313 final int premulRGB[] = cm.getPremulRGB()[value]; 314 315 b += premulRGB[0]; 316 g += premulRGB[1]; 317 r += premulRGB[2]; 318 } 319 } 320 321 // final alpha = alpha component value * maximum local alpha value 322 final int a = (int) (alpha * maxLocalAlpha * IcyColorMap.MAX_LEVEL); 323 324 if (a != 0) 325 { 326 final int inv = (1 << (IcyColorMap.COLORMAP_BITS + 8)) / a; 327 328 // normalize on alpha 329 b = (b * inv) >> 8; 330 g = (g * inv) >> 8; 331 r = (r * inv) >> 8; 332 } 333 334 return ((b > IcyColorMap.MAX_LEVEL) ? IcyColorMap.MAX_LEVEL : b) 335 | (((g > IcyColorMap.MAX_LEVEL) ? IcyColorMap.MAX_LEVEL : g) << 8) 336 | (((r > IcyColorMap.MAX_LEVEL) ? IcyColorMap.MAX_LEVEL : r) << 16) | (a << 24); 337 } 338 339 @Override 340 public float[] toRGB(float[] colorvalue) 341 { 342 final float[] result = new float[4]; 343 final int numComponents = Math.min(getNumComponents(), colorvalue.length); 344 345 // default alpha 346 float alpha = 1f; 347 // default max local alpha 348 float maxLocalAlpha = 0f; 349 // default RGB 350 float rf = 0f, gf = 0f, bf = 0f; 351 352 for (int comp = 0; comp < numComponents; comp++) 353 { 354 final IcyColorMap cm = toRGBmaps[comp]; 355 356 if (cm.isEnabled()) 357 { 358 final int value = (int) (colorvalue[comp] * IcyColorMap.MAX_INDEX); 359 final float alphaValue = cm.alpha.mapf[value]; 360 361 // alpha channel ? 362 if (cm.getType() == IcyColorMapType.ALPHA) 363 alpha = alphaValue; 364 else if (alphaValue > maxLocalAlpha) 365 maxLocalAlpha = alphaValue; 366 367 final float premulRGBNorm[] = cm.getPremulRGBNorm()[value]; 368 369 bf += premulRGBNorm[0]; 370 gf += premulRGBNorm[1]; 371 rf += premulRGBNorm[2]; 372 } 373 } 374 375 // final alpha = alpha component value * maximum local alpha value 376 final float af = alpha * maxLocalAlpha; 377 378 if (af != 0f) 379 { 380 final float inv = 1f / af; 381 382 // normalize on alpha 383 bf *= inv; 384 gf *= inv; 385 rf *= inv; 386 } 387 388 result[0] = (bf > 1f) ? 1f : bf; 389 result[1] = (gf > 1f) ? 1f : gf; 390 result[2] = (rf > 1f) ? 1f : rf; 391 result[3] = af; 392 393 return result; 394 } 395 396 /** 397 * Set 8 bit ARGB data in an ARGB buffer from a scaled input buffer 398 * 399 * @param unnormSrc 400 * source buffer containing unnormalized values ([0..255] range) for each component 401 * @param dest 402 * ARGB components buffer 403 */ 404 public void fillARGBBuffer(int[][] unnormSrc, int[] dest, int offset, int length) 405 { 406 final int numComponents = getNumComponents(); 407 408 if (numComponents > 0) 409 { 410 final int[] input = new int[numComponents]; 411 412 for (int i = 0; i < length; i++) 413 { 414 // get data value 415 for (int comp = 0; comp < numComponents; comp++) 416 input[comp] = unnormSrc[comp][i]; 417 418 // convert to RGBA 419 dest[offset + i] = toRGBUnnorm(input); 420 } 421 } 422 } 423 424 /** 425 * Set 8 bit ARGB data in an ARGB buffer from a scaled input buffer 426 * 427 * @param unnormSrc 428 * source buffer containing unnormalized values ([0..255] range) for each component 429 * @param dest 430 * ARGB components buffer 431 */ 432 public void fillARGBBuffer(int[][] unnormSrc, int[] dest) 433 { 434 if ((unnormSrc == null) || (dest == null)) 435 { 436 throw new IllegalArgumentException("Parameters 'unnormSrc' and 'destARGB' should not be null !"); 437 } 438 439 final int numComponents = getNumComponents(); 440 441 if (unnormSrc.length != numComponents) 442 { 443 throw new IllegalArgumentException("Parameters 'unnormSrc' size is [" + unnormSrc.length + "][..] where [" 444 + numComponents + "][..] is expected !"); 445 } 446 447 if (numComponents > 0) 448 { 449 final int size = unnormSrc[0].length; 450 final int[] input = new int[numComponents]; 451 452 for (int i = 0; i < size; i++) 453 { 454 // get data value 455 for (int comp = 0; comp < numComponents; comp++) 456 input[comp] = unnormSrc[comp][i]; 457 458 // convert to RGBA 459 dest[i] = toRGBUnnorm(input); 460 } 461 } 462 } 463 464 /** 465 * Return the number of component of colorSpace 466 */ 467 @Override 468 public int getNumComponents() 469 { 470 return toRGBmaps.length; 471 } 472 473 /** 474 * Return the colormap of the specified component. 475 */ 476 public IcyColorMap getColorMap(int component) 477 { 478 return toRGBmaps[component]; 479 } 480 481 /** 482 * @deprecated Use {@link #getColorMap(int)} instead (different case). 483 */ 484 @Deprecated 485 public IcyColorMap getColormap(int component) 486 { 487 return getColorMap(component); 488 } 489 490 /** 491 * Set the colormap for the specified component (actually copy the content of source colormap). 492 * 493 * @param component 494 * component we want to set the colormap 495 * @param colorMap 496 * source colorMap 497 * @param setAlpha 498 * also set the alpha information 499 */ 500 public void setColorMap(int component, IcyColorMap colorMap, boolean setAlpha) 501 { 502 toRGBmaps[component].copyFrom(colorMap, setAlpha); 503 } 504 505 /** 506 * @deprecated Use {@link #setColorMap(int, IcyColorMap, boolean)} instead. 507 */ 508 @Deprecated 509 public void setColormap(int component, IcyColorMap map) 510 { 511 setColorMap(component, map, true); 512 } 513 514 /** 515 * @deprecated Use <code>setColormap(channel, map)</code> instead. 516 */ 517 @Deprecated 518 public void copyColormap(int component, IcyColorMap map, boolean copyName, boolean copyAlpha) 519 { 520 setColorMap(component, map, copyAlpha); 521 522 if (copyName) 523 toRGBmaps[component].setName(map.getName()); 524 } 525 526 /** 527 * @deprecated Use <code>setColormap(channel, map)</code> instead. 528 */ 529 @Deprecated 530 public void copyColormap(int component, IcyColorMap map, boolean copyName) 531 { 532 setColorMap(component, map, true); 533 534 if (copyName) 535 toRGBmaps[component].setName(map.getName()); 536 } 537 538 /** 539 * @deprecated Use <code>setColormap(channel, map)</code> instead. 540 */ 541 @Deprecated 542 public void copyColormap(int component, IcyColorMap map) 543 { 544 setColorMap(component, map, true); 545 } 546 547 /** 548 * Return the RGB inverse colormap for specified RGB component. 549 */ 550 public FromRGBColorMap getFromRGBMap(int component) 551 { 552 return fromRGBmaps[component]; 553 } 554 555 /** 556 * Set the RGB colormaps from a compatible colorModel. 557 */ 558 public void setColorMaps(ColorModel cm) 559 { 560 if (cm instanceof IcyColorModel) 561 setColorMaps((IcyColorSpace) cm.getColorSpace(), true); 562 else 563 { 564 // get datatype and numComponent of source colorModel 565 final Object srcElem = cm.getDataElements(0x0, null); 566 final DataType srcDataType = ArrayUtil.getDataType(srcElem); 567 final int srcNumComponents = ArrayUtil.getLength(srcElem); 568 final DataType dataType = DataType.getDataTypeFromDataBufferType(cm.getTransferType()); 569 final int numComponents = getNumComponents(); 570 571 // can't recover colormap if we have different dataType or numComponents 572 if ((srcNumComponents != numComponents) || (srcDataType != dataType)) 573 return; 574 575 final boolean hasAlpha = cm.hasAlpha(); 576 577 for (int comp = 0; comp < numComponents; comp++) 578 { 579 final IcyColorMap map = toRGBmaps[comp]; 580 581 map.beginUpdate(); 582 try 583 { 584 // set type 585 if (hasAlpha && (comp == (numComponents - 1))) 586 map.setType(IcyColorMapType.ALPHA); 587 else 588 map.setType(IcyColorMapType.RGB); 589 590 for (int index = 0; index < IcyColorMap.SIZE; index++) 591 { 592 switch (dataType.getJavaType()) 593 { 594 case BYTE: 595 { 596 final byte bvalues[] = new byte[numComponents]; 597 598 // build an pixel element 599 for (int i = 0; i < numComponents; i++) 600 { 601 if (i == comp) 602 bvalues[i] = (byte) (index * (1 << 8) / IcyColorMap.SIZE); 603 else if (hasAlpha && (i == (numComponents - 1))) 604 bvalues[i] = (byte) (IcyColorMap.MAX_INDEX * (1 << 8) / IcyColorMap.SIZE); 605 else 606 bvalues[i] = 0; 607 } 608 609 // set colormap data 610 map.setAlpha(index, (short) cm.getAlpha(bvalues)); 611 map.setRed(index, (short) cm.getRed(bvalues)); 612 map.setGreen(index, (short) cm.getGreen(bvalues)); 613 map.setBlue(index, (short) cm.getBlue(bvalues)); 614 break; 615 } 616 617 case SHORT: 618 { 619 final short svalues[] = new short[numComponents]; 620 621 // build an pixel element 622 for (int i = 0; i < numComponents; i++) 623 { 624 if (i == comp) 625 svalues[i] = (short) (index * (1 << 16) / IcyColorMap.SIZE); 626 else if (hasAlpha && (i == (numComponents - 1))) 627 svalues[i] = (short) (IcyColorMap.MAX_INDEX * (1 << 16) / IcyColorMap.SIZE); 628 else 629 svalues[i] = 0; 630 } 631 632 // set colormap data 633 map.setAlpha(index, (short) cm.getAlpha(svalues)); 634 map.setRed(index, (short) cm.getRed(svalues)); 635 map.setGreen(index, (short) cm.getGreen(svalues)); 636 map.setBlue(index, (short) cm.getBlue(svalues)); 637 break; 638 } 639 640 case INT: 641 { 642 final int ivalues[] = new int[numComponents]; 643 644 // build an pixel element 645 for (int i = 0; i < numComponents; i++) 646 { 647 if (i == comp) 648 ivalues[i] = (index * (1 << 32) / IcyColorMap.SIZE); 649 else if (hasAlpha && (i == (numComponents - 1))) 650 ivalues[i] = (IcyColorMap.MAX_INDEX * (1 << 32) / IcyColorMap.SIZE); 651 else 652 ivalues[i] = 0; 653 } 654 655 // set colormap data 656 map.setAlpha(index, (short) cm.getAlpha(ivalues)); 657 map.setRed(index, (short) cm.getRed(ivalues)); 658 map.setGreen(index, (short) cm.getGreen(ivalues)); 659 map.setBlue(index, (short) cm.getBlue(ivalues)); 660 break; 661 } 662 663 case LONG: 664 { 665 final long lvalues[] = new long[numComponents]; 666 667 // build an pixel element 668 for (int i = 0; i < numComponents; i++) 669 { 670 if (i == comp) 671 lvalues[i] = (index * (1 << 32) / IcyColorMap.SIZE); 672 else if (hasAlpha && (i == (numComponents - 1))) 673 lvalues[i] = (IcyColorMap.MAX_INDEX * (1 << 32) / IcyColorMap.SIZE); 674 else 675 lvalues[i] = 0; 676 } 677 678 // set colormap data 679 map.setAlpha(index, (short) cm.getAlpha(lvalues)); 680 map.setRed(index, (short) cm.getRed(lvalues)); 681 map.setGreen(index, (short) cm.getGreen(lvalues)); 682 map.setBlue(index, (short) cm.getBlue(lvalues)); 683 break; 684 } 685 686 case FLOAT: 687 { 688 final float fvalues[] = new float[numComponents]; 689 690 // build an pixel element 691 for (int i = 0; i < numComponents; i++) 692 { 693 if (i == comp) 694 fvalues[i] = (float) index / (float) IcyColorMap.SIZE; 695 else if (hasAlpha && (i == (numComponents - 1))) 696 fvalues[i] = (IcyColorMap.MAX_INDEX / (float) IcyColorMap.SIZE); 697 else 698 fvalues[i] = 0; 699 } 700 701 // set colormap data 702 map.setAlpha(index, (short) cm.getAlpha(fvalues)); 703 map.setRed(index, (short) cm.getRed(fvalues)); 704 map.setGreen(index, (short) cm.getGreen(fvalues)); 705 map.setBlue(index, (short) cm.getBlue(fvalues)); 706 break; 707 } 708 709 case DOUBLE: 710 { 711 final double dvalues[] = new double[numComponents]; 712 713 // build an pixel element 714 for (int i = 0; i < numComponents; i++) 715 { 716 if (i == comp) 717 dvalues[i] = (double) index / (double) IcyColorMap.SIZE; 718 else if (hasAlpha && (i == (numComponents - 1))) 719 dvalues[i] = (IcyColorMap.MAX_INDEX / (double) IcyColorMap.SIZE); 720 else 721 dvalues[i] = 0; 722 } 723 724 // set colormap data 725 map.setAlpha(index, (short) cm.getAlpha(dvalues)); 726 map.setRed(index, (short) cm.getRed(dvalues)); 727 map.setGreen(index, (short) cm.getGreen(dvalues)); 728 map.setBlue(index, (short) cm.getBlue(dvalues)); 729 break; 730 } 731 732 default: 733 break; 734 } 735 } 736 } 737 finally 738 { 739 map.endUpdate(); 740 } 741 } 742 } 743 } 744 745 /** 746 * @deprecated Use {@link #setColorMaps(ColorModel)} instead (different case). 747 */ 748 @Deprecated 749 public void setColormaps(ColorModel cm) 750 { 751 setColorMaps(cm); 752 } 753 754 /** 755 * @deprecated Use {@link #setColorMaps(ColorModel)} instead. 756 */ 757 @Deprecated 758 public void copyColormaps(ColorModel cm) 759 { 760 setColorMaps(cm); 761 } 762 763 /** 764 * Set colormaps from specified colorSpace (do a copy). 765 * 766 * @param source 767 * source colorspace to copy the colormaps from 768 * @param setAlpha 769 * also set the alpha information 770 */ 771 public void setColorMaps(IcyColorSpace source, boolean setAlpha) 772 { 773 final int numComponents = Math.min(source.getNumComponents(), getNumComponents()); 774 775 beginUpdate(); 776 try 777 { 778 // copy colormap 779 for (int comp = 0; comp < numComponents; comp++) 780 setColorMap(comp, source.getColorMap(comp), setAlpha); 781 } 782 finally 783 { 784 endUpdate(); 785 } 786 } 787 788 /** 789 * @deprecated Use {@link #setColorMaps(IcyColorSpace, boolean)} instead. 790 */ 791 @Deprecated 792 public void setColormaps(IcyColorSpace source) 793 { 794 setColorMaps(source, true); 795 } 796 797 /** 798 * @deprecated Use {@link #setColorMaps(IcyColorSpace, boolean)} instead. 799 */ 800 @Deprecated 801 public void copyColormaps(IcyColorSpace source) 802 { 803 setColorMaps(source, true); 804 } 805 806 /** 807 * get index of the specified colormap 808 * 809 * @param colormap 810 * @return index 811 */ 812 public int indexOfColorMap(IcyColorMap colormap) 813 { 814 for (int i = 0; i < toRGBmaps.length; i++) 815 if (toRGBmaps[i].equals(colormap)) 816 return i; 817 818 return -1; 819 } 820 821 @Override 822 public String getName(int idx) 823 { 824 // TODO: should get name from metadata 825 return "Component #" + idx; 826 } 827 828 /** 829 * Add a listener 830 * 831 * @param listener 832 */ 833 public void addListener(IcyColorSpaceListener listener) 834 { 835 listeners.add(listener); 836 } 837 838 /** 839 * Remove a listener 840 * 841 * @param listener 842 */ 843 public void removeListener(IcyColorSpaceListener listener) 844 { 845 listeners.remove(listener); 846 } 847 848 /** 849 * fire event 850 */ 851 public void fireEvent(IcyColorSpaceEvent e) 852 { 853 for (IcyColorSpaceListener listener : new ArrayList<IcyColorSpaceListener>(listeners)) 854 listener.colorSpaceChanged(e); 855 } 856 857 /** 858 * called when colorspace has changed (afaik when a colormap has changed) 859 */ 860 private void changed(int component) 861 { 862 final IcyColorMap colorMap = getColorMap(component); 863 864 // we can have only 1 alpha colormap 865 if (colorMap != null) 866 { 867 // alpha type colormap ? 868 if (colorMap.getType() == IcyColorMapType.ALPHA) 869 { 870 // check that others colormap are non alpha 871 for (IcyColorMap map : toRGBmaps) 872 { 873 if (map != colorMap) 874 { 875 // we have another ALPHA colormap ? 876 if (map.getType() == IcyColorMapType.ALPHA) 877 // set it to RGB 878 map.setType(IcyColorMapType.RGB); 879 } 880 } 881 } 882 } 883 884 // handle changed via updater object 885 updater.changed(new IcyColorSpaceEvent(this, component)); 886 } 887 888 /** 889 * process on colorspace change 890 */ 891 @Override 892 public void onChanged(CollapsibleEvent compare) 893 { 894 final IcyColorSpaceEvent event = (IcyColorSpaceEvent) compare; 895 896 // recalculate fromRGB colormaps 897 generateFromRGBColorMaps(); 898 899 // notify listener we have changed 900 fireEvent(event); 901 } 902 903 @Override 904 public void colorMapChanged(IcyColorMapEvent e) 905 { 906 final int index = indexOfColorMap(e.getColormap()); 907 908 // colormap found ? raise a "changed" event 909 if (index != -1) 910 changed(index); 911 } 912 913 /** 914 * @see icy.common.UpdateEventHandler#beginUpdate() 915 */ 916 public void beginUpdate() 917 { 918 updater.beginUpdate(); 919 } 920 921 /** 922 * @see icy.common.UpdateEventHandler#endUpdate() 923 */ 924 public void endUpdate() 925 { 926 updater.endUpdate(); 927 } 928 929 /** 930 * @see icy.common.UpdateEventHandler#isUpdating() 931 */ 932 public boolean isUpdating() 933 { 934 return updater.isUpdating(); 935 } 936 937}