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.sequence; 020 021import java.awt.Dimension; 022import java.awt.Rectangle; 023import java.awt.image.BufferedImage; 024import java.io.Closeable; 025import java.io.IOException; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.List; 032import java.util.Map.Entry; 033import java.util.Set; 034import java.util.TreeMap; 035 036import javax.swing.undo.UndoManager; 037 038import org.w3c.dom.Node; 039 040import icy.common.CollapsibleEvent; 041import icy.common.UpdateEventHandler; 042import icy.common.exception.TooLargeArrayException; 043import icy.common.listener.ChangeListener; 044import icy.file.FileUtil; 045import icy.gui.viewer.Viewer; 046import icy.image.IcyBufferedImage; 047import icy.image.IcyBufferedImageEvent; 048import icy.image.IcyBufferedImageListener; 049import icy.image.IcyBufferedImageUtil; 050import icy.image.ImageProvider; 051import icy.image.colormap.IcyColorMap; 052import icy.image.colormodel.IcyColorModel; 053import icy.image.colormodel.IcyColorModelEvent; 054import icy.image.colormodel.IcyColorModelListener; 055import icy.image.lut.LUT; 056import icy.main.Icy; 057import icy.math.MathUtil; 058import icy.math.Scaler; 059import icy.math.UnitUtil; 060import icy.math.UnitUtil.UnitPrefix; 061import icy.painter.Overlay; 062import icy.painter.OverlayEvent; 063import icy.painter.OverlayEvent.OverlayEventType; 064import icy.painter.OverlayListener; 065import icy.painter.OverlayWrapper; 066import icy.painter.Painter; 067import icy.preferences.GeneralPreferences; 068import icy.roi.ROI; 069import icy.roi.ROI2D; 070import icy.roi.ROI3D; 071import icy.roi.ROIEvent; 072import icy.roi.ROIListener; 073import icy.sequence.SequenceEvent.SequenceEventSourceType; 074import icy.sequence.SequenceEvent.SequenceEventType; 075import icy.sequence.edit.DataSequenceEdit; 076import icy.sequence.edit.DefaultSequenceEdit; 077import icy.sequence.edit.MetadataSequenceEdit; 078import icy.sequence.edit.ROIAddSequenceEdit; 079import icy.sequence.edit.ROIAddsSequenceEdit; 080import icy.sequence.edit.ROIRemoveSequenceEdit; 081import icy.sequence.edit.ROIRemovesSequenceEdit; 082import icy.system.IcyExceptionHandler; 083import icy.system.thread.ThreadUtil; 084import icy.type.DataType; 085import icy.type.TypeUtil; 086import icy.type.collection.CollectionUtil; 087import icy.type.collection.array.Array1DUtil; 088import icy.type.dimension.Dimension5D; 089import icy.type.rectangle.Rectangle5D; 090import icy.undo.IcyUndoManager; 091import icy.undo.IcyUndoableEdit; 092import icy.util.OMEUtil; 093import icy.util.StringUtil; 094import loci.formats.ome.OMEXMLMetadataImpl; 095import ome.xml.meta.OMEXMLMetadata; 096 097/** 098 * Image sequence object.<br> 099 * A <code>Sequence</code> is basically a 5 dimension (XYCZT) image where :<br> 100 * XY dimension = planar image<br> 101 * C dimension = channel<br> 102 * Z dimension = depth<br> 103 * T dimension = time<br> 104 * <br> 105 * The XYC dimensions are bounded into the {@link IcyBufferedImage} object so <code>Sequence</code> define a list of 106 * {@link IcyBufferedImage} where each image is associated to a Z and T 107 * information. 108 * 109 * @author Fabrice de Chaumont & Stephane 110 */ 111 112public class Sequence implements SequenceModel, IcyColorModelListener, IcyBufferedImageListener, ChangeListener, 113 ROIListener, OverlayListener 114{ 115 public static final String DEFAULT_NAME = "no name"; 116 117 /** 118 * @deprecated 119 */ 120 @Deprecated 121 public static final int TYPE_BYTE = TypeUtil.TYPE_BYTE; 122 /** 123 * @deprecated 124 */ 125 @Deprecated 126 public static final int TYPE_DOUBLE = TypeUtil.TYPE_DOUBLE; 127 /** 128 * @deprecated 129 */ 130 @Deprecated 131 public static final int TYPE_FLOAT = TypeUtil.TYPE_FLOAT; 132 /** 133 * @deprecated 134 */ 135 @Deprecated 136 public static final int TYPE_INT = TypeUtil.TYPE_INT; 137 /** 138 * @deprecated 139 */ 140 @Deprecated 141 public static final int TYPE_SHORT = TypeUtil.TYPE_SHORT; 142 /** 143 * @deprecated 144 */ 145 @Deprecated 146 public static final int TYPE_UNDEFINED = TypeUtil.TYPE_UNDEFINED; 147 148 public static final String ID_NAME = "name"; 149 150 public static final String ID_POSITION_X = "positionX"; 151 public static final String ID_POSITION_Y = "positionY"; 152 public static final String ID_POSITION_Z = "positionZ"; 153 public static final String ID_POSITION_T = "positionT"; 154 public static final String ID_POSITION_T_OFFSET = "positionTOffset"; 155 156 public static final String ID_PIXEL_SIZE_X = "pixelSizeX"; 157 public static final String ID_PIXEL_SIZE_Y = "pixelSizeY"; 158 public static final String ID_PIXEL_SIZE_Z = "pixelSizeZ"; 159 public static final String ID_TIME_INTERVAL = "timeInterval"; 160 161 public static final String ID_CHANNEL_NAME = "channelName"; 162 163 public static final String ID_VIRTUAL = "virtual"; 164 165 /** 166 * id generator 167 */ 168 protected static int id_gen = 1; 169 170 /** 171 * volumetric images (4D [XYCZ]) 172 */ 173 protected final TreeMap<Integer, VolumetricImage> volumetricImages; 174 /** 175 * painters 176 */ 177 protected final Set<Overlay> overlays; 178 /** 179 * ROIs 180 */ 181 protected final Set<ROI> rois; 182 183 /** 184 * id of sequence (uniq during an Icy session) 185 */ 186 protected final int id; 187 /** 188 * colorModel of sequence 189 */ 190 protected IcyColorModel colorModel; 191 /** 192 * default lut for this sequence 193 */ 194 protected LUT defaultLut; 195 /** 196 * user lut for this sequence (saved in metadata) 197 */ 198 protected LUT userLut; 199 /** 200 * Origin filename (from/to which the sequence has been loaded/saved)<br> 201 * null --> no file attachment<br> 202 * directory or metadata file --> multiples files attachment<br> 203 * image file --> single file attachment 204 */ 205 protected String filename; 206 /** 207 * Returns the {@link ImageProvider} used to load the sequence data.<br> 208 * It can return <code>null</code> if the Sequence was not loaded from a specific resource or if it was saved in between. 209 */ 210 protected ImageProvider imageProvider; 211 212 /** 213 * Resolution level from the original image<br> 214 * 0 --> full image resolution<br> 215 * 1 --> resolution / 2<br> 216 * 2 --> resolution / 4<br> 217 * 3 --> ...<br> 218 * Default value is 0 219 */ 220 protected int originResolution; 221 /** 222 * Region (X,Y) from original image if this image is a crop of the original image.<br> 223 * Default value is <code>null</code> (no crop) 224 */ 225 protected Rectangle originXYRegion; 226 /** 227 * Z range from original image if this image is a crop in Z of the original image.<br> 228 * Default value is -1, -1 if we have the whole Z range. 229 */ 230 protected int originZMin; 231 protected int originZMax; 232 /** 233 * T range from original image if this image is a crop in T of the original image.<br> 234 * Default value is -1, -1 if we have the whole T range. 235 */ 236 protected int originTMin; 237 protected int originTMax; 238 /** 239 * Channel position from original image if this image is a single channel extraction of the original image.<br> 240 * Default value is -1 which mean that all channels were preserved. 241 */ 242 protected int originChannel; 243 244 /** 245 * Metadata 246 */ 247 protected OMEXMLMetadata metaData; 248 // /** 249 // * X, Y, Z resolution (in mm) 250 // */ 251 // private double pixelSizeX; 252 // private double pixelSizeY; 253 // private double pixelSizeZ; 254 // /** 255 // * T resolution (in ms) 256 // */ 257 // private double timeInterval; 258 // /** 259 // * channels name 260 // */ 261 // private String channelsName[]; 262 263 // /** 264 // * automatic update of component absolute bounds 265 // */ 266 // private boolean componentAbsBoundsAutoUpdate; 267 /** 268 * automatic update of channel bounds 269 */ 270 protected boolean autoUpdateChannelBounds; 271 /** 272 * persistent object to load/save data (XML format) 273 */ 274 protected final SequencePersistent persistent; 275 /** 276 * undo manager 277 */ 278 protected final IcyUndoManager undoManager; 279 280 /** 281 * internal updater 282 */ 283 protected final UpdateEventHandler updater; 284 /** 285 * listeners 286 */ 287 protected final List<SequenceListener> listeners; 288 protected final List<SequenceModelListener> modelListeners; 289 290 /** 291 * internals 292 */ 293 protected boolean channelBoundsInvalid; 294 295 /** 296 * Creates a new empty sequence with specified meta data object and name. 297 */ 298 public Sequence(OMEXMLMetadata meta, String name) 299 { 300 super(); 301 302 // set id 303 synchronized (Sequence.class) 304 { 305 id = id_gen; 306 id_gen++; 307 } 308 309 // set metadata object 310 if (meta == null) 311 metaData = MetaDataUtil.createMetadata(name); 312 else 313 metaData = meta; 314 315 // set name 316 if (!StringUtil.isEmpty(name)) 317 MetaDataUtil.setName(metaData, 0, name); 318 else 319 { 320 // default name 321 if (StringUtil.isEmpty(MetaDataUtil.getName(metaData, 0))) 322 MetaDataUtil.setName(metaData, 0, DEFAULT_NAME + StringUtil.toString(id, 3)); 323 } 324 filename = null; 325 imageProvider = null; 326 327 originResolution = 0; 328 originXYRegion = null; 329 originZMin = -1; 330 originZMax = -1; 331 originTMin = -1; 332 originTMax = -1; 333 originChannel = -1; 334 335 // default pixel size and time interval 336 if (Double.isNaN(MetaDataUtil.getPixelSizeX(metaData, 0, Double.NaN))) 337 MetaDataUtil.setPixelSizeX(metaData, 0, 1d); 338 if (Double.isNaN(MetaDataUtil.getPixelSizeY(metaData, 0, Double.NaN))) 339 MetaDataUtil.setPixelSizeY(metaData, 0, 1d); 340 if (Double.isNaN(MetaDataUtil.getPixelSizeZ(metaData, 0, Double.NaN))) 341 MetaDataUtil.setPixelSizeZ(metaData, 0, 1d); 342 if (Double.isNaN(MetaDataUtil.getTimeInterval(metaData, 0, Double.NaN))) 343 MetaDataUtil.setTimeInterval(metaData, 0, 1d); 344 345 volumetricImages = new TreeMap<Integer, VolumetricImage>(); 346 overlays = new HashSet<Overlay>(); 347 rois = new HashSet<ROI>(); 348 persistent = new SequencePersistent(this); 349 undoManager = new IcyUndoManager(this, GeneralPreferences.getHistorySize()); 350 351 updater = new UpdateEventHandler(this, false); 352 listeners = new ArrayList<SequenceListener>(); 353 modelListeners = new ArrayList<SequenceModelListener>(); 354 355 // no colorModel yet 356 colorModel = null; 357 defaultLut = null; 358 userLut = null; 359 channelBoundsInvalid = false; 360 // automatic update of channel bounds 361 autoUpdateChannelBounds = true; 362 } 363 364 /** 365 * @deprecated Use {@link #Sequence(OMEXMLMetadata, String)} instead. 366 */ 367 @Deprecated 368 public Sequence(OMEXMLMetadataImpl meta, String name) 369 { 370 this((OMEXMLMetadata) meta, name); 371 } 372 373 /** 374 * Creates a sequence with specified name and containing the specified image 375 */ 376 public Sequence(String name, IcyBufferedImage image) 377 { 378 this(name, (BufferedImage) image); 379 } 380 381 /** 382 * Creates a sequence with specified name and containing the specified image 383 */ 384 public Sequence(String name, BufferedImage image) 385 { 386 this((OMEXMLMetadata) null, name); 387 388 addImage(image); 389 } 390 391 /** 392 * @deprecated Use {@link #Sequence(OMEXMLMetadata)} instead. 393 */ 394 @Deprecated 395 public Sequence(OMEXMLMetadataImpl meta) 396 { 397 this((OMEXMLMetadata) meta); 398 } 399 400 /** 401 * Creates a new empty sequence with specified metadata. 402 */ 403 public Sequence(OMEXMLMetadata meta) 404 { 405 this(meta, null); 406 } 407 408 /** 409 * Creates a sequence containing the specified image. 410 */ 411 public Sequence(IcyBufferedImage image) 412 { 413 this((BufferedImage) image); 414 } 415 416 /** 417 * Creates a sequence containing the specified image. 418 */ 419 public Sequence(BufferedImage image) 420 { 421 this((OMEXMLMetadata) null, null); 422 423 addImage(image); 424 } 425 426 /** 427 * Creates an empty sequence with specified name. 428 */ 429 public Sequence(String name) 430 { 431 this((OMEXMLMetadata) null, name); 432 } 433 434 /** 435 * Creates an empty sequence. 436 */ 437 public Sequence() 438 { 439 this((OMEXMLMetadata) null, null); 440 } 441 442 @Override 443 protected void finalize() throws Throwable 444 { 445 try 446 { 447 // close image provider if needed 448 if ((imageProvider != null) && (imageProvider instanceof Closeable)) 449 ((Closeable) imageProvider).close(); 450 } 451 catch (IOException e) 452 { 453 // ignore 454 } 455 456 super.finalize(); 457 } 458 459 /** 460 * This method close all attached viewers 461 */ 462 public void close() 463 { 464 Icy.getMainInterface().closeSequence(this); 465 } 466 467 /** 468 * Called when sequence has been closed (all viewers displaying it closed).<br> 469 * <i>Used internally, you should not call it this method directly !</i> 470 */ 471 public void closed() 472 { 473 // do this in background as it can take sometime 474 while (!ThreadUtil.bgRun(new Runnable() 475 { 476 @Override 477 public void run() 478 { 479 // Sequence persistence enabled --> save XML 480 if (GeneralPreferences.getSequencePersistence()) 481 saveXMLData(); 482 } 483 })) 484 { 485 // wait until the process execute 486 ThreadUtil.sleep(10L); 487 } 488 489 // notify close 490 fireClosedEvent(); 491 } 492 493 /** 494 * Copy data and metadata from the specified Sequence 495 * 496 * @param source 497 * the source sequence to copy data from 498 * @param copyName 499 * if set to <code>true</code> it will also copy the name from the source sequence 500 */ 501 public void copyFrom(Sequence source, boolean copyName) 502 { 503 copyDataFrom(source); 504 copyMetaDataFrom(source, copyName); 505 } 506 507 /** 508 * Copy data from the specified Sequence 509 */ 510 public void copyDataFrom(Sequence source) 511 { 512 final int sizeT = source.getSizeT(); 513 final int sizeZ = source.getSizeZ(); 514 515 beginUpdate(); 516 try 517 { 518 removeAllImages(); 519 for (int t = 0; t < sizeT; t++) 520 { 521 for (int z = 0; z < sizeZ; z++) 522 { 523 final IcyBufferedImage img = source.getImage(t, z); 524 525 if (img != null) 526 setImage(t, z, IcyBufferedImageUtil.getCopy(img)); 527 else 528 source.setImage(t, z, null); 529 } 530 } 531 } 532 finally 533 { 534 endUpdate(); 535 } 536 } 537 538 /** 539 * Copy metadata from the specified Sequence 540 * 541 * @param source 542 * the source sequence to copy metadata from 543 * @param copyName 544 * if set to <code>true</code> it will also copy the name from the source sequence 545 */ 546 public void copyMetaDataFrom(Sequence source, boolean copyName) 547 { 548 // copy all metadata from source 549 metaData = OMEUtil.createOMEXMLMetadata(source.getOMEXMLMetadata()); 550 551 // restore name if needed 552 if (copyName) 553 setName(source.getName()); 554 555 // notify metadata changed 556 metaChanged(null); 557 } 558 559 /** 560 * Create a complete restore point for this sequence. 561 * 562 * @param name 563 * restore point name (visible in the History panel) 564 * @return false if for some reason the operation failed (out of memory for instance) 565 * @see #undo() 566 */ 567 public boolean createUndoPoint(String name) 568 { 569 try 570 { 571 undoManager.addEdit(new DefaultSequenceEdit(SequenceUtil.getCopy(this, false, false, false), this)); 572 return true; 573 } 574 catch (Throwable t) 575 { 576 return false; 577 } 578 } 579 580 /** 581 * Create a restore point for sequence data. 582 * 583 * @param name 584 * restore point name (visible in the History panel) 585 * @return false if for some reason the operation failed (out of memory for instance) 586 * @see #undo() 587 */ 588 public boolean createUndoDataPoint(String name) 589 { 590 try 591 { 592 undoManager.addEdit(new DataSequenceEdit(SequenceUtil.getCopy(this, false, false, false), this, name)); 593 return true; 594 } 595 catch (Throwable t) 596 { 597 return false; 598 } 599 } 600 601 /** 602 * Create a restore point for sequence metadata. 603 * 604 * @param name 605 * restore point name (visible in the History panel) 606 * @return false if for some reason the operation failed (out of memory for instance) 607 * @see #undo() 608 */ 609 public boolean createUndoMetadataPoint(String name) 610 { 611 try 612 { 613 undoManager.addEdit(new MetadataSequenceEdit(OMEUtil.createOMEXMLMetadata(metaData), this, name)); 614 return true; 615 } 616 catch (Throwable t) 617 { 618 return false; 619 } 620 } 621 622 /** 623 * Add an Undoable edit to the Sequence UndoManager 624 * 625 * @param edit 626 * the undoable edit to add 627 * @return <code>false</code> if the operation failed 628 */ 629 public boolean addUndoableEdit(IcyUndoableEdit edit) 630 { 631 if (edit != null) 632 return undoManager.addEdit(edit); 633 634 return false; 635 } 636 637 /** 638 * Undo to the last <i>Undoable</i> change set in the Sequence {@link UndoManager} 639 * 640 * @return <code>true</code> if the operation succeed 641 * @see #createUndoPoint(String) 642 * @see UndoManager#undo() 643 */ 644 public boolean undo() 645 { 646 if (undoManager.canUndo()) 647 { 648 undoManager.undo(); 649 return true; 650 } 651 652 return false; 653 } 654 655 /** 656 * Redo the next <i>Undoable</i> change set in the Sequence {@link UndoManager} 657 * 658 * @return <code>true</code> if the operation succeed 659 * @see #createUndoPoint(String) 660 * @see UndoManager#redo() 661 */ 662 public boolean redo() 663 { 664 if (undoManager.canRedo()) 665 { 666 undoManager.redo(); 667 return true; 668 } 669 670 return false; 671 } 672 673 /** 674 * Clear all undo operations from the {@link UndoManager}.<br> 675 * You should use this method after you modified the sequence without providing any <i>undo</i> 676 * support. 677 */ 678 public void clearUndoManager() 679 { 680 getUndoManager().discardAllEdits(); 681 } 682 683 protected void setColorModel(IcyColorModel cm) 684 { 685 // remove listener 686 if (colorModel != null) 687 colorModel.removeListener(this); 688 689 colorModel = cm; 690 691 // add listener 692 if (cm != null) 693 cm.addListener(this); 694 695 // sequence type changed 696 typeChanged(); 697 // sequence component bounds changed 698 componentBoundsChanged(cm, -1); 699 // sequence colormap changed 700 colormapChanged(cm, -1); 701 } 702 703 /** 704 * @deprecated Use {@link SequenceUtil#convertToType(Sequence, DataType, boolean)} instead. 705 */ 706 @Deprecated 707 public Sequence convertToType(DataType dataType, boolean rescale) 708 { 709 return SequenceUtil.convertToType(this, dataType, rescale); 710 } 711 712 /** 713 * @deprecated Use {@link SequenceUtil#convertType(Sequence, DataType, Scaler[])} instead. 714 */ 715 @Deprecated 716 public Sequence convertToType(DataType dataType, Scaler scaler) 717 { 718 return SequenceUtil.convertToType(this, dataType, scaler); 719 } 720 721 /** 722 * @deprecated Use {@link SequenceUtil#convertToType(Sequence, DataType, boolean)} instead 723 */ 724 @Deprecated 725 public Sequence convertToType(int dataType, boolean signed, boolean rescale) 726 { 727 return convertToType(DataType.getDataType(dataType, signed), rescale); 728 } 729 730 /** 731 * @deprecated Use {@link SequenceUtil#extractChannel(Sequence, int)} instead. 732 */ 733 @Deprecated 734 public Sequence extractChannel(int channelNumber) 735 { 736 return SequenceUtil.extractChannel(this, channelNumber); 737 } 738 739 /** 740 * @deprecated Use {@link SequenceUtil#extractChannels(Sequence, List)} instead. 741 */ 742 @Deprecated 743 public Sequence extractChannels(List<Integer> channelNumbers) 744 { 745 return SequenceUtil.extractChannels(this, channelNumbers); 746 } 747 748 /** 749 * @deprecated Use {@link SequenceUtil#extractChannel(Sequence, int)} instead 750 */ 751 @Deprecated 752 public Sequence extractBand(int bandNumber) 753 { 754 return extractChannel(bandNumber); 755 } 756 757 /** 758 * @deprecated Use {@link SequenceUtil#extractChannels(Sequence, List)} instead 759 */ 760 @Deprecated 761 public Sequence extractBands(List<Integer> bandNumbers) 762 { 763 return extractChannels(bandNumbers); 764 } 765 766 /** 767 * Returns all VolumetricImage as TreeMap (contains t position) 768 */ 769 public TreeMap<Integer, VolumetricImage> getVolumetricImages() 770 { 771 synchronized (volumetricImages) 772 { 773 return new TreeMap<Integer, VolumetricImage>(volumetricImages); 774 } 775 } 776 777 /** 778 * Returns all VolumetricImage 779 */ 780 public ArrayList<VolumetricImage> getAllVolumetricImage() 781 { 782 synchronized (volumetricImages) 783 { 784 return new ArrayList<VolumetricImage>(volumetricImages.values()); 785 } 786 } 787 788 /** 789 * Returns first viewer attached to this sequence 790 */ 791 public Viewer getFirstViewer() 792 { 793 return Icy.getMainInterface().getFirstViewer(this); 794 } 795 796 /** 797 * Returns viewers attached to this sequence 798 */ 799 public ArrayList<Viewer> getViewers() 800 { 801 return Icy.getMainInterface().getViewers(this); 802 } 803 804 /** 805 * Set the volatile state for this Sequence (see {@link IcyBufferedImage#setVolatile(boolean)}).<br> 806 * 807 * @throws OutOfMemoryError 808 * if there is not enough memory available to store image 809 * data when setting back to <i>non volatile</i> state 810 * @throws UnsupportedOperationException 811 * if cache engine is not initialized (error at initialization). 812 */ 813 public void setVolatile(boolean value) throws OutOfMemoryError, UnsupportedOperationException 814 { 815 final boolean vol = isVolatile(); 816 817 try 818 { 819 // change volatile state for all images 820 for (IcyBufferedImage image : getAllImage()) 821 if (image != null) 822 image.setVolatile(value); 823 824 if (vol != value) 825 metaChanged(ID_VIRTUAL); 826 } 827 catch (OutOfMemoryError e) 828 { 829 // not enough memory to complete the operation --> restore previous state 830 for (IcyBufferedImage image : getAllImage()) 831 if (image != null) 832 image.setVolatile(!value); 833 834 throw e; 835 } 836 } 837 838 /** 839 * Same as {@link #setVolatile(boolean)} 840 * 841 * @throws OutOfMemoryError 842 * if there is not enough memory available to store image 843 * data when setting back to <i>non volatile</i> state 844 * @throws UnsupportedOperationException 845 * if cache engine is not initialized (error at initialization). 846 */ 847 public void setVirtual(boolean value) throws OutOfMemoryError, UnsupportedOperationException 848 { 849 setVolatile(value); 850 } 851 852 /** 853 * Returns true if this sequence contains volatile image (see {@link IcyBufferedImage#isVolatile()}). 854 */ 855 public boolean isVolatile() 856 { 857 final IcyBufferedImage img = getFirstNonNullImage(); 858 if (img != null) 859 return img.isVolatile(); 860 861 return false; 862 } 863 864 /** 865 * Same as {@link #isVolatile()} 866 */ 867 public boolean isVirtual() 868 { 869 return isVolatile(); 870 } 871 872 /** 873 * get sequence id (this id is unique during an ICY session) 874 */ 875 public int getId() 876 { 877 return id; 878 } 879 880 /** 881 * Sequence name 882 */ 883 public void setName(String value) 884 { 885 if (getName() != value) 886 { 887 MetaDataUtil.setName(metaData, 0, value); 888 metaChanged(ID_NAME); 889 } 890 } 891 892 public String getName() 893 { 894 return MetaDataUtil.getName(metaData, 0); 895 } 896 897 /** 898 * Returns the origin filename (from/to which the sequence has been loaded/saved).<br> 899 * This filename information is also used to store the XML persistent data.<br/> 900 * null / empty --> no file attachment<br> 901 * image file --> single file attachment 902 * directory or metadata file --> multiples files attachment<br> 903 * 904 * @return the origin filename 905 */ 906 public String getFilename() 907 { 908 return filename; 909 } 910 911 /** 912 * Set the origin filename (from/to which the sequence has been loaded/saved).<br> 913 * When you set the filename you need to ensure that "sub part" information are correctly reset (setOriginXXX(...) 914 * methods) as this filename will be used to generate the XML persistent data file name.<br/> 915 * null / empty --> no file attachment<br> 916 * image file --> single file attachment 917 * directory or metadata file --> multiples files attachment<br> 918 * 919 * @param filename 920 * the filename to set 921 */ 922 public void setFilename(String filename) 923 { 924 if (this.filename != filename) 925 { 926 this.filename = filename; 927 } 928 } 929 930 /** 931 * Returns the {@link ImageProvider} used to load the sequence data.<br> 932 * It can return <code>null</code> if the Sequence was not loaded from a specific resource or if it was saved in between.<br> 933 * 934 * @return the {@link ImageProvider} used to load the Sequence 935 */ 936 public ImageProvider getImageProvider() 937 { 938 return imageProvider; 939 } 940 941 /** 942 * Set the {@link ImageProvider} used to load the sequence data.<br> 943 * When you set the <i>ImageProvider</i> you need to ensure we can use it (should be opened for {@link SequenceIdImporter}).<br> 944 * Also "sub part" informations has to be correctly set (setOriginXXX(...) methods) as we may use it to retrieve sequence data from the 945 * {@link ImageProvider}. 946 */ 947 public void setImageProvider(ImageProvider value) 948 { 949 try 950 { 951 // close previous 952 if ((imageProvider != null) && (imageProvider instanceof Closeable)) 953 ((Closeable) imageProvider).close(); 954 } 955 catch (IOException e) 956 { 957 // ignore 958 } 959 960 imageProvider = value; 961 } 962 963 /** 964 * Returns the output base filename.<br> 965 * This function is supposed to be used internally only. 966 * 967 * @param folderExt 968 * If the filename of this sequence refer a folder then we extend it with 'folderExt' to build the base name. 969 * @see #getOutputExtension() 970 */ 971 public String getOutputBaseName(String folderExt) 972 { 973 String result = getFilename(); 974 975 if (StringUtil.isEmpty(result)) 976 return ""; 977 978 // remove some problematic character for XML file 979 result = FileUtil.cleanPath(result); 980 981 // filename reference a directory --> use "<directory>/<folderExt>" 982 if (FileUtil.isDirectory(result)) 983 result += "/" + folderExt; 984 // otherwise remove extension 985 else 986 result = FileUtil.setExtension(result, ""); 987 988 return result; 989 } 990 991 /** 992 * Returns the output filename extension (not the file extension, just extension from base name).<br> 993 * The extension is based on some internals informations as serie index and resolution level.<br> 994 * This function is supposed to be used internally only. 995 * 996 * @see #getOutputBaseName(String) 997 */ 998 public String getOutputExtension() 999 { 1000 String result = ""; 1001 1002 // retrieve the serie index 1003 final int serieNum = getSeries(); 1004 1005 // multi serie image --> add a specific extension 1006 if (serieNum != 0) 1007 result += "_S" + serieNum; 1008 1009 // retrieve the resolution 1010 final int resolution = getOriginResolution(); 1011 1012 // sub resolution --> add a specific extension 1013 if (resolution != 0) 1014 result += "_R" + resolution; 1015 1016 // retrieve the XY region offset 1017 final Rectangle xyRegion = getOriginXYRegion(); 1018 1019 // not null --> add a specific extension 1020 if (xyRegion != null) 1021 result += "_XY(" + xyRegion.x + "," + xyRegion.y + "-" + xyRegion.width + "," + xyRegion.height + ")"; 1022 1023 // retrieve the Z range 1024 final int zMin = getOriginZMin(); 1025 final int zMax = getOriginZMax(); 1026 1027 // sub Z range --> add a specific extension 1028 if ((zMin != -1) || (zMax != -1)) 1029 { 1030 if (zMin == zMax) 1031 result += "_Z" + zMin; 1032 else 1033 result += "_Z(" + zMin + "-" + zMax + ")"; 1034 } 1035 1036 // retrieve the T range 1037 final int tMin = getOriginTMin(); 1038 final int tMax = getOriginTMax(); 1039 1040 // sub T range --> add a specific extension 1041 if ((tMin != -1) || (tMax != -1)) 1042 { 1043 if (tMin == tMax) 1044 result += "_T" + tMin; 1045 else 1046 result += "_T(" + tMin + "-" + tMax + ")"; 1047 } 1048 1049 // retrieve the original channel 1050 final int channel = getOriginChannel(); 1051 1052 // single channel extraction --> add a specific extension 1053 if (channel != -1) 1054 result += "_C" + channel; 1055 1056 return result; 1057 } 1058 1059 /** 1060 * Return the desired output filename for this Sequence.<br> 1061 * It uses the origin filename and add a specific extension depending some internals properties. 1062 * 1063 * @param withExtension 1064 * Add the original file extension is set to <code>true</code> 1065 * @see #getFilename() 1066 * @see #getOutputBaseName(String) 1067 * @see #getOutputExtension() 1068 */ 1069 public String getOutputFilename(boolean withExtension) 1070 { 1071 String result = getFilename(); 1072 1073 if (StringUtil.isEmpty(result)) 1074 return ""; 1075 1076 final String ext = FileUtil.getFileExtension(result, true); 1077 1078 result = getOutputBaseName(FileUtil.getFileName(result, false)) + getOutputExtension(); 1079 if (withExtension) 1080 result += ext; 1081 1082 return result; 1083 } 1084 1085 /** 1086 * Returns the resolution level from the origin image (defined by {@link #getFilename()}).<br> 1087 * By default it returns 0 if this sequence corresponds to the full resolution of the original image.<br> 1088 * 1 --> original resolution / 2<br> 1089 * 2 --> original resolution / 4<br> 1090 * 3 --> original resolution / 8<br> 1091 * ... 1092 */ 1093 public int getOriginResolution() 1094 { 1095 return originResolution; 1096 } 1097 1098 /** 1099 * Internal use only, you should not directly use this method. 1100 * 1101 * @see #getOriginResolution() 1102 */ 1103 public void setOriginResolution(int value) 1104 { 1105 originResolution = value; 1106 } 1107 1108 /** 1109 * Returns the region (X,Y) from original image if this image is a crop of the original image (in original image 1110 * resolution).<br> 1111 * Default value is <code>null</code> (full size). 1112 */ 1113 public Rectangle getOriginXYRegion() 1114 { 1115 return originXYRegion; 1116 } 1117 1118 /** 1119 * Internal use only, you should not directly use this method. 1120 * 1121 * @see #getOriginXYRegion() 1122 */ 1123 public void setOriginXYRegion(Rectangle value) 1124 { 1125 // better to use a copy 1126 if (value != null) 1127 originXYRegion = new Rectangle(value); 1128 // clear it 1129 else 1130 originXYRegion = null; 1131 } 1132 1133 /** 1134 * Returns the Z range minimum from original image if this image is a crop in Z of the original image.<br> 1135 * Default value is -1 which mean we have the whole Z range. 1136 */ 1137 public int getOriginZMin() 1138 { 1139 return originZMin; 1140 } 1141 1142 /** 1143 * Internal use only, you should not directly use this method. 1144 * 1145 * @see #getOriginZMin() 1146 */ 1147 public void setOriginZMin(int value) 1148 { 1149 originZMin = value; 1150 } 1151 1152 /** 1153 * Returns the Z range maximum from original image if this image is a crop in Z of the original image.<br> 1154 * Default value is -1 which mean we have the whole Z range. 1155 */ 1156 public int getOriginZMax() 1157 { 1158 return originZMax; 1159 } 1160 1161 /** 1162 * Internal use only, you should not directly use this method. 1163 * 1164 * @see #getOriginZMax() 1165 */ 1166 public void setOriginZMax(int value) 1167 { 1168 originZMax = value; 1169 } 1170 1171 /** 1172 * Returns the T range minimum from original image if this image is a crop in T of the original image.<br> 1173 * Default value is -1 which mean we have the whole T range. 1174 */ 1175 public int getOriginTMin() 1176 { 1177 return originTMin; 1178 } 1179 1180 /** 1181 * Internal use only, you should not directly use this method. 1182 * 1183 * @see #getOriginTMin() 1184 */ 1185 public void setOriginTMin(int value) 1186 { 1187 originTMin = value; 1188 } 1189 1190 /** 1191 * Returns the T range maximum from original image if this image is a crop in T of the original image.<br> 1192 * Default value is -1 which mean we have the whole T range. 1193 */ 1194 public int getOriginTMax() 1195 { 1196 return originTMax; 1197 } 1198 1199 /** 1200 * Internal use only, you should not directly use this method. 1201 * 1202 * @see #getOriginTMax() 1203 */ 1204 public void setOriginTMax(int value) 1205 { 1206 originTMax = value; 1207 } 1208 1209 /** 1210 * Returns the channel position from original image if this image is a single channel extraction of the original 1211 * image.<br> 1212 * Default value is -1 which mean that all channels were preserved. 1213 */ 1214 public int getOriginChannel() 1215 { 1216 return originChannel; 1217 } 1218 1219 /** 1220 * Internal use only, you should not directly use this method. 1221 * 1222 * @see #getOriginChannel() 1223 */ 1224 public void setOriginChannel(int value) 1225 { 1226 originChannel = value; 1227 } 1228 1229 /** 1230 * Reset origin information (used after saved operation normally, internal use only). 1231 */ 1232 public void resetOriginInformation() 1233 { 1234 setSeries(0); 1235 setOriginChannel(-1); 1236 setOriginResolution(0); 1237 setOriginTMin(-1); 1238 setOriginTMax(-1); 1239 setOriginZMin(-1); 1240 setOriginZMax(-1); 1241 setOriginXYRegion(null); 1242 } 1243 1244 /** 1245 * Returns series index if the Sequence comes from a multi serie image.<br> 1246 * By default it returns 0 if the sequence comes from a single serie image or if this is the 1247 * first series image. 1248 */ 1249 public int getSeries() 1250 { 1251 // retrieve the image ID (sequences are always single serie) 1252 final String id = MetaDataUtil.getImageID(getOMEXMLMetadata(), 0); 1253 1254 if (id.startsWith("Image:")) 1255 { 1256 final String[] serieNums = id.substring(6).split(":"); 1257 1258 if (serieNums.length > 0) 1259 return StringUtil.parseInt(serieNums[0], 0); 1260 } 1261 1262 return 0; 1263 } 1264 1265 /** 1266 * Set series index if the Sequence comes from a multi serie image (internal use only). 1267 */ 1268 public void setSeries(int value) 1269 { 1270 // retrieve the image ID (sequences are always single serie) 1271 final String id = MetaDataUtil.getImageID(getOMEXMLMetadata(), 0); 1272 1273 if (id.startsWith("Image:")) 1274 MetaDataUtil.setImageID(getOMEXMLMetadata(), 0, "Image:" + value); 1275 } 1276 1277 /** 1278 * @deprecated Use {@link #getSeries()} instead 1279 */ 1280 @Deprecated 1281 public int getSerieIndex() 1282 { 1283 return getSeries(); 1284 } 1285 1286 /** 1287 * Returns meta data object 1288 */ 1289 public OMEXMLMetadata getOMEXMLMetadata() 1290 { 1291 return metaData; 1292 } 1293 1294 /** 1295 * Set the meta data object 1296 */ 1297 public void setMetaData(OMEXMLMetadata metaData) 1298 { 1299 if (this.metaData != metaData) 1300 { 1301 this.metaData = metaData; 1302 // all meta data changed 1303 metaChanged(null); 1304 } 1305 } 1306 1307 /** 1308 * @deprecated Use {@link #getOMEXMLMetadata()} instead. 1309 */ 1310 @Deprecated 1311 public OMEXMLMetadataImpl getMetadata() 1312 { 1313 return (OMEXMLMetadataImpl) getOMEXMLMetadata(); 1314 } 1315 1316 /** 1317 * @deprecated Use {@link #setMetaData(OMEXMLMetadata)} instead. 1318 */ 1319 @Deprecated 1320 public void setMetaData(OMEXMLMetadataImpl metaData) 1321 { 1322 setMetaData((OMEXMLMetadata) metaData); 1323 } 1324 1325 /** 1326 * Returns the physical position [X,Y,Z] (in µm) of the image represented by this Sequence. 1327 * This information can be used to represent the position of the image in the original sample (microscope 1328 * information) or the position of a sub image from the original image (crop operation).<br> 1329 * Note that OME store this information at Plane level (each Z,T,C), here we just use value from Plane(0,0,0) then we use the pixels size and time interval 1330 * information to compute other positions. 1331 */ 1332 public double[] getPosition() 1333 { 1334 return new double[] {getPositionX(), getPositionY(), getPositionZ()}; 1335 } 1336 1337 /** 1338 * Returns the X physical position / offset (in µm) of the image represented by this Sequence.<br> 1339 * This information can be used to represent the position of the image in the original sample (microscope 1340 * information) or the position of a sub image the original image (crop operation).<br> 1341 * Note that OME store this information at Plane level (each Z,T,C), here we just use value from Plane(0,0,0) then we use the pixels size and time interval 1342 * information to compute other positions. 1343 */ 1344 public double getPositionX() 1345 { 1346 return MetaDataUtil.getPositionX(metaData, 0, 0, 0, 0, 0d); 1347 } 1348 1349 /** 1350 * Returns the Y physical position / offset (in µm) of the image represented by this Sequence.<br> 1351 * This information can be used to represent the position of the image in the original sample (microscope 1352 * information) or the position of a sub image the original image (crop operation).<br> 1353 * Note that OME store this information at Plane level (each Z,T,C), here we just use value from Plane(0,0,0) then we use the pixels size and time interval 1354 * information to compute other positions. 1355 */ 1356 public double getPositionY() 1357 { 1358 return MetaDataUtil.getPositionY(metaData, 0, 0, 0, 0, 0d); 1359 } 1360 1361 /** 1362 * Returns the Z physical position / offset (in µm) of the image represented by this Sequence.<br> 1363 * This information can be used to represent the position of the image in the original sample (microscope 1364 * information) or the position of a sub image the original image (crop operation).<br> 1365 * Note that OME store this information at Plane level (each Z,T,C), here we just use value from Plane(0,0,0) then we use the pixels size and time interval 1366 * information to compute other positions. 1367 */ 1368 public double getPositionZ() 1369 { 1370 return MetaDataUtil.getPositionZ(metaData, 0, 0, 0, 0, 0d); 1371 } 1372 1373 /** 1374 * Same as {@link #getTimeStamp()} 1375 */ 1376 public long getPositionT() 1377 { 1378 return getTimeStamp(); 1379 } 1380 1381 /** 1382 * Returns the timestamp (elapsed milliseconds from the Java epoch of 1970-01-01 T00:00:00Z) of the image represented by this Sequence. 1383 * 1384 * @see #getPositionTOffset(int, int, int) 1385 * @see #getTimeInterval() 1386 */ 1387 public long getTimeStamp() 1388 { 1389 return MetaDataUtil.getTimeStamp(metaData, 0, 0L); 1390 } 1391 1392 /** 1393 * Returns the time position offset (in second for OME compatibility) relative to first image for the image at specified (T,Z,C) position. 1394 * 1395 * @see #getTimeInterval() 1396 * @see #getTimeStamp() 1397 */ 1398 public double getPositionTOffset(int t, int z, int c) 1399 { 1400 return MetaDataUtil.getPositionTOffset(metaData, 0, t, z, c, 0d); 1401 } 1402 1403 /** 1404 * Sets the X physical position / offset (in µm) of the image represented by this Sequence.<br> 1405 * This information can be used to represent the position of the image in the original sample (microscope 1406 * information) or the position of a sub image the original image (crop operation).<br> 1407 * Note that OME store this information at Plane level (each Z,T,C), here we always use value from Plane(0,0,0) 1408 */ 1409 public void setPositionX(double value) 1410 { 1411 if (getPositionX() != value) 1412 { 1413 MetaDataUtil.setPositionX(metaData, 0, 0, 0, 0, value); 1414 metaChanged(ID_POSITION_X); 1415 } 1416 } 1417 1418 /** 1419 * Sets the X physical position / offset (in µm) of the image represented by this Sequence.<br> 1420 * This information can be used to represent the position of the image in the original sample (microscope 1421 * information) or the position of a sub image the original image (crop operation).<br> 1422 * Note that OME store this information at Plane level (each Z,T,C), here we always use value from Plane(0,0,0) 1423 */ 1424 public void setPositionY(double value) 1425 { 1426 if (getPositionY() != value) 1427 { 1428 MetaDataUtil.setPositionY(metaData, 0, 0, 0, 0, value); 1429 metaChanged(ID_POSITION_Y); 1430 } 1431 } 1432 1433 /** 1434 * Sets the X physical position / offset (in µm) of the image represented by this Sequence.<br> 1435 * This information can be used to represent the position of the image in the original sample (microscope 1436 * information) or the position of a sub image the original image (crop operation).<br> 1437 * Note that OME store this information at Plane level (each Z,T,C), here we always use value from Plane(0,0,0) 1438 */ 1439 public void setPositionZ(double value) 1440 { 1441 if (getPositionZ() != value) 1442 { 1443 MetaDataUtil.setPositionZ(metaData, 0, 0, 0, 0, value); 1444 metaChanged(ID_POSITION_Z); 1445 } 1446 } 1447 1448 /** 1449 * Same as {@link #setTimeStamp(long)} 1450 */ 1451 public void setPositionT(long value) 1452 { 1453 setTimeStamp(value); 1454 } 1455 1456 /** 1457 * Sets the timestamp (elapsed milliseconds from the Java epoch of 1970-01-01 T00:00:00Z) for the image represented by this Sequence. 1458 * 1459 * @see #setPositionTOffset(int, int, int, double) 1460 * @see #setTimeInterval(double) 1461 */ 1462 public void setTimeStamp(long value) 1463 { 1464 if (getTimeStamp() != value) 1465 { 1466 MetaDataUtil.setTimeStamp(metaData, 0, value); 1467 metaChanged(ID_POSITION_T); 1468 } 1469 } 1470 1471 /** 1472 * Sets the time position / offset (in second for OME compatibility) relative to first image for the image at specified (T,Z,C) position. 1473 * 1474 * @see #setTimeInterval(double) 1475 * @see #setTimeStamp(long) 1476 */ 1477 public void setPositionTOffset(int t, int z, int c, double value) 1478 { 1479 if (getPositionTOffset(t, z, c) != value) 1480 { 1481 MetaDataUtil.setPositionTOffset(metaData, 0, t, z, c, value); 1482 metaChanged(ID_POSITION_T_OFFSET, t); 1483 } 1484 } 1485 1486 /** 1487 * Returns pixel size for [X,Y,Z] dimension (in µm to be OME compatible) 1488 */ 1489 public double[] getPixelSize() 1490 { 1491 return new double[] {getPixelSizeX(), getPixelSizeY(), getPixelSizeZ()}; 1492 } 1493 1494 /** 1495 * Returns X pixel size (in µm to be OME compatible) 1496 */ 1497 public double getPixelSizeX() 1498 { 1499 return MetaDataUtil.getPixelSizeX(metaData, 0, 1d); 1500 } 1501 1502 /** 1503 * Returns Y pixel size (in µm to be OME compatible) 1504 */ 1505 public double getPixelSizeY() 1506 { 1507 return MetaDataUtil.getPixelSizeY(metaData, 0, 1d); 1508 } 1509 1510 /** 1511 * Returns Z pixel size (in µm to be OME compatible) 1512 */ 1513 public double getPixelSizeZ() 1514 { 1515 return MetaDataUtil.getPixelSizeZ(metaData, 0, 1d); 1516 } 1517 1518 /** 1519 * Returns T time interval (in second for OME compatibility) 1520 * 1521 * @see #getPositionTOffset(int, int, int) 1522 */ 1523 public double getTimeInterval() 1524 { 1525 double result = MetaDataUtil.getTimeInterval(metaData, 0, 0d); 1526 1527 // not yet defined ? 1528 if (result == 0d) 1529 { 1530 result = MetaDataUtil.getTimeIntervalFromTimePositions(metaData, 0); 1531 // we got something --> set it as the time interval 1532 if (result != 0d) 1533 MetaDataUtil.setTimeInterval(metaData, 0, result); 1534 } 1535 1536 return result; 1537 } 1538 1539 /** 1540 * Set X pixel size (in µm to be OME compatible) 1541 */ 1542 public void setPixelSizeX(double value) 1543 { 1544 if (getPixelSizeX() != value) 1545 { 1546 MetaDataUtil.setPixelSizeX(metaData, 0, value); 1547 metaChanged(ID_PIXEL_SIZE_X); 1548 } 1549 } 1550 1551 /** 1552 * Set Y pixel size (in µm to be OME compatible) 1553 */ 1554 public void setPixelSizeY(double value) 1555 { 1556 if (getPixelSizeY() != value) 1557 { 1558 MetaDataUtil.setPixelSizeY(metaData, 0, value); 1559 metaChanged(ID_PIXEL_SIZE_Y); 1560 } 1561 } 1562 1563 /** 1564 * Set Z pixel size (in µm to be OME compatible) 1565 */ 1566 public void setPixelSizeZ(double value) 1567 { 1568 if (getPixelSizeZ() != value) 1569 { 1570 MetaDataUtil.setPixelSizeZ(metaData, 0, value); 1571 metaChanged(ID_PIXEL_SIZE_Z); 1572 } 1573 } 1574 1575 /** 1576 * Set T time resolution (in second to be OME compatible) 1577 * 1578 * @see #setPositionTOffset(int, int, int, double) 1579 */ 1580 public void setTimeInterval(double value) 1581 { 1582 if (MetaDataUtil.getTimeInterval(metaData, 0, 0d) != value) 1583 { 1584 MetaDataUtil.setTimeInterval(metaData, 0, value); 1585 metaChanged(ID_TIME_INTERVAL); 1586 } 1587 } 1588 1589 /** 1590 * Returns the pixel size scaling factor to convert a number of pixel/voxel unit into <code>µm</code><br/> 1591 * <br> 1592 * For instance to get the scale ration for 2D distance:<br> 1593 * <code>valueMicroMeter = pixelNum * getPixelSizeScaling(2, 1)</code><br> 1594 * For a 2D surface:<br> 1595 * <code>valueMicroMeter2 = pixelNum * getPixelSizeScaling(2, 2)</code><br> 1596 * For a 3D volume:<br> 1597 * <code>valueMicroMeter3 = pixelNum * getPixelSizeScaling(3, 3)</code><br> 1598 * 1599 * @param dimCompute 1600 * dimension order for size calculation<br> 1601 * <li>1 --> pixel size X used for conversion</li><br> 1602 * <li>2 --> pixel size X and Y used for conversion</li><br> 1603 * <li>3 or above --> pixel size X, Y and Z used for conversion</li><br> 1604 * @param dimResult 1605 * dimension order for the result (unit)<br> 1606 * <li>1 --> distance</li><br> 1607 * <li>2 --> area</li><br> 1608 * <li>3 or above --> volume</li><br> 1609 */ 1610 public double getPixelSizeScaling(int dimCompute, int dimResult) 1611 { 1612 double result; 1613 1614 switch (dimCompute) 1615 { 1616 case 0: 1617 // incorrect 1618 return 0d; 1619 1620 case 1: 1621 result = getPixelSizeX(); 1622 break; 1623 1624 case 2: 1625 result = getPixelSizeX() * getPixelSizeY(); 1626 break; 1627 1628 default: 1629 result = getPixelSizeX() * getPixelSizeY() * getPixelSizeZ(); 1630 break; 1631 } 1632 1633 result = Math.pow(result, (double) dimResult / (double) dimCompute); 1634 1635 return result; 1636 } 1637 1638 /** 1639 * Returns the best pixel size unit for the specified dimension order given the sequence's pixel 1640 * size informations.<br/> 1641 * <li>Compute a 2D distance:</li> 1642 * 1643 * <pre> 1644 * dimCompute = 2; 1645 * dimUnit = 1; 1646 * valueMicroMeter = pixelNum * getPixelSizeScaling(dimCompute); 1647 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1648 * finalValue = UnitUtil.getValueInUnit(valueMicroMeter, UnitPrefix.MICRO, bestUnit); 1649 * valueString = Double.toString(finalValue) + " " + bestUnit.toString() + "m"; 1650 * </pre> 1651 * 1652 * <li>Compute a 2D surface:</li> 1653 * 1654 * <pre> 1655 * dimCompute = 2; 1656 * dimUnit = 2; 1657 * valueMicroMeter = pixelNum * getPixelSizeScaling(dimCompute); 1658 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1659 * finalValue = UnitUtil.getValueInUnit(valueMicroMeter, UnitPrefix.MICRO, bestUnit); 1660 * valueString = Double.toString(finalValue) + " " + bestUnit.toString() + "m2"; 1661 * </pre> 1662 * 1663 * <li>Compute a 3D volume:</li> 1664 * 1665 * <pre> 1666 * dimCompute = 3; 1667 * dimUnit = 3; 1668 * valueMicroMeter = pixelNum * getPixelSizeScaling(dimCompute); 1669 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1670 * finalValue = UnitUtil.getValueInUnit(valueMicroMeter, UnitPrefix.MICRO, bestUnit); 1671 * valueString = Double.toString(finalValue) + " " + bestUnit.toString() + "m3"; 1672 * </pre> 1673 * 1674 * @param dimCompute 1675 * dimension order for size calculation<br> 1676 * <li>1 --> pixel size X used for conversion</li><br> 1677 * <li>2 --> pixel size X and Y used for conversion</li><br> 1678 * <li>3 or above --> pixel size X, Y and Z used for conversion</li><br> 1679 * @param dimResult 1680 * dimension order for the result (unit)<br> 1681 * <li>1 --> distance</li><br> 1682 * <li>2 --> area</li><br> 1683 * <li>3 or above --> volume</li><br> 1684 * @see #calculateSizeBestUnit(double, int, int) 1685 */ 1686 public UnitPrefix getBestPixelSizeUnit(int dimCompute, int dimResult) 1687 { 1688 switch (dimResult) 1689 { 1690 case 0: 1691 // keep original 1692 return UnitPrefix.MICRO; 1693 1694 case 1: 1695 return UnitUtil.getBestUnit((getPixelSizeScaling(dimCompute, dimResult) * 10), UnitPrefix.MICRO, 1696 dimResult); 1697 1698 case 2: 1699 return UnitUtil.getBestUnit((getPixelSizeScaling(dimCompute, dimResult) * 100), UnitPrefix.MICRO, 1700 dimResult); 1701 1702 default: 1703 return UnitUtil.getBestUnit((getPixelSizeScaling(dimCompute, dimResult) * 1000), UnitPrefix.MICRO, 1704 dimResult); 1705 } 1706 } 1707 1708 /** 1709 * Returns the size in µm for the specified amount of sample/pixel value in the specified 1710 * dimension order.<br> 1711 * <br> 1712 * For the perimeter in µm:<br> 1713 * <code>perimeter = calculateSize(contourInPixel, 2, 1)</code><br> 1714 * For a 2D surface in µm2:<br> 1715 * <code>surface = calculateSize(interiorInPixel, 2, 2)</code><br> 1716 * For a 2D surface area in µm2:<br> 1717 * <code>volume = calculateSize(contourInPixel, 3, 2)</code><br> 1718 * For a 3D volume in µm3:<br> 1719 * <code>volume = calculateSize(interiorInPixel, 3, 3)</code><br> 1720 * 1721 * @param pixelNumber 1722 * number of pixel 1723 * @param dimCompute 1724 * dimension order for size calculation<br> 1725 * <li>1 --> pixel size X used for conversion</li><br> 1726 * <li>2 --> pixel size X and Y used for conversion</li><br> 1727 * <li>3 or above --> pixel size X, Y and Z used for conversion</li><br> 1728 * @param dimResult 1729 * dimension order for the result (unit)<br> 1730 * <li>1 --> distance</li><br> 1731 * <li>2 --> area</li><br> 1732 * <li>3 or above --> volume</li><br> 1733 * @see #calculateSizeBestUnit(double, int, int) 1734 */ 1735 public double calculateSize(double pixelNumber, int dimCompute, int dimResult) 1736 { 1737 return pixelNumber * getPixelSizeScaling(dimCompute, dimResult); 1738 } 1739 1740 /** 1741 * Returns the size converted in the best unit (see {@link #getBestPixelSizeUnit(int, int)} for 1742 * the specified amount of sample/pixel value in the specified dimension order.<br/> 1743 * <li>Compute a 2D distance:</li> 1744 * 1745 * <pre> 1746 * dimCompute = 2; 1747 * dimUnit = 1; 1748 * valueBestUnit = calculateSizeBestUnit(pixelNum, dimCompute, dimUnit); 1749 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1750 * valueString = Double.toString(valueBestUnit) + " " + bestUnit.toString() + "m"; 1751 * </pre> 1752 * 1753 * <li>Compute a 2D surface:</li> 1754 * 1755 * <pre> 1756 * dimCompute = 2; 1757 * dimUnit = 2; 1758 * valueBestUnit = calculateSizeBestUnit(pixelNum, dimCompute, dimUnit); 1759 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1760 * valueString = Double.toString(valueBestUnit) + " " + bestUnit.toString() + "m2"; 1761 * </pre> 1762 * 1763 * <li>Compute a 3D volume:</li> 1764 * 1765 * <pre> 1766 * dimCompute = 3; 1767 * dimUnit = 3; 1768 * valueBestUnit = calculateSizeBestUnit(pixelNum, dimCompute, dimUnit); 1769 * bestUnit = getBestPixelSizeUnit(dimCompute, dimUnit); 1770 * valueString = Double.toString(valueBestUnit) + " " + bestUnit.toString() + "m3"; 1771 * </pre> 1772 * 1773 * @param pixelNumber 1774 * number of pixel 1775 * @param dimCompute 1776 * dimension order for size calculation<br> 1777 * <li>1 --> pixel size X used for conversion</li><br> 1778 * <li>2 --> pixel size X and Y used for conversion</li><br> 1779 * <li>3 or above --> pixel size X, Y and Z used for conversion</li><br> 1780 * @param dimResult 1781 * dimension order for the result (unit)<br> 1782 * <li>1 --> distance</li><br> 1783 * <li>2 --> area</li><br> 1784 * <li>3 or above --> volume</li><br> 1785 * @see #calculateSize(double, int, int) 1786 * @see #getBestPixelSizeUnit(int, int) 1787 */ 1788 public double calculateSizeBestUnit(double pixelNumber, int dimCompute, int dimResult) 1789 { 1790 final double value = calculateSize(pixelNumber, dimCompute, dimResult); 1791 final UnitPrefix unit = getBestPixelSizeUnit(dimCompute, dimResult); 1792 return UnitUtil.getValueInUnit(value, UnitPrefix.MICRO, unit, dimResult); 1793 } 1794 1795 /** 1796 * Returns the size and appropriate unit in form of String for specified amount of sample/pixel 1797 * value in the specified dimension order.<br> 1798 * <br> 1799 * For instance if you want to retrieve the 2D distance:<br> 1800 * <code>distanceStr = calculateSize(distanceInPixel, 2, 1, 5)</code><br> 1801 * For a 2D surface:<br> 1802 * <code>surfaceStr = calculateSize(surfaceInPixel, 2, 2, 5)</code><br> 1803 * For a 3D volume:<br> 1804 * <code>volumeStr = calculateSize(volumeInPixel, 3, 3, 5)</code><br> 1805 * 1806 * @param pixelNumber 1807 * number of pixel 1808 * @param dimCompute 1809 * dimension order for the calculation 1810 * @param dimResult 1811 * dimension order for the result (unit) 1812 * @param significantDigit 1813 * wanted significant digit for the result (0 for all) 1814 * @see #calculateSize(double, int, int) 1815 */ 1816 public String calculateSize(double pixelNumber, int dimCompute, int dimResult, int significantDigit) 1817 { 1818 double value = calculateSize(pixelNumber, dimCompute, dimResult); 1819 final String postFix = (dimResult > 1) ? StringUtil.toString(dimResult) : ""; 1820 final UnitPrefix unit = UnitUtil.getBestUnit(value, UnitPrefix.MICRO, dimResult); 1821 // final UnitPrefix unit = getBestPixelSizeUnit(dimCompute, dimResult); 1822 1823 value = UnitUtil.getValueInUnit(value, UnitPrefix.MICRO, unit, dimResult); 1824 if (significantDigit != 0) 1825 value = MathUtil.roundSignificant(value, significantDigit); 1826 1827 return StringUtil.toString(value) + " " + unit.toString() + "m" + postFix; 1828 } 1829 1830 /** 1831 * Get default name for specified channel 1832 */ 1833 public String getDefaultChannelName(int index) 1834 { 1835 return MetaDataUtil.getDefaultChannelName(index); 1836 } 1837 1838 /** 1839 * Get name for specified channel 1840 */ 1841 public String getChannelName(int index) 1842 { 1843 return MetaDataUtil.getChannelName(metaData, 0, index); 1844 } 1845 1846 /** 1847 * Set name for specified channel 1848 */ 1849 public void setChannelName(int index, String value) 1850 { 1851 if (!StringUtil.equals(getChannelName(index), value)) 1852 { 1853 MetaDataUtil.setChannelName(metaData, 0, index, value); 1854 metaChanged(ID_CHANNEL_NAME, index); 1855 } 1856 } 1857 1858 /** 1859 * @deprecated Use {@link #getAutoUpdateChannelBounds()} instead. 1860 */ 1861 @Deprecated 1862 public boolean isComponentAbsBoundsAutoUpdate() 1863 { 1864 return getAutoUpdateChannelBounds(); 1865 } 1866 1867 /** 1868 * @deprecated Use {@link #setAutoUpdateChannelBounds(boolean)} instead. 1869 */ 1870 @Deprecated 1871 public void setComponentAbsBoundsAutoUpdate(boolean value) 1872 { 1873 // nothing here 1874 } 1875 1876 /** 1877 * @return true is channel bounds are automatically updated when sequence data is modified. 1878 * @see #setAutoUpdateChannelBounds(boolean) 1879 */ 1880 public boolean getAutoUpdateChannelBounds() 1881 { 1882 return autoUpdateChannelBounds; 1883 } 1884 1885 /** 1886 * If set to <code>true</code> (default) then channel bounds will be automatically recalculated 1887 * when sequence data is modified.<br> 1888 * This can consume a lot of time if you make many updates on large sequence.<br> 1889 * In this case you should do your updates in a {@link #beginUpdate()} ... {@link #endUpdate()} block to avoid 1890 * severals recalculation. 1891 */ 1892 public void setAutoUpdateChannelBounds(boolean value) 1893 { 1894 if (autoUpdateChannelBounds != value) 1895 { 1896 if (value) 1897 updateChannelsBounds(false); 1898 1899 autoUpdateChannelBounds = value; 1900 } 1901 } 1902 1903 /** 1904 * @deprecated Use {@link #getAutoUpdateChannelBounds()} instead. 1905 */ 1906 @Deprecated 1907 public boolean isComponentUserBoundsAutoUpdate() 1908 { 1909 return getAutoUpdateChannelBounds(); 1910 } 1911 1912 /** 1913 * @deprecated Use {@link #setAutoUpdateChannelBounds(boolean)} instead. 1914 */ 1915 @Deprecated 1916 public void setComponentUserBoundsAutoUpdate(boolean value) 1917 { 1918 setAutoUpdateChannelBounds(value); 1919 } 1920 1921 /** 1922 * @return the AWT dispatching property 1923 * @deprecated Don't use it, events should stay on current thread 1924 */ 1925 @Deprecated 1926 public boolean isAWTDispatching() 1927 { 1928 return updater.isAwtDispatch(); 1929 } 1930 1931 /** 1932 * All events are dispatched on AWT when true else they are dispatched on current thread 1933 * 1934 * @deprecated Don't use it, events should stay on current thread 1935 */ 1936 @Deprecated 1937 public void setAWTDispatching(boolean value) 1938 { 1939 updater.setAwtDispatch(value); 1940 } 1941 1942 /** 1943 * Add the specified listener to listeners list 1944 */ 1945 public void addListener(SequenceListener listener) 1946 { 1947 listeners.add(listener); 1948 } 1949 1950 /** 1951 * Remove the specified listener from listeners list 1952 */ 1953 public void removeListener(SequenceListener listener) 1954 { 1955 listeners.remove(listener); 1956 } 1957 1958 /** 1959 * Get listeners list 1960 */ 1961 public SequenceListener[] getListeners() 1962 { 1963 return listeners.toArray(new SequenceListener[0]); 1964 } 1965 1966 /** 1967 * Add the specified {@link icy.sequence.SequenceModel.SequenceModelListener} to listeners list 1968 */ 1969 @Override 1970 public void addSequenceModelListener(SequenceModelListener listener) 1971 { 1972 modelListeners.add(listener); 1973 } 1974 1975 /** 1976 * Remove the specified {@link icy.sequence.SequenceModel.SequenceModelListener} from listeners 1977 * list 1978 */ 1979 @Override 1980 public void removeSequenceModelListener(SequenceModelListener listener) 1981 { 1982 modelListeners.remove(listener); 1983 } 1984 1985 /** 1986 * Get the Undo manager of this sequence 1987 */ 1988 public IcyUndoManager getUndoManager() 1989 { 1990 return undoManager; 1991 } 1992 1993 /** 1994 * @deprecated Use {@link #contains(Overlay)} instead. 1995 */ 1996 @Deprecated 1997 public boolean contains(Painter painter) 1998 { 1999 return getOverlay(painter) != null; 2000 } 2001 2002 /** 2003 * Returns true if the sequence contains the specified overlay 2004 */ 2005 public boolean contains(Overlay overlay) 2006 { 2007 if (overlay == null) 2008 return false; 2009 2010 synchronized (overlays) 2011 { 2012 return overlays.contains(overlay); 2013 } 2014 } 2015 2016 /** 2017 * Returns true if the sequence contains the specified ROI 2018 */ 2019 public boolean contains(ROI roi) 2020 { 2021 if (roi == null) 2022 return false; 2023 2024 synchronized (rois) 2025 { 2026 return rois.contains(roi); 2027 } 2028 } 2029 2030 /** 2031 * @deprecated Use {@link #hasOverlay()} instead. 2032 */ 2033 @Deprecated 2034 public boolean hasPainter() 2035 { 2036 return hasOverlay(); 2037 } 2038 2039 /** 2040 * @deprecated Use {@link #getOverlays()} instead. 2041 */ 2042 @Deprecated 2043 public ArrayList<Painter> getPainters() 2044 { 2045 final ArrayList<Painter> result = new ArrayList<Painter>(overlays.size()); 2046 2047 synchronized (overlays) 2048 { 2049 for (Overlay overlay : overlays) 2050 { 2051 if (overlay instanceof OverlayWrapper) 2052 result.add(((OverlayWrapper) overlay).getPainter()); 2053 else 2054 result.add(overlay); 2055 } 2056 } 2057 2058 return result; 2059 } 2060 2061 /** 2062 * @deprecated Use {@link #getOverlaySet()} instead. 2063 */ 2064 @Deprecated 2065 public HashSet<Painter> getPainterSet() 2066 { 2067 final HashSet<Painter> result = new HashSet<Painter>(overlays.size()); 2068 2069 synchronized (overlays) 2070 { 2071 for (Overlay overlay : overlays) 2072 { 2073 if (overlay instanceof OverlayWrapper) 2074 result.add(((OverlayWrapper) overlay).getPainter()); 2075 else 2076 result.add(overlay); 2077 } 2078 } 2079 2080 return result; 2081 } 2082 2083 /** 2084 * @deprecated Use {@link #getOverlays(Class)} instead. 2085 */ 2086 @Deprecated 2087 public List<Painter> getPainters(Class<? extends Painter> painterClass) 2088 { 2089 final ArrayList<Painter> result = new ArrayList<Painter>(overlays.size()); 2090 2091 synchronized (overlays) 2092 { 2093 for (Overlay overlay : overlays) 2094 { 2095 if (overlay instanceof OverlayWrapper) 2096 { 2097 if (painterClass.isInstance(((OverlayWrapper) overlay).getPainter())) 2098 result.add(overlay); 2099 } 2100 else 2101 { 2102 if (painterClass.isInstance(overlay)) 2103 result.add(overlay); 2104 } 2105 } 2106 } 2107 2108 return result; 2109 } 2110 2111 /** 2112 * Returns true if the sequence contains at least one Overlay. 2113 */ 2114 public boolean hasOverlay() 2115 { 2116 return overlays.size() > 0; 2117 } 2118 2119 /** 2120 * Returns all overlays attached to this sequence 2121 */ 2122 public List<Overlay> getOverlays() 2123 { 2124 synchronized (overlays) 2125 { 2126 return new ArrayList<Overlay>(overlays); 2127 } 2128 } 2129 2130 /** 2131 * Returns all overlays attached to this sequence (HashSet form) 2132 */ 2133 public Set<Overlay> getOverlaySet() 2134 { 2135 synchronized (overlays) 2136 { 2137 return new HashSet<Overlay>(overlays); 2138 } 2139 } 2140 2141 /** 2142 * Returns true if the sequence contains Overlay of specified Overlay class. 2143 */ 2144 public boolean hasOverlay(Class<? extends Overlay> overlayClass) 2145 { 2146 synchronized (overlays) 2147 { 2148 for (Overlay overlay : overlays) 2149 if (overlayClass.isInstance(overlay)) 2150 return true; 2151 } 2152 2153 return false; 2154 } 2155 2156 /** 2157 * Returns overlays of specified class attached to this sequence 2158 */ 2159 @SuppressWarnings("unchecked") 2160 public <T extends Overlay> List<T> getOverlays(Class<T> overlayClass) 2161 { 2162 final List<T> result = new ArrayList<T>(overlays.size()); 2163 2164 synchronized (overlays) 2165 { 2166 for (Overlay overlay : overlays) 2167 if (overlayClass.isInstance(overlay)) 2168 result.add((T) overlay); 2169 } 2170 2171 return result; 2172 } 2173 2174 /** 2175 * Returns true if the sequence contains at least one ROI. 2176 */ 2177 public boolean hasROI() 2178 { 2179 return rois.size() > 0; 2180 } 2181 2182 /** 2183 * Returns all ROIs attached to this sequence. 2184 * 2185 * @param sorted 2186 * If true the returned list is ordered by the ROI id (creation order). 2187 */ 2188 public List<ROI> getROIs(boolean sorted) 2189 { 2190 final List<ROI> result; 2191 2192 synchronized (rois) 2193 { 2194 result = new ArrayList<ROI>(rois); 2195 } 2196 2197 // sort it if required 2198 if (sorted) 2199 Collections.sort(result, ROI.idComparator); 2200 2201 return result; 2202 } 2203 2204 /** 2205 * Returns all ROIs attached to this sequence. 2206 */ 2207 public ArrayList<ROI> getROIs() 2208 { 2209 return (ArrayList<ROI>) getROIs(false); 2210 } 2211 2212 /** 2213 * Returns all ROIs attached to this sequence (HashSet form) 2214 */ 2215 public HashSet<ROI> getROISet() 2216 { 2217 synchronized (rois) 2218 { 2219 return new HashSet<ROI>(rois); 2220 } 2221 } 2222 2223 /** 2224 * Returns all 2D ROIs attached to this sequence. 2225 * 2226 * @param sorted 2227 * If true the returned list is ordered by the ROI id (creation order). 2228 */ 2229 public List<ROI2D> getROI2Ds(boolean sorted) 2230 { 2231 final List<ROI2D> result = new ArrayList<ROI2D>(rois.size()); 2232 2233 synchronized (rois) 2234 { 2235 for (ROI roi : rois) 2236 if (roi instanceof ROI2D) 2237 result.add((ROI2D) roi); 2238 } 2239 2240 // sort it if required 2241 if (sorted) 2242 Collections.sort(result, ROI.idComparator); 2243 2244 return result; 2245 } 2246 2247 /** 2248 * Returns all 2D ROIs attached to this sequence. 2249 */ 2250 public ArrayList<ROI2D> getROI2Ds() 2251 { 2252 return (ArrayList<ROI2D>) getROI2Ds(false); 2253 } 2254 2255 /** 2256 * Returns all 3D ROIs attached to this sequence. 2257 * 2258 * @param sorted 2259 * If true the returned list is ordered by the ROI id (creation order). 2260 */ 2261 public List<ROI3D> getROI3Ds(boolean sorted) 2262 { 2263 final List<ROI3D> result = new ArrayList<ROI3D>(rois.size()); 2264 2265 synchronized (rois) 2266 { 2267 for (ROI roi : rois) 2268 if (roi instanceof ROI3D) 2269 result.add((ROI3D) roi); 2270 } 2271 2272 // sort it if required 2273 if (sorted) 2274 Collections.sort(result, ROI.idComparator); 2275 2276 return result; 2277 } 2278 2279 /** 2280 * Returns all 3D ROIs attached to this sequence. 2281 */ 2282 public ArrayList<ROI3D> getROI3Ds() 2283 { 2284 return (ArrayList<ROI3D>) getROI3Ds(false); 2285 } 2286 2287 /** 2288 * Returns true if the sequence contains ROI of specified ROI class. 2289 */ 2290 public boolean hasROI(Class<? extends ROI> roiClass) 2291 { 2292 synchronized (rois) 2293 { 2294 for (ROI roi : rois) 2295 if (roiClass.isInstance(roi)) 2296 return true; 2297 } 2298 2299 return false; 2300 } 2301 2302 /** 2303 * Returns ROIs of specified class attached to this sequence 2304 */ 2305 @SuppressWarnings("unchecked") 2306 public <T extends ROI> List<T> getROIs(Class<T> roiClass, boolean sorted) 2307 { 2308 final List<T> result = new ArrayList<T>(rois.size()); 2309 2310 synchronized (rois) 2311 { 2312 for (ROI roi : rois) 2313 if (roiClass.isInstance(roi)) 2314 result.add((T) roi); 2315 } 2316 2317 // sort it if required 2318 if (sorted) 2319 Collections.sort(result, ROI.idComparator); 2320 2321 return result; 2322 } 2323 2324 /** 2325 * @deprecated Use {@link #getROIs(Class, boolean)} instead 2326 */ 2327 @Deprecated 2328 public List<ROI> getROIs(Class<? extends ROI> roiClass) 2329 { 2330 final List<ROI> result = new ArrayList<ROI>(rois.size()); 2331 2332 synchronized (rois) 2333 { 2334 for (ROI roi : rois) 2335 if (roiClass.isInstance(roi)) 2336 result.add(roi); 2337 } 2338 2339 return result; 2340 } 2341 2342 /** 2343 * Returns the number of ROI of specified ROI class attached to the sequence. 2344 */ 2345 public int getROICount(Class<? extends ROI> roiClass) 2346 { 2347 int result = 0; 2348 2349 synchronized (rois) 2350 { 2351 for (ROI roi : rois) 2352 if (roiClass.isInstance(roi)) 2353 result++; 2354 } 2355 2356 return result; 2357 } 2358 2359 /** 2360 * Returns true if the sequence contains at least one selected ROI. 2361 */ 2362 public boolean hasSelectedROI() 2363 { 2364 return getSelectedROI() != null; 2365 } 2366 2367 /** 2368 * Returns the first selected ROI found (null if no ROI selected) 2369 */ 2370 public ROI getSelectedROI() 2371 { 2372 synchronized (rois) 2373 { 2374 for (ROI roi : rois) 2375 if (roi.isSelected()) 2376 return roi; 2377 } 2378 2379 return null; 2380 } 2381 2382 /** 2383 * Returns the first selected 2D ROI found (null if no 2D ROI selected) 2384 */ 2385 public ROI2D getSelectedROI2D() 2386 { 2387 synchronized (rois) 2388 { 2389 for (ROI roi : rois) 2390 if ((roi instanceof ROI2D) && roi.isSelected()) 2391 return (ROI2D) roi; 2392 } 2393 2394 return null; 2395 } 2396 2397 /** 2398 * Returns the first selected 3D ROI found (null if no 3D ROI selected) 2399 */ 2400 public ROI3D getSelectedROI3D() 2401 { 2402 synchronized (rois) 2403 { 2404 for (ROI roi : rois) 2405 if ((roi instanceof ROI3D) && roi.isSelected()) 2406 return (ROI3D) roi; 2407 } 2408 2409 return null; 2410 } 2411 2412 /** 2413 * Returns all selected ROI of given class (Set format). 2414 * 2415 * @param roiClass 2416 * ROI class restriction 2417 * @param wantReadOnly 2418 * also return ROI with read only state 2419 */ 2420 public Set<ROI> getSelectedROISet(Class<? extends ROI> roiClass, boolean wantReadOnly) 2421 { 2422 final Set<ROI> result = new HashSet<ROI>(rois.size()); 2423 2424 synchronized (rois) 2425 { 2426 for (ROI roi : rois) 2427 if (roi.isSelected() && roiClass.isInstance(roi)) 2428 if (wantReadOnly || !roi.isReadOnly()) 2429 result.add(roi); 2430 } 2431 2432 return result; 2433 } 2434 2435 /** 2436 * Returns all selected ROI of given class (Set format). 2437 * 2438 * @param roiClass 2439 * ROI class restriction 2440 */ 2441 @SuppressWarnings("unchecked") 2442 public <T extends ROI> Set<T> getSelectedROISet(Class<T> roiClass) 2443 { 2444 final Set<T> result = new HashSet<T>(rois.size()); 2445 2446 synchronized (rois) 2447 { 2448 for (ROI roi : rois) 2449 if (roi.isSelected() && roiClass.isInstance(roi)) 2450 result.add((T) roi); 2451 } 2452 2453 return result; 2454 } 2455 2456 /** 2457 * Returns all selected ROI (Set format). 2458 */ 2459 public Set<ROI> getSelectedROISet() 2460 { 2461 final Set<ROI> result = new HashSet<ROI>(rois.size()); 2462 2463 synchronized (rois) 2464 { 2465 for (ROI roi : rois) 2466 if (roi.isSelected()) 2467 result.add(roi); 2468 } 2469 2470 return result; 2471 } 2472 2473 /** 2474 * Returns all selected ROI of given class. 2475 * 2476 * @param roiClass 2477 * ROI class restriction 2478 * @param sorted 2479 * If true the returned list is ordered by the ROI id (creation order) 2480 * @param wantReadOnly 2481 * also return ROI with read only state 2482 */ 2483 @SuppressWarnings("unchecked") 2484 public <T extends ROI> List<T> getSelectedROIs(Class<T> roiClass, boolean sorted, boolean wantReadOnly) 2485 { 2486 final List<T> result = new ArrayList<T>(rois.size()); 2487 2488 synchronized (rois) 2489 { 2490 for (ROI roi : rois) 2491 if (roi.isSelected() && roiClass.isInstance(roi)) 2492 result.add((T) roi); 2493 } 2494 2495 // sort it if required 2496 if (sorted) 2497 Collections.sort(result, ROI.idComparator); 2498 2499 return result; 2500 } 2501 2502 /** 2503 * Returns all selected ROI of given class. 2504 * 2505 * @param roiClass 2506 * ROI class restriction 2507 * @param wantReadOnly 2508 * also return ROI with read only state 2509 */ 2510 public List<ROI> getSelectedROIs(Class<? extends ROI> roiClass, boolean wantReadOnly) 2511 { 2512 final List<ROI> result = new ArrayList<ROI>(rois.size()); 2513 2514 synchronized (rois) 2515 { 2516 for (ROI roi : rois) 2517 if (roi.isSelected() && roiClass.isInstance(roi)) 2518 if (wantReadOnly || !roi.isReadOnly()) 2519 result.add(roi); 2520 } 2521 2522 return result; 2523 } 2524 2525 /** 2526 * Returns all selected ROI 2527 */ 2528 public ArrayList<ROI> getSelectedROIs() 2529 { 2530 final ArrayList<ROI> result = new ArrayList<ROI>(rois.size()); 2531 2532 synchronized (rois) 2533 { 2534 for (ROI roi : rois) 2535 if (roi.isSelected()) 2536 result.add(roi); 2537 } 2538 2539 return result; 2540 } 2541 2542 /** 2543 * Returns all selected 2D ROI 2544 */ 2545 public ArrayList<ROI2D> getSelectedROI2Ds() 2546 { 2547 final ArrayList<ROI2D> result = new ArrayList<ROI2D>(rois.size()); 2548 2549 synchronized (rois) 2550 { 2551 for (ROI roi : rois) 2552 if ((roi instanceof ROI2D) && roi.isSelected()) 2553 result.add((ROI2D) roi); 2554 } 2555 2556 return result; 2557 } 2558 2559 /** 2560 * Returns all selected 3D ROI 2561 */ 2562 public ArrayList<ROI3D> getSelectedROI3Ds() 2563 { 2564 final ArrayList<ROI3D> result = new ArrayList<ROI3D>(rois.size()); 2565 2566 synchronized (rois) 2567 { 2568 for (ROI roi : rois) 2569 if ((roi instanceof ROI3D) && roi.isSelected()) 2570 result.add((ROI3D) roi); 2571 } 2572 2573 return result; 2574 } 2575 2576 /** 2577 * Returns the current focused ROI (null if no ROI focused) 2578 */ 2579 public ROI getFocusedROI() 2580 { 2581 synchronized (rois) 2582 { 2583 for (ROI roi : rois) 2584 if (roi.isFocused()) 2585 return roi; 2586 } 2587 2588 return null; 2589 } 2590 2591 /** 2592 * Set the selected ROI (exclusive selection).<br> 2593 * Specifying a <code>null</code> ROI here will actually clear all ROI selection.<br> 2594 * Note that you can use {@link #setSelectedROIs(List)} or {@link ROI#setSelected(boolean)} for 2595 * multiple ROI selection. 2596 * 2597 * @param roi 2598 * the ROI to select. 2599 * @return <code>false</code> is the specified ROI is not attached to the sequence. 2600 */ 2601 public boolean setSelectedROI(ROI roi) 2602 { 2603 beginUpdate(); 2604 try 2605 { 2606 synchronized (rois) 2607 { 2608 for (ROI currentRoi : rois) 2609 if (currentRoi != roi) 2610 currentRoi.setSelected(false); 2611 } 2612 2613 if (contains(roi)) 2614 { 2615 roi.setSelected(true); 2616 return true; 2617 } 2618 } 2619 finally 2620 { 2621 endUpdate(); 2622 } 2623 2624 return false; 2625 } 2626 2627 /** 2628 * @deprecated Use {@link #setSelectedROI(ROI)} instead. 2629 */ 2630 @Deprecated 2631 public boolean setSelectedROI(ROI roi, boolean exclusive) 2632 { 2633 if (exclusive) 2634 return setSelectedROI(roi); 2635 2636 if (contains(roi)) 2637 { 2638 roi.setSelected(true); 2639 return true; 2640 } 2641 2642 return false; 2643 } 2644 2645 /** 2646 * @deprecated Use {@link #setSelectedROIs(List)} instead. 2647 */ 2648 @Deprecated 2649 public void setSelectedROIs(ArrayList<ROI> selected) 2650 { 2651 setSelectedROIs((List<ROI>) selected); 2652 } 2653 2654 /** 2655 * Set selected ROI (unselected all others) 2656 */ 2657 public void setSelectedROIs(List<? extends ROI> selected) 2658 { 2659 final List<ROI> oldSelected = getSelectedROIs(); 2660 2661 final int newSelectedSize = (selected == null) ? 0 : selected.size(); 2662 final int oldSelectedSize = oldSelected.size(); 2663 2664 // easy optimization 2665 if ((newSelectedSize == 0) && (oldSelectedSize == 0)) 2666 return; 2667 2668 final HashSet<ROI> newSelected; 2669 2670 // use HashSet for fast .contains() ! 2671 if (selected != null) 2672 newSelected = new HashSet<ROI>(selected); 2673 else 2674 newSelected = new HashSet<ROI>(); 2675 2676 // selection changed ? 2677 if (!CollectionUtil.equals(oldSelected, newSelected)) 2678 { 2679 beginUpdate(); 2680 try 2681 { 2682 if (newSelectedSize > 0) 2683 { 2684 for (ROI roi : getROIs()) 2685 roi.setSelected(newSelected.contains(roi)); 2686 } 2687 else 2688 { 2689 // unselected all ROIs 2690 for (ROI roi : getROIs()) 2691 roi.setSelected(false); 2692 } 2693 } 2694 finally 2695 { 2696 endUpdate(); 2697 } 2698 } 2699 } 2700 2701 /** 2702 * Set the focused ROI 2703 */ 2704 public boolean setFocusedROI(ROI roi) 2705 { 2706 // faster .contain() 2707 final Set<ROI> listRoi = getROISet(); 2708 2709 beginUpdate(); 2710 try 2711 { 2712 for (ROI currentRoi : listRoi) 2713 if (currentRoi != roi) 2714 currentRoi.internalUnfocus(); 2715 2716 if (listRoi.contains(roi)) 2717 { 2718 roi.internalFocus(); 2719 return true; 2720 } 2721 } 2722 finally 2723 { 2724 endUpdate(); 2725 } 2726 2727 return false; 2728 } 2729 2730 /** 2731 * Add the specified collection of ROI to the sequence. 2732 * 2733 * @param rois 2734 * the collection of ROI to attach to the sequence 2735 * @param canUndo 2736 * If true the action can be canceled by the undo manager. 2737 * @return <code>true</code> if the operation succeed or <code>false</code> if some ROIs could 2738 * not be added (already present) 2739 */ 2740 public boolean addROIs(Collection<? extends ROI> rois, boolean canUndo) 2741 { 2742 if (!rois.isEmpty()) 2743 { 2744 final List<ROI> addedRois = new ArrayList<ROI>(); 2745 2746 for (ROI roi : rois) 2747 { 2748 if (addROI(roi, false)) 2749 addedRois.add(roi); 2750 } 2751 2752 if (canUndo && !addedRois.isEmpty()) 2753 addUndoableEdit(new ROIAddsSequenceEdit(this, addedRois)); 2754 2755 return addedRois.size() == rois.size(); 2756 } 2757 2758 return true; 2759 } 2760 2761 /** 2762 * Add the specified ROI to the sequence. 2763 * 2764 * @param roi 2765 * ROI to attach to the sequence 2766 */ 2767 public boolean addROI(ROI roi) 2768 { 2769 return addROI(roi, false); 2770 } 2771 2772 /** 2773 * Add the specified ROI to the sequence. 2774 * 2775 * @param roi 2776 * ROI to attach to the sequence 2777 * @param canUndo 2778 * If true the action can be canceled by the undo manager. 2779 * @return <code>true</code> if the operation succeed or <code>false</code> otherwise (already 2780 * present) 2781 */ 2782 public boolean addROI(ROI roi, boolean canUndo) 2783 { 2784 if ((roi == null) || contains(roi)) 2785 return false; 2786 2787 synchronized (rois) 2788 { 2789 rois.add(roi); 2790 } 2791 // add listener to ROI 2792 roi.addListener(this); 2793 // notify roi added 2794 roiChanged(roi, SequenceEventType.ADDED); 2795 // then add ROI overlay to sequence 2796 addOverlay(roi.getOverlay()); 2797 2798 if (canUndo) 2799 addUndoableEdit(new ROIAddSequenceEdit(this, roi)); 2800 2801 return true; 2802 2803 } 2804 2805 /** 2806 * Remove the specified ROI from the sequence. 2807 * 2808 * @param roi 2809 * ROI to detach from the sequence 2810 */ 2811 public boolean removeROI(ROI roi) 2812 { 2813 return removeROI(roi, false); 2814 } 2815 2816 /** 2817 * Remove the specified ROI from the sequence. 2818 * 2819 * @param roi 2820 * ROI to detach from the sequence 2821 * @param canUndo 2822 * If true the action can be canceled by the undo manager. 2823 * @return <code>false</code> if the ROI was not found in the sequence.<br/> 2824 * Returns <code>true</code> otherwise. 2825 */ 2826 public boolean removeROI(ROI roi, boolean canUndo) 2827 { 2828 if (contains(roi)) 2829 { 2830 // remove ROI overlay first 2831 removeOverlay(roi.getOverlay()); 2832 2833 // remove ROI 2834 synchronized (rois) 2835 { 2836 rois.remove(roi); 2837 } 2838 // remove listener 2839 roi.removeListener(this); 2840 // notify roi removed 2841 roiChanged(roi, SequenceEventType.REMOVED); 2842 2843 if (canUndo) 2844 addUndoableEdit(new ROIRemoveSequenceEdit(this, roi)); 2845 2846 return true; 2847 } 2848 2849 return false; 2850 } 2851 2852 /** 2853 * Remove the specified collection of ROI from the sequence. 2854 * 2855 * @param rois 2856 * the collection of ROI to remove from the sequence 2857 * @param canUndo 2858 * If true the action can be canceled by the undo manager. 2859 * @return <code>true</code> if all ROI from the collection has been correctly removed. 2860 */ 2861 public boolean removeROIs(Collection<? extends ROI> rois, boolean canUndo) 2862 { 2863 if (!rois.isEmpty()) 2864 { 2865 final List<ROI> removedRois = new ArrayList<ROI>(); 2866 2867 for (ROI roi : rois) 2868 { 2869 if (removeROI(roi, false)) 2870 removedRois.add(roi); 2871 } 2872 2873 if (canUndo && !removedRois.isEmpty()) 2874 addUndoableEdit(new ROIRemovesSequenceEdit(this, removedRois)); 2875 2876 return removedRois.size() == rois.size(); 2877 } 2878 2879 return true; 2880 } 2881 2882 /** 2883 * Remove all selected ROI from the sequence. 2884 * 2885 * @param removeReadOnly 2886 * Specify if we should also remove <i>read only</i> ROI (see {@link ROI#isReadOnly()}) 2887 * @return <code>true</code> if at least one ROI was removed.<br/> 2888 * Returns <code>false</code> otherwise 2889 */ 2890 public boolean removeSelectedROIs(boolean removeReadOnly) 2891 { 2892 return removeSelectedROIs(removeReadOnly, false); 2893 } 2894 2895 /** 2896 * Remove all selected ROI from the sequence. 2897 * 2898 * @param removeReadOnly 2899 * Specify if we should also remove <i>read only</i> ROI (see {@link ROI#isReadOnly()}) 2900 * @param canUndo 2901 * If true the action can be canceled by the undo manager. 2902 * @return <code>true</code> if at least one ROI was removed.<br/> 2903 * Returns <code>false</code> otherwise 2904 */ 2905 public boolean removeSelectedROIs(boolean removeReadOnly, boolean canUndo) 2906 { 2907 final List<ROI> undoList = new ArrayList<ROI>(); 2908 2909 beginUpdate(); 2910 try 2911 { 2912 synchronized (rois) 2913 { 2914 for (ROI roi : getROIs()) 2915 { 2916 if (roi.isSelected() && (removeReadOnly || !roi.isReadOnly())) 2917 { 2918 // remove ROI overlay first 2919 removeOverlay(roi.getOverlay()); 2920 2921 rois.remove(roi); 2922 // remove listener 2923 roi.removeListener(this); 2924 // notify roi removed 2925 roiChanged(roi, SequenceEventType.REMOVED); 2926 2927 // save deleted ROI 2928 undoList.add(roi); 2929 } 2930 } 2931 } 2932 2933 if (canUndo) 2934 undoManager.addEdit(new ROIRemovesSequenceEdit(this, undoList)); 2935 } 2936 finally 2937 { 2938 endUpdate(); 2939 } 2940 2941 return !undoList.isEmpty(); 2942 } 2943 2944 /** 2945 * Remove all ROI from the sequence. 2946 */ 2947 public void removeAllROI() 2948 { 2949 removeAllROI(false); 2950 } 2951 2952 /** 2953 * Remove all ROI from the sequence. 2954 * 2955 * @param canUndo 2956 * If true the action can be canceled by the undo manager. 2957 */ 2958 public void removeAllROI(boolean canUndo) 2959 { 2960 if (!rois.isEmpty()) 2961 { 2962 final List<ROI> allROIs = getROIs(); 2963 2964 // remove all ROI 2965 for (ROI roi : allROIs) 2966 removeROI(roi, false); 2967 2968 if (canUndo) 2969 addUndoableEdit(new ROIRemovesSequenceEdit(this, allROIs)); 2970 } 2971 } 2972 2973 /** 2974 * Return the overlay associated to the specified painter.<br> 2975 * Used only for backward compatibility with {@link Painter} interface. 2976 */ 2977 @SuppressWarnings("deprecation") 2978 protected Overlay getOverlay(Painter painter) 2979 { 2980 if (painter instanceof Overlay) 2981 return (Overlay) painter; 2982 2983 synchronized (overlays) 2984 { 2985 for (Overlay overlay : overlays) 2986 if (overlay instanceof OverlayWrapper) 2987 if (((OverlayWrapper) overlay).getPainter() == painter) 2988 return overlay; 2989 } 2990 2991 return null; 2992 } 2993 2994 /** 2995 * @deprecated Use {@link #addOverlay(Overlay)} instead. 2996 */ 2997 @Deprecated 2998 public boolean addPainter(Painter painter) 2999 { 3000 if (painter instanceof Overlay) 3001 return addOverlay((Overlay) painter); 3002 3003 if ((painter == null) || contains(painter)) 3004 return false; 3005 3006 addOverlay(new OverlayWrapper(painter, "Overlay wrapper")); 3007 3008 return true; 3009 } 3010 3011 /** 3012 * @deprecated Use {@link #removeOverlay(Overlay)} instead. 3013 */ 3014 @Deprecated 3015 public boolean removePainter(Painter painter) 3016 { 3017 if (painter instanceof Overlay) 3018 return removeOverlay((Overlay) painter); 3019 3020 return removeOverlay(getOverlay(painter)); 3021 } 3022 3023 /** 3024 * Add an overlay to the sequence. 3025 */ 3026 public boolean addOverlay(Overlay overlay) 3027 { 3028 if ((overlay == null) || contains(overlay)) 3029 return false; 3030 3031 synchronized (overlays) 3032 { 3033 overlays.add(overlay); 3034 } 3035 3036 // add listener 3037 overlay.addOverlayListener(this); 3038 // notify overlay added 3039 overlayChanged(overlay, SequenceEventType.ADDED); 3040 3041 return true; 3042 } 3043 3044 /** 3045 * Remove an overlay from the sequence. 3046 */ 3047 public boolean removeOverlay(Overlay overlay) 3048 { 3049 boolean result; 3050 3051 synchronized (overlays) 3052 { 3053 result = overlays.remove(overlay); 3054 } 3055 3056 if (result) 3057 { 3058 // remove listener 3059 overlay.removeOverlayListener(this); 3060 // notify overlay removed 3061 overlayChanged(overlay, SequenceEventType.REMOVED); 3062 } 3063 3064 return result; 3065 } 3066 3067 /** 3068 * Returns the VolumetricImage at position t 3069 */ 3070 public VolumetricImage getVolumetricImage(int t) 3071 { 3072 synchronized (volumetricImages) 3073 { 3074 return volumetricImages.get(Integer.valueOf(t)); 3075 } 3076 } 3077 3078 /** 3079 * Returns the first VolumetricImage 3080 */ 3081 protected VolumetricImage getFirstVolumetricImage() 3082 { 3083 final Entry<Integer, VolumetricImage> entry; 3084 3085 synchronized (volumetricImages) 3086 { 3087 entry = volumetricImages.firstEntry(); 3088 } 3089 3090 if (entry != null) 3091 return entry.getValue(); 3092 3093 return null; 3094 } 3095 3096 /** 3097 * Returns the last VolumetricImage 3098 */ 3099 protected VolumetricImage getLastVolumetricImage() 3100 { 3101 final Entry<Integer, VolumetricImage> entry; 3102 3103 synchronized (volumetricImages) 3104 { 3105 entry = volumetricImages.lastEntry(); 3106 } 3107 3108 if (entry != null) 3109 return entry.getValue(); 3110 3111 return null; 3112 } 3113 3114 /** 3115 * Add an empty volumetricImage at last index + 1 3116 */ 3117 public VolumetricImage addVolumetricImage() 3118 { 3119 return setVolumetricImage(getSizeT()); 3120 } 3121 3122 /** 3123 * Add an empty volumetricImage at t position 3124 */ 3125 protected VolumetricImage setVolumetricImage(int t) 3126 { 3127 // remove old volumetric image if any 3128 removeAllImages(t); 3129 3130 final VolumetricImage volImg = new VolumetricImage(this); 3131 3132 synchronized (volumetricImages) 3133 { 3134 volumetricImages.put(Integer.valueOf(t), volImg); 3135 } 3136 3137 return volImg; 3138 } 3139 3140 /** 3141 * Add a volumetricImage at t position<br> 3142 * It actually create a new volumetricImage and add it to the sequence<br> 3143 * The new created volumetricImage is returned 3144 */ 3145 public VolumetricImage addVolumetricImage(int t, VolumetricImage volImg) 3146 { 3147 if (volImg != null) 3148 { 3149 final VolumetricImage result; 3150 3151 beginUpdate(); 3152 try 3153 { 3154 // get new volumetric image (remove old one if any) 3155 result = setVolumetricImage(t); 3156 3157 for (Entry<Integer, IcyBufferedImage> entry : volImg.getImages().entrySet()) 3158 setImage(t, entry.getKey().intValue(), entry.getValue()); 3159 } 3160 finally 3161 { 3162 endUpdate(); 3163 } 3164 3165 return result; 3166 } 3167 3168 return null; 3169 } 3170 3171 /** 3172 * @deprecated Use {@link #removeAllImages(int)} instead. 3173 */ 3174 @Deprecated 3175 public boolean removeVolumetricImage(int t) 3176 { 3177 return removeAllImages(t); 3178 } 3179 3180 /** 3181 * Returns the last image of VolumetricImage[t] 3182 */ 3183 public IcyBufferedImage getLastImage(int t) 3184 { 3185 final VolumetricImage volImg = getVolumetricImage(t); 3186 3187 if (volImg != null) 3188 return volImg.getLastImage(); 3189 3190 return null; 3191 } 3192 3193 /** 3194 * Returns the first image of first VolumetricImage 3195 */ 3196 public IcyBufferedImage getFirstImage() 3197 { 3198 final VolumetricImage volImg = getFirstVolumetricImage(); 3199 3200 if (volImg != null) 3201 return volImg.getFirstImage(); 3202 3203 return null; 3204 } 3205 3206 /** 3207 * Returns the first non null image if exist 3208 */ 3209 public IcyBufferedImage getFirstNonNullImage() 3210 { 3211 synchronized (volumetricImages) 3212 { 3213 for (VolumetricImage volImg : volumetricImages.values()) 3214 { 3215 final IcyBufferedImage img = volImg.getFirstNonNullImage(); 3216 if (img != null) 3217 return img; 3218 } 3219 } 3220 3221 return null; 3222 } 3223 3224 /** 3225 * Returns the last image of last VolumetricImage 3226 */ 3227 public IcyBufferedImage getLastImage() 3228 { 3229 final VolumetricImage volImg = getLastVolumetricImage(); 3230 3231 if (volImg != null) 3232 return volImg.getLastImage(); 3233 3234 return null; 3235 } 3236 3237 /** 3238 * Returns a single component image corresponding to the component c of the image 3239 * at time t and depth z.<br> 3240 * This actually create a new image which share its data with internal image 3241 * so any modifications to one affect the other.<br> 3242 * if <code>(c == -1)</code> then this method is equivalent to {@link #getImage(int, int)}<br> 3243 * if <code>((c == 0) || (sizeC == 1))</code> then this method is equivalent to {@link #getImage(int, int)}<br> 3244 * if <code>((c < 0) || (c >= sizeC))</code> then it returns <code>null</code> 3245 * 3246 * @see IcyBufferedImageUtil#extractChannel(IcyBufferedImage, int) 3247 * @since version 1.0.3.3b 3248 */ 3249 @Override 3250 public IcyBufferedImage getImage(int t, int z, int c) 3251 { 3252 final IcyBufferedImage src = getImage(t, z); 3253 3254 if ((src == null) || (c == -1)) 3255 return src; 3256 3257 return src.getImage(c); 3258 } 3259 3260 /** 3261 * Returns image at time t and depth z. 3262 * 3263 * @param loadData 3264 * if <code>true</code> then we ensure that image data is loaded (in case of lazy loading) before returning the image 3265 */ 3266 public IcyBufferedImage getImage(int t, int z, boolean loadData) 3267 { 3268 final VolumetricImage volImg = getVolumetricImage(t); 3269 3270 if (volImg != null) 3271 { 3272 final IcyBufferedImage result = volImg.getImage(z); 3273 3274 if (loadData && (result != null)) 3275 result.loadData(); 3276 3277 return result; 3278 } 3279 3280 return null; 3281 } 3282 3283 /** 3284 * Returns image at time t and depth z 3285 */ 3286 @Override 3287 public IcyBufferedImage getImage(int t, int z) 3288 { 3289 // FIXME: check if that is *really* not needed anymore (as the image contains the importer information) 3290 3291 // by default we prefer to load data on getImage(t,z) call as we probably need it 3292 // (and that is important if we want to set the image in another Sequence) 3293 // return getImage(t, z, true); 3294 3295 return getImage(t, z, false); 3296 } 3297 3298 /** 3299 * Returns all images at specified t position 3300 */ 3301 public ArrayList<IcyBufferedImage> getImages(int t) 3302 { 3303 final VolumetricImage volImg = getVolumetricImage(t); 3304 3305 if (volImg != null) 3306 return volImg.getAllImage(); 3307 3308 return new ArrayList<IcyBufferedImage>(); 3309 } 3310 3311 /** 3312 * Returns all images of sequence in [ZT] order:<br> 3313 * 3314 * <pre> 3315 * T=0 Z=0 3316 * T=0 Z=1 3317 * T=0 Z=2 3318 * ... 3319 * T=1 Z=0 3320 * ... 3321 * </pre> 3322 */ 3323 public ArrayList<IcyBufferedImage> getAllImage() 3324 { 3325 final ArrayList<IcyBufferedImage> result = new ArrayList<IcyBufferedImage>(); 3326 3327 synchronized (volumetricImages) 3328 { 3329 for (VolumetricImage volImg : volumetricImages.values()) 3330 result.addAll(volImg.getAllImage()); 3331 } 3332 3333 return result; 3334 } 3335 3336 /** 3337 * Put an image into the specified VolumetricImage at the given z location 3338 */ 3339 protected void setImage(VolumetricImage volImg, int z, BufferedImage image) throws IllegalArgumentException 3340 { 3341 if (volImg != null) 3342 { 3343 // not the same image ? 3344 if (volImg.getImage(z) != image) 3345 { 3346 // this is different from removeImage as we don't remove empty VolumetricImage 3347 if (image == null) 3348 volImg.removeImage(z); 3349 else 3350 { 3351 IcyBufferedImage icyImg; 3352 3353 // convert to icyImage if needed 3354 if (image instanceof IcyBufferedImage) 3355 icyImg = (IcyBufferedImage) image; 3356 else 3357 icyImg = IcyBufferedImage.createFrom(image); 3358 3359 // possible type change ? 3360 final boolean typeChange = (colorModel == null) || isEmpty() 3361 || ((getNumImage() == 1) && (volImg.getImage(z) != null)); 3362 3363 // not changing type and not compatible 3364 if (!typeChange && !isCompatible(icyImg)) 3365 throw new IllegalArgumentException("Sequence.setImage: image is not compatible !"); 3366 3367 // we want to share the same color space for all the sequence: 3368 // colormap eats a lot of memory so it's better to keep one global and we never 3369 // use colormap for single image anyway. But it's important to preserve the colormodel for each 3370 // image though as it store the channel bounds informations. 3371 if (colorModel != null) 3372 icyImg.getIcyColorModel().setColorSpace(colorModel.getIcyColorSpace()); 3373 3374 // set automatic channel update from sequence 3375 icyImg.setAutoUpdateChannelBounds(getAutoUpdateChannelBounds()); 3376 3377 // set image 3378 volImg.setImage(z, icyImg); 3379 3380 // possible type change --> virtual state may have changed 3381 if (typeChange) 3382 metaChanged(ID_VIRTUAL); 3383 } 3384 } 3385 } 3386 } 3387 3388 /** 3389 * Set an image at the specified position.<br/> 3390 * Note that the image will be transformed in IcyBufferedImage internally if needed 3391 * 3392 * @param t 3393 * T position 3394 * @param z 3395 * Z position 3396 * @param image 3397 * the image to set 3398 */ 3399 public void setImage(int t, int z, BufferedImage image) throws IllegalArgumentException 3400 { 3401 final boolean volImgCreated; 3402 3403 if (image == null) 3404 return; 3405 3406 VolumetricImage volImg = getVolumetricImage(t); 3407 3408 if (volImg == null) 3409 { 3410 volImg = setVolumetricImage(t); 3411 volImgCreated = true; 3412 } 3413 else 3414 volImgCreated = false; 3415 3416 try 3417 { 3418 // set image 3419 setImage(volImg, z, image); 3420 } 3421 catch (IllegalArgumentException e) 3422 { 3423 // image set failed ? remove empty image list if needed 3424 if (volImgCreated) 3425 removeAllImages(t); 3426 // throw exception 3427 throw e; 3428 } 3429 } 3430 3431 /** 3432 * Add an image (image is added in Z dimension).<br> 3433 * This method is equivalent to <code>setImage(max(getSizeT() - 1, 0), getSizeZ(t), image)</code> 3434 */ 3435 public void addImage(BufferedImage image) throws IllegalArgumentException 3436 { 3437 final int t = Math.max(getSizeT() - 1, 0); 3438 3439 setImage(t, getSizeZ(t), image); 3440 } 3441 3442 /** 3443 * Add an image at specified T position.<br> 3444 * This method is equivalent to <code>setImage(t, getSizeZ(t), image)</code> 3445 */ 3446 public void addImage(int t, BufferedImage image) throws IllegalArgumentException 3447 { 3448 setImage(t, getSizeZ(t), image); 3449 } 3450 3451 /** 3452 * Remove the image at the specified position. 3453 */ 3454 public boolean removeImage(int t, int z) 3455 { 3456 final VolumetricImage volImg = getVolumetricImage(t); 3457 3458 if (volImg != null) 3459 { 3460 final boolean result; 3461 3462 beginUpdate(); 3463 try 3464 { 3465 result = volImg.removeImage(z); 3466 3467 // empty ? 3468 if (volImg.isEmpty()) 3469 // remove it 3470 removeAllImages(t); 3471 } 3472 finally 3473 { 3474 endUpdate(); 3475 } 3476 3477 return result; 3478 } 3479 3480 return false; 3481 } 3482 3483 /** 3484 * Remove all images at position <code>t</code> 3485 */ 3486 public boolean removeAllImages(int t) 3487 { 3488 final VolumetricImage volImg; 3489 3490 synchronized (volumetricImages) 3491 { 3492 volImg = volumetricImages.remove(Integer.valueOf(t)); 3493 } 3494 3495 // we do manual clear to dispatch events correctly 3496 if (volImg != null) 3497 volImg.clear(); 3498 3499 return volImg != null; 3500 } 3501 3502 /** 3503 * Remove all images 3504 */ 3505 public void removeAllImages() 3506 { 3507 beginUpdate(); 3508 try 3509 { 3510 synchronized (volumetricImages) 3511 { 3512 while (!volumetricImages.isEmpty()) 3513 { 3514 final VolumetricImage volImg = volumetricImages.pollFirstEntry().getValue(); 3515 // we do manual clear to dispatch events correctly 3516 if (volImg != null) 3517 volImg.clear(); 3518 } 3519 } 3520 } 3521 finally 3522 { 3523 endUpdate(); 3524 } 3525 } 3526 3527 /** 3528 * @deprecated Use {@link #removeAllImages(int)} instead. 3529 */ 3530 @Deprecated 3531 public boolean removeAllImage(int t) 3532 { 3533 return removeAllImages(t); 3534 } 3535 3536 /** 3537 * @deprecated Use {@link #removeAllImages()} instead. 3538 */ 3539 @Deprecated 3540 public void removeAllImage() 3541 { 3542 removeAllImages(); 3543 } 3544 3545 /** 3546 * Remove empty element of image list 3547 */ 3548 public void packImageList() 3549 { 3550 beginUpdate(); 3551 try 3552 { 3553 synchronized (volumetricImages) 3554 { 3555 for (Entry<Integer, VolumetricImage> entry : volumetricImages.entrySet()) 3556 { 3557 final VolumetricImage volImg = entry.getValue(); 3558 final int t = entry.getKey().intValue(); 3559 3560 if (volImg == null) 3561 { 3562 removeAllImages(t); 3563 } 3564 else 3565 { 3566 // pack the list 3567 volImg.pack(); 3568 // empty ? --> remove it 3569 if (volImg.isEmpty()) 3570 removeAllImages(t); 3571 } 3572 } 3573 } 3574 } 3575 finally 3576 { 3577 endUpdate(); 3578 } 3579 } 3580 3581 /** 3582 * return the number of loaded image 3583 */ 3584 public int getNumImage() 3585 { 3586 int result = 0; 3587 3588 synchronized (volumetricImages) 3589 { 3590 for (VolumetricImage volImg : volumetricImages.values()) 3591 if (volImg != null) 3592 result += volImg.getNumImage(); 3593 } 3594 3595 return result; 3596 } 3597 3598 /** 3599 * return true if no image in sequence 3600 */ 3601 public boolean isEmpty() 3602 { 3603 synchronized (volumetricImages) 3604 { 3605 for (VolumetricImage volImg : volumetricImages.values()) 3606 if ((volImg != null) && (!volImg.isEmpty())) 3607 return false; 3608 } 3609 3610 return true; 3611 } 3612 3613 /** 3614 * Returns true if the sequence uses default attributed name 3615 */ 3616 public boolean isDefaultName() 3617 { 3618 return getName().startsWith(DEFAULT_NAME); 3619 } 3620 3621 /** 3622 * Returns true is the specified channel uses default attributed name 3623 */ 3624 public boolean isDefaultChannelName(int index) 3625 { 3626 return StringUtil.equals(getChannelName(index), getDefaultChannelName(index)); 3627 } 3628 3629 /** 3630 * Returns the number of volumetricImage in the sequence<br> 3631 * Use getSizeT instead 3632 * 3633 * @see #getSizeT 3634 * @deprecated 3635 */ 3636 @Deprecated 3637 public int getLength() 3638 { 3639 return getSizeT(); 3640 } 3641 3642 /** 3643 * return the number of volumetricImage in the sequence 3644 */ 3645 @Override 3646 public int getSizeT() 3647 { 3648 synchronized (volumetricImages) 3649 { 3650 if (volumetricImages.isEmpty()) 3651 return 0; 3652 3653 return volumetricImages.lastKey().intValue() + 1; 3654 } 3655 } 3656 3657 /** 3658 * Returns the global number of z stack in the sequence. 3659 * Use getSizeZ instead 3660 * 3661 * @see #getSizeZ 3662 * @deprecated 3663 */ 3664 @Deprecated 3665 public int getDepth() 3666 { 3667 return getSizeZ(); 3668 } 3669 3670 /** 3671 * Returns the global number of z stack in the sequence. 3672 */ 3673 @Override 3674 public int getSizeZ() 3675 { 3676 final int sizeT = getSizeT(); 3677 3678 int result = 0; 3679 for (int i = 0; i < sizeT; i++) 3680 result = Math.max(result, getSizeZ(i)); 3681 3682 return result; 3683 } 3684 3685 /** 3686 * Returns the number of z stack for the volumetricImage[t]. 3687 */ 3688 public int getSizeZ(int t) 3689 { 3690 // t = -1 means global Z size 3691 if (t == -1) 3692 return getSizeZ(); 3693 3694 final VolumetricImage volImg = getVolumetricImage(t); 3695 3696 if (volImg != null) 3697 return volImg.getSize(); 3698 3699 return 0; 3700 } 3701 3702 /** 3703 * Returns the number of component/channel/band per image.<br> 3704 * Use getSizeC instead 3705 * 3706 * @see #getSizeC 3707 * @deprecated 3708 */ 3709 @Deprecated 3710 public int getNumComponents() 3711 { 3712 return getSizeC(); 3713 } 3714 3715 /** 3716 * Returns the number of component/channel/band per image 3717 */ 3718 @Override 3719 public int getSizeC() 3720 { 3721 // color model defined ? --> get it from color model 3722 if (colorModel != null) 3723 return colorModel.getNumComponents(); 3724 3725 // else try to get it from metadata 3726 return MetaDataUtil.getSizeC(metaData, 0); 3727 } 3728 3729 /** 3730 * Same as {@link #getSizeY()} 3731 */ 3732 public int getHeight() 3733 { 3734 return getSizeY(); 3735 } 3736 3737 /** 3738 * Returns the height of the sequence (0 if the sequence contains no image). 3739 */ 3740 @Override 3741 public int getSizeY() 3742 { 3743 // try to get from image first 3744 final IcyBufferedImage img = getFirstNonNullImage(); 3745 3746 if (img != null) 3747 return img.getHeight(); 3748 3749 // else try to get from metadata 3750 return MetaDataUtil.getSizeY(metaData, 0); 3751 } 3752 3753 /** 3754 * Same as {@link #getSizeX()} 3755 */ 3756 public int getWidth() 3757 { 3758 return getSizeX(); 3759 } 3760 3761 /** 3762 * Returns the width of the sequence (0 if the sequence contains no image). 3763 */ 3764 @Override 3765 public int getSizeX() 3766 { 3767 final IcyBufferedImage img = getFirstNonNullImage(); 3768 3769 // try to get it from image first 3770 if (img != null) 3771 return img.getWidth(); 3772 3773 // else try to get from metadata 3774 return MetaDataUtil.getSizeX(metaData, 0); 3775 } 3776 3777 /** 3778 * Returns the size of the specified dimension 3779 */ 3780 public int getSize(DimensionId dim) 3781 { 3782 switch (dim) 3783 { 3784 case X: 3785 return getSizeX(); 3786 case Y: 3787 return getSizeY(); 3788 case C: 3789 return getSizeC(); 3790 case Z: 3791 return getSizeZ(); 3792 case T: 3793 return getSizeT(); 3794 default: 3795 case NULL: 3796 return 0; 3797 } 3798 } 3799 3800 /** 3801 * Returns 2D dimension of sequence {sizeX, sizeY} 3802 */ 3803 public Dimension getDimension2D() 3804 { 3805 return new Dimension(getSizeX(), getSizeY()); 3806 } 3807 3808 /** 3809 * Returns 5D dimension of sequence {sizeX, sizeY, sizeZ, sizeT, sizeC} 3810 */ 3811 public Dimension5D.Integer getDimension5D() 3812 { 3813 return new Dimension5D.Integer(getSizeX(), getSizeY(), getSizeZ(), getSizeT(), getSizeC()); 3814 } 3815 3816 /** 3817 * @deprecated Use {@link #getDimension2D()} instead. 3818 */ 3819 @Deprecated 3820 public Dimension getDimension() 3821 { 3822 return getDimension2D(); 3823 } 3824 3825 /** 3826 * Returns 2D bounds of sequence {0, 0, sizeX, sizeY} 3827 * 3828 * @see #getDimension2D() 3829 */ 3830 public Rectangle getBounds2D() 3831 { 3832 return new Rectangle(getSizeX(), getSizeY()); 3833 } 3834 3835 /** 3836 * Returns 5D bounds of sequence {0, 0, 0, 0, 0, sizeX, sizeY, sizeZ, sizeT, sizeC} 3837 * 3838 * @see #getDimension5D() 3839 */ 3840 public Rectangle5D.Integer getBounds5D() 3841 { 3842 return new Rectangle5D.Integer(0, 0, 0, 0, 0, getSizeX(), getSizeY(), getSizeZ(), getSizeT(), getSizeC()); 3843 } 3844 3845 /** 3846 * @deprecated Use {@link #getBounds2D()} instead 3847 */ 3848 @Deprecated 3849 public Rectangle getBounds() 3850 { 3851 return getBounds2D(); 3852 } 3853 3854 /** 3855 * Returns the number of sample.<br> 3856 * This is equivalent to<br> 3857 * <code>getSizeX() * getSizeY() * getSizeC() * getSizeZ() * getSizeT()</code> 3858 */ 3859 public int getNumSample() 3860 { 3861 return getSizeX() * getSizeY() * getSizeC() * getSizeZ() * getSizeT(); 3862 } 3863 3864 /** 3865 * Test if the specified image is compatible with current loaded images in sequence 3866 */ 3867 public boolean isCompatible(IcyBufferedImage image) 3868 { 3869 if ((colorModel == null) || isEmpty()) 3870 return true; 3871 3872 return (image.getWidth() == getWidth()) && (image.getHeight() == getHeight()) 3873 && isCompatible(image.getIcyColorModel()); 3874 } 3875 3876 /** 3877 * Test if the specified colorModel is compatible with sequence colorModel 3878 */ 3879 public boolean isCompatible(IcyColorModel cm) 3880 { 3881 // test that colorModel are compatible 3882 if (colorModel == null) 3883 return true; 3884 3885 return colorModel.isCompatible(cm); 3886 } 3887 3888 /** 3889 * Returns true if specified LUT is compatible with sequence LUT 3890 */ 3891 public boolean isLutCompatible(LUT lut) 3892 { 3893 IcyColorModel cm = colorModel; 3894 // not yet defined ? use default one 3895 if (cm == null) 3896 cm = IcyColorModel.createInstance(); 3897 3898 return lut.isCompatible(cm); 3899 } 3900 3901 /** 3902 * Returns the colorModel 3903 */ 3904 public IcyColorModel getColorModel() 3905 { 3906 return colorModel; 3907 } 3908 3909 /** 3910 * Same as {@link #createCompatibleLUT()} 3911 */ 3912 public LUT getDefaultLUT() 3913 { 3914 // color model not anymore compatible with user LUT --> reset it 3915 if ((defaultLut == null) || ((colorModel != null) && !defaultLut.isCompatible(colorModel))) 3916 defaultLut = createCompatibleLUT(); 3917 3918 return defaultLut; 3919 } 3920 3921 /** 3922 * Returns <code>true</code> if a user LUT has be defined for this sequence. 3923 */ 3924 public boolean hasUserLUT() 3925 { 3926 return (userLut != null); 3927 } 3928 3929 /** 3930 * Returns the users LUT.<br> 3931 * If user LUT is not defined then a new default LUT is returned. 3932 * 3933 * @see #getDefaultLUT() 3934 */ 3935 public LUT getUserLUT() 3936 { 3937 // color model not anymore compatible with user LUT --> reset it 3938 if ((userLut == null) || ((colorModel != null) && !userLut.isCompatible(colorModel))) 3939 userLut = getDefaultLUT(); 3940 3941 return userLut; 3942 } 3943 3944 /** 3945 * Sets the user LUT (saved in XML persistent metadata). 3946 */ 3947 public void setUserLUT(LUT lut) 3948 { 3949 if ((colorModel == null) || lut.isCompatible(colorModel)) 3950 userLut = lut; 3951 } 3952 3953 /** 3954 * Creates and returns the default LUT for this sequence.<br> 3955 * If the sequence is empty it returns a default ARGB LUT. 3956 */ 3957 public LUT createCompatibleLUT() 3958 { 3959 final IcyColorModel result; 3960 3961 // not yet defined ? use default one 3962 if (colorModel == null) 3963 result = IcyColorModel.createInstance(); 3964 else 3965 result = IcyColorModel.createInstance(colorModel, true, true); 3966 3967 return new LUT(result); 3968 } 3969 3970 /** 3971 * Get the default colormap for the specified channel 3972 * 3973 * @param channel 3974 * channel we want to set the colormap 3975 * @see #getColorMap(int) 3976 */ 3977 public IcyColorMap getDefaultColorMap(int channel) 3978 { 3979 if (colorModel != null) 3980 return colorModel.getColorMap(channel); 3981 3982 return getDefaultLUT().getLutChannel(channel).getColorMap(); 3983 } 3984 3985 /** 3986 * Set the default colormap for the specified channel 3987 * 3988 * @param channel 3989 * channel we want to set the colormap 3990 * @param map 3991 * source colormap to copy 3992 * @param setAlpha 3993 * also copy the alpha information 3994 * @see #getDefaultColorMap(int) 3995 */ 3996 public void setDefaultColormap(int channel, IcyColorMap map, boolean setAlpha) 3997 { 3998 if (colorModel != null) 3999 colorModel.setColorMap(channel, map, setAlpha); 4000 } 4001 4002 /** 4003 * Set the default colormap for the specified channel 4004 * 4005 * @param channel 4006 * channel we want to set the colormap 4007 * @param map 4008 * source colormap to copy 4009 * @see #getDefaultColorMap(int) 4010 */ 4011 public void setDefaultColormap(int channel, IcyColorMap map) 4012 { 4013 setDefaultColormap(channel, map, map.isAlpha()); 4014 } 4015 4016 /** 4017 * Get the user colormap for the specified channel.<br> 4018 * User colormap is saved in the XML persistent data and reloaded when opening the Sequence. 4019 * 4020 * @param channel 4021 * channel we want to set the colormap 4022 * @see #getDefaultColorMap(int) 4023 */ 4024 public IcyColorMap getColorMap(int channel) 4025 { 4026 final LUT lut = getUserLUT(); 4027 4028 if (channel < lut.getNumChannel()) 4029 return lut.getLutChannel(channel).getColorMap(); 4030 4031 return null; 4032 } 4033 4034 /** 4035 * Set the user colormap for the specified channel.<br> 4036 * User colormap is saved in the XML persistent data and reloaded when opening the Sequence. 4037 * 4038 * @param channel 4039 * channel we want to set the colormap 4040 * @param map 4041 * source colormap to copy 4042 * @param setAlpha 4043 * also copy the alpha information 4044 * @see #getColorMap(int) 4045 */ 4046 public void setColormap(int channel, IcyColorMap map, boolean setAlpha) 4047 { 4048 final LUT lut = getUserLUT(); 4049 4050 if (channel < lut.getNumChannel()) 4051 lut.getLutChannel(channel).setColorMap(map, setAlpha); 4052 } 4053 4054 /** 4055 * Set the user colormap for the specified channel.<br> 4056 * User colormap is saved in the XML persistent data and reloaded when opening the Sequence. 4057 * 4058 * @param channel 4059 * channel we want to set the colormap 4060 * @param map 4061 * source colormap to copy 4062 * @see #getColorMap(int) 4063 */ 4064 public void setColormap(int channel, IcyColorMap map) 4065 { 4066 setColormap(channel, map, map.isAlpha()); 4067 } 4068 4069 /** 4070 * Returns the data type of sequence 4071 */ 4072 public DataType getDataType_() 4073 { 4074 // assume unsigned byte by default 4075 if (colorModel == null) 4076 // preserve UNDEFINED here for backward compatibility (Math Operation for instance) 4077 return DataType.UNDEFINED; 4078 4079 return colorModel.getDataType_(); 4080 } 4081 4082 /** 4083 * Returns the data type of sequence 4084 * 4085 * @deprecated use {@link #getDataType_()} instead 4086 */ 4087 @Deprecated 4088 public int getDataType() 4089 { 4090 if (colorModel == null) 4091 return TypeUtil.TYPE_UNDEFINED; 4092 4093 return colorModel.getDataType(); 4094 } 4095 4096 /** 4097 * Returns true if this is a float data type sequence 4098 */ 4099 public boolean isFloatDataType() 4100 { 4101 return getDataType_().isFloat(); 4102 } 4103 4104 /** 4105 * Returns true if this is a signed data type sequence 4106 */ 4107 public boolean isSignedDataType() 4108 { 4109 return getDataType_().isSigned(); 4110 } 4111 4112 /** 4113 * Internal use only. 4114 */ 4115 private static double[][] adjustBounds(double[][] curBounds, double[][] bounds) 4116 { 4117 if (bounds == null) 4118 return curBounds; 4119 4120 for (int comp = 0; comp < bounds.length; comp++) 4121 { 4122 final double[] compBounds = bounds[comp]; 4123 final double[] curCompBounds = curBounds[comp]; 4124 4125 if (curCompBounds[0] < compBounds[0]) 4126 compBounds[0] = curCompBounds[0]; 4127 if (curCompBounds[1] > compBounds[1]) 4128 compBounds[1] = curCompBounds[1]; 4129 } 4130 4131 return bounds; 4132 } 4133 4134 /** 4135 * Recalculate all image channels bounds (min and max values).<br> 4136 * Internal use only. 4137 */ 4138 protected void recalculateAllImageChannelsBounds() 4139 { 4140 // nothing to do... 4141 if ((colorModel == null) || isEmpty()) 4142 return; 4143 4144 final List<VolumetricImage> volumes = getAllVolumetricImage(); 4145 4146 beginUpdate(); 4147 try 4148 { 4149 // recalculate images bounds (automatically update sequence bounds with event) 4150 for (VolumetricImage volImg : volumes) 4151 for (IcyBufferedImage img : volImg.getAllImage()) 4152 img.updateChannelsBounds(); 4153 } 4154 finally 4155 { 4156 endUpdate(); 4157 } 4158 } 4159 4160 /** 4161 * Update channels bounds (min and max values)<br> 4162 * At this point we assume images has correct channels bounds information.<br> 4163 * Internal use only. 4164 */ 4165 protected void internalUpdateChannelsBounds() 4166 { 4167 // nothing to do... 4168 if ((colorModel == null) || isEmpty()) 4169 return; 4170 4171 double[][] bounds; 4172 4173 bounds = null; 4174 // recalculate bounds from all images 4175 synchronized (volumetricImages) 4176 { 4177 for (VolumetricImage volImg : volumetricImages.values()) 4178 { 4179 for (IcyBufferedImage img : volImg.getAllImage()) 4180 { 4181 if (img != null) 4182 bounds = adjustBounds(img.getChannelsTypeBounds(), bounds); 4183 } 4184 } 4185 } 4186 4187 // set new computed bounds 4188 colorModel.setComponentsAbsBounds(bounds); 4189 4190 bounds = null; 4191 // recalculate user bounds from all images 4192 synchronized (volumetricImages) 4193 { 4194 for (VolumetricImage volImg : volumetricImages.values()) 4195 { 4196 for (IcyBufferedImage img : volImg.getAllImage()) 4197 { 4198 if (img != null) 4199 bounds = adjustBounds(img.getChannelsBounds(), bounds); 4200 } 4201 } 4202 } 4203 4204 // set new computed bounds 4205 colorModel.setComponentsUserBounds(bounds); 4206 } 4207 4208 /** 4209 * Update channels bounds (min and max values).<br> 4210 * 4211 * @param forceRecalculation 4212 * If true we force all images channels bounds recalculation (this can take sometime). <br> 4213 * You can left this flag to false if sequence images have their bounds updated (which 4214 * should be the case by default). 4215 */ 4216 public void updateChannelsBounds(boolean forceRecalculation) 4217 { 4218 // force calculation of all images bounds 4219 if (forceRecalculation) 4220 recalculateAllImageChannelsBounds(); 4221 // then update sequence bounds 4222 internalUpdateChannelsBounds(); 4223 } 4224 4225 /** 4226 * Update channels bounds (min and max values).<br> 4227 * All images channels bounds are recalculated (this can take sometime). 4228 */ 4229 public void updateChannelsBounds() 4230 { 4231 // force recalculation 4232 updateChannelsBounds(true); 4233 } 4234 4235 /** 4236 * @deprecated Use {@link #updateChannelsBounds(boolean)} instead. 4237 */ 4238 @Deprecated 4239 public void updateComponentsBounds(boolean forceRecalculation, boolean adjustByteToo) 4240 { 4241 updateChannelsBounds(forceRecalculation); 4242 } 4243 4244 /** 4245 * @deprecated Use {@link #updateChannelsBounds(boolean)} instead. 4246 */ 4247 @Deprecated 4248 public void updateComponentsBounds(boolean forceRecalculation) 4249 { 4250 updateChannelsBounds(forceRecalculation); 4251 } 4252 4253 /** 4254 * @deprecated Use {@link #updateChannelsBounds(boolean)} instead. 4255 */ 4256 @Deprecated 4257 public void updateComponentsBounds() 4258 { 4259 // force recalculation 4260 updateChannelsBounds(true); 4261 } 4262 4263 /** 4264 * Get the data type minimum value. 4265 */ 4266 public double getDataTypeMin() 4267 { 4268 return getDataType_().getMinValue(); 4269 } 4270 4271 /** 4272 * Get the data type maximum value. 4273 */ 4274 public double getDataTypeMax() 4275 { 4276 return getDataType_().getMaxValue(); 4277 } 4278 4279 /** 4280 * Get data type bounds (min and max values). 4281 */ 4282 public double[] getDataTypeBounds() 4283 { 4284 return new double[] {getDataTypeMin(), getDataTypeMax()}; 4285 } 4286 4287 /** 4288 * Get the preferred data type minimum value in the whole sequence for the specified channel. 4289 */ 4290 public double getChannelTypeMin(int channel) 4291 { 4292 if (colorModel == null) 4293 return 0d; 4294 4295 return colorModel.getComponentAbsMinValue(channel); 4296 } 4297 4298 /** 4299 * Get the preferred data type maximum value in the whole sequence for the specified channel. 4300 */ 4301 public double getChannelTypeMax(int channel) 4302 { 4303 if (colorModel == null) 4304 return 0d; 4305 4306 return colorModel.getComponentAbsMaxValue(channel); 4307 } 4308 4309 /** 4310 * Get the preferred data type bounds (min and max values) in the whole sequence for the 4311 * specified channel. 4312 */ 4313 public double[] getChannelTypeBounds(int channel) 4314 { 4315 if (colorModel == null) 4316 return new double[] {0d, 0d}; 4317 4318 return colorModel.getComponentAbsBounds(channel); 4319 } 4320 4321 /** 4322 * Get the preferred data type bounds (min and max values) in the whole sequence for all 4323 * channels. 4324 */ 4325 public double[][] getChannelsTypeBounds() 4326 { 4327 final int sizeC = getSizeC(); 4328 final double[][] result = new double[sizeC][]; 4329 4330 for (int c = 0; c < sizeC; c++) 4331 result[c] = getChannelTypeBounds(c); 4332 4333 return result; 4334 } 4335 4336 /** 4337 * Get the global preferred data type bounds (min and max values) for all channels. 4338 */ 4339 public double[] getChannelsGlobalTypeBounds() 4340 { 4341 final int sizeC = getSizeC(); 4342 final double[] result = getChannelTypeBounds(0); 4343 4344 for (int c = 1; c < sizeC; c++) 4345 { 4346 final double[] bounds = getChannelTypeBounds(c); 4347 result[0] = Math.min(bounds[0], result[0]); 4348 result[1] = Math.max(bounds[1], result[1]); 4349 } 4350 4351 return result; 4352 } 4353 4354 /** 4355 * @deprecated Use {@link #getChannelsGlobalTypeBounds()} instead 4356 */ 4357 @Deprecated 4358 public double[] getChannelTypeGlobalBounds() 4359 { 4360 return getChannelsGlobalTypeBounds(); 4361 } 4362 4363 /** 4364 * @deprecated Use {@link #getChannelTypeGlobalBounds()} instead. 4365 */ 4366 @Deprecated 4367 public double[] getGlobalChannelTypeBounds() 4368 { 4369 return getChannelTypeGlobalBounds(); 4370 } 4371 4372 /** 4373 * @deprecated Use {@link #getChannelTypeMin(int)} instead. 4374 */ 4375 @Deprecated 4376 public double getComponentAbsMinValue(int component) 4377 { 4378 return getChannelTypeMin(component); 4379 } 4380 4381 /** 4382 * @deprecated Use {@link #getChannelTypeMax(int)} instead. 4383 */ 4384 @Deprecated 4385 public double getComponentAbsMaxValue(int component) 4386 { 4387 return getChannelTypeMax(component); 4388 } 4389 4390 /** 4391 * @deprecated Use {@link #getChannelTypeBounds(int)} instead. 4392 */ 4393 @Deprecated 4394 public double[] getComponentAbsBounds(int component) 4395 { 4396 return getChannelTypeBounds(component); 4397 } 4398 4399 /** 4400 * @deprecated Use {@link #getChannelsTypeBounds()} instead. 4401 */ 4402 @Deprecated 4403 public double[][] getComponentsAbsBounds() 4404 { 4405 return getChannelsTypeBounds(); 4406 } 4407 4408 /** 4409 * @deprecated Use {@link #getChannelsGlobalTypeBounds()} instead. 4410 */ 4411 @Deprecated 4412 public double[] getGlobalComponentAbsBounds() 4413 { 4414 return getChannelsGlobalTypeBounds(); 4415 } 4416 4417 /** 4418 * Get the minimum value in the whole sequence for the specified channel. 4419 */ 4420 public double getChannelMin(int channel) 4421 { 4422 if (colorModel == null) 4423 return 0d; 4424 4425 return colorModel.getComponentUserMinValue(channel); 4426 } 4427 4428 /** 4429 * Get maximum value in the whole sequence for the specified channel. 4430 */ 4431 public double getChannelMax(int channel) 4432 { 4433 if (colorModel == null) 4434 return 0d; 4435 4436 return colorModel.getComponentUserMaxValue(channel); 4437 } 4438 4439 /** 4440 * Get bounds (min and max values) in the whole sequence for the specified channel. 4441 */ 4442 public double[] getChannelBounds(int channel) 4443 { 4444 if (colorModel == null) 4445 return new double[] {0d, 0d}; 4446 4447 // lazy channel bounds update 4448 if (channelBoundsInvalid) 4449 { 4450 channelBoundsInvalid = false; 4451 // images channels bounds are valid at this point 4452 internalUpdateChannelsBounds(); 4453 } 4454 4455 return colorModel.getComponentUserBounds(channel); 4456 } 4457 4458 /** 4459 * Get bounds (min and max values) in the whole sequence for all channels. 4460 */ 4461 public double[][] getChannelsBounds() 4462 { 4463 final int sizeC = getSizeC(); 4464 final double[][] result = new double[sizeC][]; 4465 4466 for (int c = 0; c < sizeC; c++) 4467 result[c] = getChannelBounds(c); 4468 4469 return result; 4470 } 4471 4472 /** 4473 * Get global bounds (min and max values) in the whole sequence for all channels. 4474 */ 4475 public double[] getChannelsGlobalBounds() 4476 { 4477 final int sizeC = getSizeC(); 4478 final double[] result = new double[2]; 4479 4480 result[0] = Double.MAX_VALUE; 4481 result[1] = -Double.MAX_VALUE; 4482 4483 for (int c = 0; c < sizeC; c++) 4484 { 4485 final double[] bounds = getChannelBounds(c); 4486 4487 if (bounds[0] < result[0]) 4488 result[0] = bounds[0]; 4489 if (bounds[1] > result[1]) 4490 result[1] = bounds[1]; 4491 } 4492 4493 return result; 4494 } 4495 4496 /** 4497 * @deprecated Use {@link #getChannelMin(int)} instead. 4498 */ 4499 @Deprecated 4500 public double getComponentUserMinValue(int component) 4501 { 4502 return getChannelMin(component); 4503 } 4504 4505 /** 4506 * @deprecated Use {@link #getChannelMax(int)} instead. 4507 */ 4508 @Deprecated 4509 public double getComponentUserMaxValue(int component) 4510 { 4511 return getChannelMax(component); 4512 } 4513 4514 /** 4515 * @deprecated Use {@link #getChannelBounds(int)} instead. 4516 */ 4517 @Deprecated 4518 public double[] getComponentUserBounds(int component) 4519 { 4520 return getChannelBounds(component); 4521 } 4522 4523 /** 4524 * @deprecated Use {@link #getChannelsBounds()} instead. 4525 */ 4526 @Deprecated 4527 public double[][] getComponentsUserBounds() 4528 { 4529 return getChannelsBounds(); 4530 } 4531 4532 /** 4533 * Force all image data to be loaded (so channels bounds can be correctly computed).<br> 4534 * Be careful, this function can take sometime. 4535 */ 4536 public void loadAllData() 4537 { 4538 for (IcyBufferedImage image : getAllImage()) 4539 if (image != null) 4540 image.loadData(); 4541 } 4542 4543 /** 4544 * Returns the data value located at position (t, z, c, y, x) as double.<br> 4545 * It returns 0d if value is not found. 4546 */ 4547 public double getData(int t, int z, int c, int y, int x) 4548 { 4549 final IcyBufferedImage img = getImage(t, z); 4550 4551 if (img != null) 4552 return img.getData(x, y, c); 4553 4554 return 0d; 4555 } 4556 4557 /** 4558 * Returns the data value located at position (t, z, c, y, x) as double.<br> 4559 * The value is interpolated depending the current double (x,y,z) coordinates.<br> 4560 * It returns 0d if value is out of range. 4561 */ 4562 public double getDataInterpolated(int t, double z, int c, double y, double x) 4563 { 4564 final int zi = (int) z; 4565 final double ratioNextZ = z - (double) zi; 4566 4567 double result = 0d; 4568 IcyBufferedImage img; 4569 4570 img = getImage(t, zi); 4571 if (img != null) 4572 { 4573 final double ratioCurZ = 1d - ratioNextZ; 4574 if (ratioCurZ > 0d) 4575 result += img.getDataInterpolated(x, y, c) * ratioCurZ; 4576 } 4577 img = getImage(t, zi + 1); 4578 if (img != null) 4579 { 4580 if (ratioNextZ > 0d) 4581 result += img.getDataInterpolated(x, y, c) * ratioNextZ; 4582 } 4583 4584 return result; 4585 } 4586 4587 /** 4588 * Returns a direct reference to 4D array data [T][Z][C][XY] 4589 */ 4590 public Object getDataXYCZT() 4591 { 4592 switch (getDataType_().getJavaType()) 4593 { 4594 case BYTE: 4595 return getDataXYCZTAsByte(); 4596 case SHORT: 4597 return getDataXYCZTAsShort(); 4598 case INT: 4599 return getDataXYCZTAsInt(); 4600 case FLOAT: 4601 return getDataXYCZTAsFloat(); 4602 case DOUBLE: 4603 return getDataXYCZTAsDouble(); 4604 default: 4605 return null; 4606 } 4607 } 4608 4609 /** 4610 * Returns a direct reference to 3D array data [Z][C][XY] for specified t 4611 */ 4612 public Object getDataXYCZ(int t) 4613 { 4614 switch (getDataType_().getJavaType()) 4615 { 4616 case BYTE: 4617 return getDataXYCZAsByte(t); 4618 case SHORT: 4619 return getDataXYCZAsShort(t); 4620 case INT: 4621 return getDataXYCZAsInt(t); 4622 case FLOAT: 4623 return getDataXYCZAsFloat(t); 4624 case DOUBLE: 4625 return getDataXYCZAsDouble(t); 4626 default: 4627 return null; 4628 } 4629 } 4630 4631 /** 4632 * Returns a direct reference to 2D array data [C][XY] for specified t, z 4633 */ 4634 public Object getDataXYC(int t, int z) 4635 { 4636 final IcyBufferedImage img = getImage(t, z); 4637 4638 if (img != null) 4639 return img.getDataXYC(); 4640 4641 return null; 4642 } 4643 4644 /** 4645 * Returns a direct reference to 1D array data [XY] for specified t, z, c 4646 */ 4647 public Object getDataXY(int t, int z, int c) 4648 { 4649 final IcyBufferedImage img = getImage(t, z); 4650 4651 if (img != null) 4652 return img.getDataXY(c); 4653 4654 return null; 4655 } 4656 4657 /** 4658 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 4659 */ 4660 public Object getDataXYZT(int c) 4661 { 4662 switch (getDataType_().getJavaType()) 4663 { 4664 case BYTE: 4665 return getDataXYZTAsByte(c); 4666 case SHORT: 4667 return getDataXYZTAsShort(c); 4668 case INT: 4669 return getDataXYZTAsInt(c); 4670 case FLOAT: 4671 return getDataXYZTAsFloat(c); 4672 case DOUBLE: 4673 return getDataXYZTAsDouble(c); 4674 default: 4675 return null; 4676 } 4677 } 4678 4679 /** 4680 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 4681 */ 4682 public Object getDataXYZ(int t, int c) 4683 { 4684 switch (getDataType_().getJavaType()) 4685 { 4686 case BYTE: 4687 return getDataXYZAsByte(t, c); 4688 case SHORT: 4689 return getDataXYZAsShort(t, c); 4690 case INT: 4691 return getDataXYZAsInt(t, c); 4692 case FLOAT: 4693 return getDataXYZAsFloat(t, c); 4694 case DOUBLE: 4695 return getDataXYZAsDouble(t, c); 4696 default: 4697 return null; 4698 } 4699 } 4700 4701 /** 4702 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 4703 */ 4704 public Object getDataCopyXYCZT() 4705 { 4706 return getDataCopyXYCZT(null, 0); 4707 } 4708 4709 /** 4710 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 4711 * If (out != null) then it's used to store result at the specified offset 4712 */ 4713 public Object getDataCopyXYCZT(Object out, int off) 4714 { 4715 switch (getDataType_().getJavaType()) 4716 { 4717 case BYTE: 4718 return getDataCopyXYCZTAsByte((byte[]) out, off); 4719 case SHORT: 4720 return getDataCopyXYCZTAsShort((short[]) out, off); 4721 case INT: 4722 return getDataCopyXYCZTAsInt((int[]) out, off); 4723 case FLOAT: 4724 return getDataCopyXYCZTAsFloat((float[]) out, off); 4725 case DOUBLE: 4726 return getDataCopyXYCZTAsDouble((double[]) out, off); 4727 default: 4728 return null; 4729 } 4730 } 4731 4732 /** 4733 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 4734 */ 4735 public Object getDataCopyXYCZ(int t) 4736 { 4737 return getDataCopyXYCZ(t, null, 0); 4738 } 4739 4740 /** 4741 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 4742 * If (out != null) then it's used to store result at the specified offset 4743 */ 4744 public Object getDataCopyXYCZ(int t, Object out, int off) 4745 { 4746 switch (getDataType_().getJavaType()) 4747 { 4748 case BYTE: 4749 return getDataCopyXYCZAsByte(t, (byte[]) out, off); 4750 case SHORT: 4751 return getDataCopyXYCZAsShort(t, (short[]) out, off); 4752 case INT: 4753 return getDataCopyXYCZAsInt(t, (int[]) out, off); 4754 case FLOAT: 4755 return getDataCopyXYCZAsFloat(t, (float[]) out, off); 4756 case DOUBLE: 4757 return getDataCopyXYCZAsDouble(t, (double[]) out, off); 4758 default: 4759 return null; 4760 } 4761 } 4762 4763 /** 4764 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 4765 */ 4766 public Object getDataCopyXYC(int t, int z) 4767 { 4768 return getDataCopyXYC(t, z, null, 0); 4769 } 4770 4771 /** 4772 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 4773 * If (out != null) then it's used to store result at the specified offset 4774 */ 4775 public Object getDataCopyXYC(int t, int z, Object out, int off) 4776 { 4777 final IcyBufferedImage img = getImage(t, z); 4778 4779 if (img != null) 4780 return img.getDataCopyXYC(out, off); 4781 4782 return out; 4783 } 4784 4785 /** 4786 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 4787 */ 4788 public Object getDataCopyXY(int t, int z, int c) 4789 { 4790 return getDataCopyXY(t, z, c, null, 0); 4791 } 4792 4793 /** 4794 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 4795 * If (out != null) then it's used to store result at the specified offset 4796 */ 4797 public Object getDataCopyXY(int t, int z, int c, Object out, int off) 4798 { 4799 final IcyBufferedImage img = getImage(t, z); 4800 4801 if (img != null) 4802 return img.getDataCopyXY(c, out, off); 4803 4804 return out; 4805 } 4806 4807 /** 4808 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 4809 */ 4810 public Object getDataCopyCXYZT() 4811 { 4812 return getDataCopyCXYZT(null, 0); 4813 } 4814 4815 /** 4816 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 4817 * If (out != null) then it's used to store result at the specified offset 4818 */ 4819 public Object getDataCopyCXYZT(Object out, int off) 4820 { 4821 switch (getDataType_().getJavaType()) 4822 { 4823 case BYTE: 4824 return getDataCopyCXYZTAsByte((byte[]) out, off); 4825 case SHORT: 4826 return getDataCopyCXYZTAsShort((short[]) out, off); 4827 case INT: 4828 return getDataCopyCXYZTAsInt((int[]) out, off); 4829 case FLOAT: 4830 return getDataCopyCXYZTAsFloat((float[]) out, off); 4831 case DOUBLE: 4832 return getDataCopyCXYZTAsDouble((double[]) out, off); 4833 default: 4834 return null; 4835 } 4836 } 4837 4838 /** 4839 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 4840 */ 4841 public Object getDataCopyCXYZ(int t) 4842 { 4843 return getDataCopyCXYZ(t, null, 0); 4844 } 4845 4846 /** 4847 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 4848 * If (out != null) then it's used to store result at the specified offset 4849 */ 4850 public Object getDataCopyCXYZ(int t, Object out, int off) 4851 { 4852 switch (getDataType_().getJavaType()) 4853 { 4854 case BYTE: 4855 return getDataCopyCXYZAsByte(t, (byte[]) out, off); 4856 case SHORT: 4857 return getDataCopyCXYZAsShort(t, (short[]) out, off); 4858 case INT: 4859 return getDataCopyCXYZAsInt(t, (int[]) out, off); 4860 case FLOAT: 4861 return getDataCopyCXYZAsFloat(t, (float[]) out, off); 4862 case DOUBLE: 4863 return getDataCopyCXYZAsDouble(t, (double[]) out, off); 4864 default: 4865 return null; 4866 } 4867 } 4868 4869 /** 4870 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 4871 */ 4872 public Object getDataCopyCXY(int t, int z) 4873 { 4874 return getDataCopyCXY(t, z, null, 0); 4875 } 4876 4877 /** 4878 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 4879 * If (out != null) then it's used to store result at the specified offset 4880 */ 4881 public Object getDataCopyCXY(int t, int z, Object out, int off) 4882 { 4883 final IcyBufferedImage img = getImage(t, z); 4884 4885 if (img != null) 4886 return img.getDataCopyCXY(out, off); 4887 4888 return out; 4889 } 4890 4891 /** 4892 * Returns a 1D array data copy [C] of specified t, z, x, y 4893 */ 4894 public Object getDataCopyC(int t, int z, int x, int y) 4895 { 4896 return getDataCopyC(t, z, x, y, null, 0); 4897 } 4898 4899 /** 4900 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 4901 * If (out != null) then it's used to store result at the specified offset 4902 */ 4903 public Object getDataCopyC(int t, int z, int x, int y, Object out, int off) 4904 { 4905 final IcyBufferedImage img = getImage(t, z); 4906 4907 if (img != null) 4908 return img.getDataCopyC(x, y, out, off); 4909 4910 return out; 4911 } 4912 4913 /** 4914 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 4915 */ 4916 public Object getDataCopyXYZT(int c) 4917 { 4918 return getDataCopyXYZT(c, null, 0); 4919 } 4920 4921 /** 4922 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 4923 * If (out != null) then it's used to store result at the specified offset 4924 */ 4925 public Object getDataCopyXYZT(int c, Object out, int off) 4926 { 4927 switch (getDataType_().getJavaType()) 4928 { 4929 case BYTE: 4930 return getDataCopyXYZTAsByte(c, (byte[]) out, off); 4931 case SHORT: 4932 return getDataCopyXYZTAsShort(c, (short[]) out, off); 4933 case INT: 4934 return getDataCopyXYZTAsInt(c, (int[]) out, off); 4935 case FLOAT: 4936 return getDataCopyXYZTAsFloat(c, (float[]) out, off); 4937 case DOUBLE: 4938 return getDataCopyXYZTAsDouble(c, (double[]) out, off); 4939 default: 4940 return null; 4941 } 4942 } 4943 4944 /** 4945 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 4946 */ 4947 public Object getDataCopyXYZ(int t, int c) 4948 { 4949 return getDataCopyXYZ(t, c, null, 0); 4950 } 4951 4952 /** 4953 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 4954 * If (out != null) then it's used to store result at the specified offset 4955 */ 4956 public Object getDataCopyXYZ(int t, int c, Object out, int off) 4957 { 4958 switch (getDataType_().getJavaType()) 4959 { 4960 case BYTE: 4961 return getDataCopyXYZAsByte(t, c, (byte[]) out, off); 4962 case SHORT: 4963 return getDataCopyXYZAsShort(t, c, (short[]) out, off); 4964 case INT: 4965 return getDataCopyXYZAsInt(t, c, (int[]) out, off); 4966 case FLOAT: 4967 return getDataCopyXYZAsFloat(t, c, (float[]) out, off); 4968 case DOUBLE: 4969 return getDataCopyXYZAsDouble(t, c, (double[]) out, off); 4970 default: 4971 return null; 4972 } 4973 } 4974 4975 /** 4976 * Returns a direct reference to 4D byte array data [T][Z][C][XY] 4977 */ 4978 public byte[][][][] getDataXYCZTAsByte() 4979 { 4980 final int sizeT = getSizeT(); 4981 final byte[][][][] result = new byte[sizeT][][][]; 4982 4983 for (int t = 0; t < sizeT; t++) 4984 result[t] = getDataXYCZAsByte(t); 4985 4986 return result; 4987 4988 } 4989 4990 /** 4991 * Returns a direct reference to 4D byte array data [T][Z][C][XY] 4992 */ 4993 public short[][][][] getDataXYCZTAsShort() 4994 { 4995 final int sizeT = getSizeT(); 4996 final short[][][][] result = new short[sizeT][][][]; 4997 4998 for (int t = 0; t < sizeT; t++) 4999 result[t] = getDataXYCZAsShort(t); 5000 5001 return result; 5002 } 5003 5004 /** 5005 * Returns a direct reference to 4D byte array data [T][Z][C][XY] 5006 */ 5007 public int[][][][] getDataXYCZTAsInt() 5008 { 5009 final int sizeT = getSizeT(); 5010 final int[][][][] result = new int[sizeT][][][]; 5011 5012 for (int t = 0; t < sizeT; t++) 5013 result[t] = getDataXYCZAsInt(t); 5014 5015 return result; 5016 } 5017 5018 /** 5019 * Returns a direct reference to 4D byte array data [T][Z][C][XY] 5020 */ 5021 public float[][][][] getDataXYCZTAsFloat() 5022 { 5023 final int sizeT = getSizeT(); 5024 final float[][][][] result = new float[sizeT][][][]; 5025 5026 for (int t = 0; t < sizeT; t++) 5027 result[t] = getDataXYCZAsFloat(t); 5028 5029 return result; 5030 } 5031 5032 /** 5033 * Returns a direct reference to 4D byte array data [T][Z][C][XY] 5034 */ 5035 public double[][][][] getDataXYCZTAsDouble() 5036 { 5037 final int sizeT = getSizeT(); 5038 final double[][][][] result = new double[sizeT][][][]; 5039 5040 for (int t = 0; t < sizeT; t++) 5041 result[t] = getDataXYCZAsDouble(t); 5042 5043 return result; 5044 } 5045 5046 /** 5047 * Returns a direct reference to 3D byte array data [Z][C][XY] for specified t 5048 */ 5049 public byte[][][] getDataXYCZAsByte(int t) 5050 { 5051 final int sizeZ = getSizeZ(t); 5052 final byte[][][] result = new byte[sizeZ][][]; 5053 5054 for (int z = 0; z < sizeZ; z++) 5055 result[z] = getDataXYCAsByte(t, z); 5056 5057 return result; 5058 } 5059 5060 /** 5061 * Returns a direct reference to 3D byte array data [Z][C][XY] for specified t 5062 */ 5063 public short[][][] getDataXYCZAsShort(int t) 5064 { 5065 final int sizeZ = getSizeZ(t); 5066 final short[][][] result = new short[sizeZ][][]; 5067 5068 for (int z = 0; z < sizeZ; z++) 5069 result[z] = getDataXYCAsShort(t, z); 5070 5071 return result; 5072 } 5073 5074 /** 5075 * Returns a direct reference to 3D byte array data [Z][C][XY] for specified t 5076 */ 5077 public int[][][] getDataXYCZAsInt(int t) 5078 { 5079 final int sizeZ = getSizeZ(t); 5080 final int[][][] result = new int[sizeZ][][]; 5081 5082 for (int z = 0; z < sizeZ; z++) 5083 result[z] = getDataXYCAsInt(t, z); 5084 5085 return result; 5086 } 5087 5088 /** 5089 * Returns a direct reference to 3D byte array data [Z][C][XY] for specified t 5090 */ 5091 public float[][][] getDataXYCZAsFloat(int t) 5092 { 5093 final int sizeZ = getSizeZ(t); 5094 final float[][][] result = new float[sizeZ][][]; 5095 5096 for (int z = 0; z < sizeZ; z++) 5097 result[z] = getDataXYCAsFloat(t, z); 5098 5099 return result; 5100 } 5101 5102 /** 5103 * Returns a direct reference to 3D byte array data [Z][C][XY] for specified t 5104 */ 5105 public double[][][] getDataXYCZAsDouble(int t) 5106 { 5107 final int sizeZ = getSizeZ(t); 5108 final double[][][] result = new double[sizeZ][][]; 5109 5110 for (int z = 0; z < sizeZ; z++) 5111 result[z] = getDataXYCAsDouble(t, z); 5112 5113 return result; 5114 } 5115 5116 /** 5117 * Returns a direct reference to 2D byte array data [C][XY] for specified t, z 5118 */ 5119 public byte[][] getDataXYCAsByte(int t, int z) 5120 { 5121 final IcyBufferedImage img = getImage(t, z); 5122 5123 if (img != null) 5124 return img.getDataXYCAsByte(); 5125 5126 return null; 5127 } 5128 5129 /** 5130 * Returns a direct reference to 2D byte array data [C][XY] for specified t, z 5131 */ 5132 public short[][] getDataXYCAsShort(int t, int z) 5133 { 5134 final IcyBufferedImage img = getImage(t, z); 5135 5136 if (img != null) 5137 return img.getDataXYCAsShort(); 5138 5139 return null; 5140 } 5141 5142 /** 5143 * Returns a direct reference to 2D byte array data [C][XY] for specified t, z 5144 */ 5145 public int[][] getDataXYCAsInt(int t, int z) 5146 { 5147 final IcyBufferedImage img = getImage(t, z); 5148 5149 if (img != null) 5150 return img.getDataXYCAsInt(); 5151 5152 return null; 5153 } 5154 5155 /** 5156 * Returns a direct reference to 2D byte array data [C][XY] for specified t, z 5157 */ 5158 public float[][] getDataXYCAsFloat(int t, int z) 5159 { 5160 final IcyBufferedImage img = getImage(t, z); 5161 5162 if (img != null) 5163 return img.getDataXYCAsFloat(); 5164 5165 return null; 5166 } 5167 5168 /** 5169 * Returns a direct reference to 2D byte array data [C][XY] for specified t, z 5170 */ 5171 public double[][] getDataXYCAsDouble(int t, int z) 5172 { 5173 final IcyBufferedImage img = getImage(t, z); 5174 5175 if (img != null) 5176 return img.getDataXYCAsDouble(); 5177 5178 return null; 5179 } 5180 5181 /** 5182 * Returns a direct reference to 1D byte array data [XY] for specified t, z, c 5183 */ 5184 public byte[] getDataXYAsByte(int t, int z, int c) 5185 { 5186 final IcyBufferedImage img = getImage(t, z); 5187 5188 if (img != null) 5189 return img.getDataXYAsByte(c); 5190 5191 return null; 5192 } 5193 5194 /** 5195 * Returns a direct reference to 1D byte array data [XY] for specified t, z, c 5196 */ 5197 public short[] getDataXYAsShort(int t, int z, int c) 5198 { 5199 final IcyBufferedImage img = getImage(t, z); 5200 5201 if (img != null) 5202 return img.getDataXYAsShort(c); 5203 5204 return null; 5205 } 5206 5207 /** 5208 * Returns a direct reference to 1D byte array data [XY] for specified t, z, c 5209 */ 5210 public int[] getDataXYAsInt(int t, int z, int c) 5211 { 5212 final IcyBufferedImage img = getImage(t, z); 5213 5214 if (img != null) 5215 return img.getDataXYAsInt(c); 5216 5217 return null; 5218 } 5219 5220 /** 5221 * Returns a direct reference to 1D byte array data [XY] for specified t, z, c 5222 */ 5223 public float[] getDataXYAsFloat(int t, int z, int c) 5224 { 5225 final IcyBufferedImage img = getImage(t, z); 5226 5227 if (img != null) 5228 return img.getDataXYAsFloat(c); 5229 5230 return null; 5231 } 5232 5233 /** 5234 * Returns a direct reference to 1D byte array data [XY] for specified t, z, c 5235 */ 5236 public double[] getDataXYAsDouble(int t, int z, int c) 5237 { 5238 final IcyBufferedImage img = getImage(t, z); 5239 5240 if (img != null) 5241 return img.getDataXYAsDouble(c); 5242 5243 return null; 5244 } 5245 5246 /** 5247 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 5248 */ 5249 public byte[][][] getDataXYZTAsByte(int c) 5250 { 5251 final int sizeT = getSizeT(); 5252 final byte[][][] result = new byte[sizeT][][]; 5253 5254 for (int t = 0; t < sizeT; t++) 5255 result[t] = getDataXYZAsByte(t, c); 5256 5257 return result; 5258 } 5259 5260 /** 5261 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 5262 */ 5263 public short[][][] getDataXYZTAsShort(int c) 5264 { 5265 final int sizeT = getSizeT(); 5266 final short[][][] result = new short[sizeT][][]; 5267 5268 for (int t = 0; t < sizeT; t++) 5269 result[t] = getDataXYZAsShort(t, c); 5270 5271 return result; 5272 } 5273 5274 /** 5275 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 5276 */ 5277 public int[][][] getDataXYZTAsInt(int c) 5278 { 5279 final int sizeT = getSizeT(); 5280 final int[][][] result = new int[sizeT][][]; 5281 5282 for (int t = 0; t < sizeT; t++) 5283 result[t] = getDataXYZAsInt(t, c); 5284 5285 return result; 5286 } 5287 5288 /** 5289 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 5290 */ 5291 public float[][][] getDataXYZTAsFloat(int c) 5292 { 5293 final int sizeT = getSizeT(); 5294 final float[][][] result = new float[sizeT][][]; 5295 5296 for (int t = 0; t < sizeT; t++) 5297 result[t] = getDataXYZAsFloat(t, c); 5298 5299 return result; 5300 } 5301 5302 /** 5303 * Returns a direct reference to 3D byte array data [T][Z][XY] for specified c 5304 */ 5305 public double[][][] getDataXYZTAsDouble(int c) 5306 { 5307 final int sizeT = getSizeT(); 5308 final double[][][] result = new double[sizeT][][]; 5309 5310 for (int t = 0; t < sizeT; t++) 5311 result[t] = getDataXYZAsDouble(t, c); 5312 5313 return result; 5314 } 5315 5316 /** 5317 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 5318 */ 5319 public byte[][] getDataXYZAsByte(int t, int c) 5320 { 5321 final int sizeZ = getSizeZ(t); 5322 final byte[][] result = new byte[sizeZ][]; 5323 5324 for (int z = 0; z < sizeZ; z++) 5325 result[z] = getDataXYAsByte(t, z, c); 5326 5327 return result; 5328 } 5329 5330 /** 5331 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 5332 */ 5333 public short[][] getDataXYZAsShort(int t, int c) 5334 { 5335 final int sizeZ = getSizeZ(t); 5336 final short[][] result = new short[sizeZ][]; 5337 5338 for (int z = 0; z < sizeZ; z++) 5339 result[z] = getDataXYAsShort(t, z, c); 5340 5341 return result; 5342 } 5343 5344 /** 5345 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 5346 */ 5347 public int[][] getDataXYZAsInt(int t, int c) 5348 { 5349 final int sizeZ = getSizeZ(t); 5350 final int[][] result = new int[sizeZ][]; 5351 5352 for (int z = 0; z < sizeZ; z++) 5353 result[z] = getDataXYAsInt(t, z, c); 5354 5355 return result; 5356 } 5357 5358 /** 5359 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 5360 */ 5361 public float[][] getDataXYZAsFloat(int t, int c) 5362 { 5363 final int sizeZ = getSizeZ(t); 5364 final float[][] result = new float[sizeZ][]; 5365 5366 for (int z = 0; z < sizeZ; z++) 5367 result[z] = getDataXYAsFloat(t, z, c); 5368 5369 return result; 5370 } 5371 5372 /** 5373 * Returns a direct reference to 2D byte array data [Z][XY] for specified t, c 5374 */ 5375 public double[][] getDataXYZAsDouble(int t, int c) 5376 { 5377 final int sizeZ = getSizeZ(t); 5378 final double[][] result = new double[sizeZ][]; 5379 5380 for (int z = 0; z < sizeZ; z++) 5381 result[z] = getDataXYAsDouble(t, z, c); 5382 5383 return result; 5384 } 5385 5386 /** 5387 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 5388 */ 5389 public byte[] getDataCopyXYCZTAsByte() 5390 { 5391 return getDataCopyXYCZTAsByte(null, 0); 5392 } 5393 5394 /** 5395 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 5396 * If (out != null) then it's used to store result at the specified offset 5397 */ 5398 public byte[] getDataCopyXYCZTAsByte(byte[] out, int off) 5399 { 5400 final long sizeT = getSizeT(); 5401 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5402 if ((len * sizeT) >= Integer.MAX_VALUE) 5403 throw new TooLargeArrayException(); 5404 5405 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5406 int offset = off; 5407 5408 for (int t = 0; t < sizeT; t++) 5409 { 5410 getDataCopyXYCZAsByte(t, result, offset); 5411 offset += len; 5412 } 5413 5414 return result; 5415 } 5416 5417 /** 5418 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 5419 */ 5420 public short[] getDataCopyXYCZTAsShort() 5421 { 5422 return getDataCopyXYCZTAsShort(null, 0); 5423 } 5424 5425 /** 5426 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 5427 * If (out != null) then it's used to store result at the specified offset 5428 */ 5429 public short[] getDataCopyXYCZTAsShort(short[] out, int off) 5430 { 5431 final long sizeT = getSizeT(); 5432 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5433 if ((len * sizeT) >= Integer.MAX_VALUE) 5434 throw new TooLargeArrayException(); 5435 5436 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5437 int offset = off; 5438 5439 for (int t = 0; t < sizeT; t++) 5440 { 5441 getDataCopyXYCZAsShort(t, result, offset); 5442 offset += len; 5443 } 5444 5445 return result; 5446 } 5447 5448 /** 5449 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 5450 */ 5451 public int[] getDataCopyXYCZTAsInt() 5452 { 5453 return getDataCopyXYCZTAsInt(null, 0); 5454 } 5455 5456 /** 5457 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 5458 * If (out != null) then it's used to store result at the specified offset 5459 */ 5460 public int[] getDataCopyXYCZTAsInt(int[] out, int off) 5461 { 5462 final long sizeT = getSizeT(); 5463 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5464 if ((len * sizeT) >= Integer.MAX_VALUE) 5465 throw new TooLargeArrayException(); 5466 5467 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5468 int offset = off; 5469 5470 for (int t = 0; t < sizeT; t++) 5471 { 5472 getDataCopyXYCZAsInt(t, result, offset); 5473 offset += len; 5474 } 5475 5476 return result; 5477 } 5478 5479 /** 5480 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 5481 */ 5482 public float[] getDataCopyXYCZTAsFloat() 5483 { 5484 return getDataCopyXYCZTAsFloat(null, 0); 5485 } 5486 5487 /** 5488 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 5489 * If (out != null) then it's used to store result at the specified offset 5490 */ 5491 public float[] getDataCopyXYCZTAsFloat(float[] out, int off) 5492 { 5493 final long sizeT = getSizeT(); 5494 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5495 if ((len * sizeT) >= Integer.MAX_VALUE) 5496 throw new TooLargeArrayException(); 5497 5498 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5499 int offset = off; 5500 5501 for (int t = 0; t < sizeT; t++) 5502 { 5503 getDataCopyXYCZAsFloat(t, result, offset); 5504 offset += len; 5505 } 5506 5507 return result; 5508 } 5509 5510 /** 5511 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY] 5512 */ 5513 public double[] getDataCopyXYCZTAsDouble() 5514 { 5515 return getDataCopyXYCZTAsDouble(null, 0); 5516 } 5517 5518 /** 5519 * Returns a 1D array data copy [XYCZT] of internal 4D array data [T][Z][C][XY]<br> 5520 * If (out != null) then it's used to store result at the specified offset 5521 */ 5522 public double[] getDataCopyXYCZTAsDouble(double[] out, int off) 5523 { 5524 final long sizeT = getSizeT(); 5525 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5526 if ((len * sizeT) >= Integer.MAX_VALUE) 5527 throw new TooLargeArrayException(); 5528 5529 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5530 int offset = off; 5531 5532 for (int t = 0; t < sizeT; t++) 5533 { 5534 getDataCopyXYCZAsDouble(t, result, offset); 5535 offset += len; 5536 } 5537 5538 return result; 5539 } 5540 5541 /** 5542 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 5543 */ 5544 public byte[] getDataCopyXYCZAsByte(int t) 5545 { 5546 return getDataCopyXYCZAsByte(t, null, 0); 5547 } 5548 5549 /** 5550 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 5551 * If (out != null) then it's used to store result at the specified offset 5552 */ 5553 public byte[] getDataCopyXYCZAsByte(int t, byte[] out, int off) 5554 { 5555 final long sizeZ = getSizeZ(); 5556 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 5557 if ((len * sizeZ) >= Integer.MAX_VALUE) 5558 throw new TooLargeArrayException(); 5559 5560 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 5561 int offset = off; 5562 5563 for (int z = 0; z < sizeZ; z++) 5564 { 5565 getDataCopyXYCAsByte(t, z, result, offset); 5566 offset += len; 5567 } 5568 5569 return result; 5570 } 5571 5572 /** 5573 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 5574 */ 5575 public short[] getDataCopyXYCZAsShort(int t) 5576 { 5577 return getDataCopyXYCZAsShort(t, null, 0); 5578 } 5579 5580 /** 5581 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 5582 * If (out != null) then it's used to store result at the specified offset 5583 */ 5584 public short[] getDataCopyXYCZAsShort(int t, short[] out, int off) 5585 { 5586 final long sizeZ = getSizeZ(); 5587 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 5588 if ((len * sizeZ) >= Integer.MAX_VALUE) 5589 throw new TooLargeArrayException(); 5590 5591 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 5592 int offset = off; 5593 5594 for (int z = 0; z < sizeZ; z++) 5595 { 5596 getDataCopyXYCAsShort(t, z, result, offset); 5597 offset += len; 5598 } 5599 5600 return result; 5601 } 5602 5603 /** 5604 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 5605 */ 5606 public int[] getDataCopyXYCZAsInt(int t) 5607 { 5608 return getDataCopyXYCZAsInt(t, null, 0); 5609 } 5610 5611 /** 5612 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 5613 * If (out != null) then it's used to store result at the specified offset 5614 */ 5615 public int[] getDataCopyXYCZAsInt(int t, int[] out, int off) 5616 { 5617 final long sizeZ = getSizeZ(); 5618 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 5619 if ((len * sizeZ) >= Integer.MAX_VALUE) 5620 throw new TooLargeArrayException(); 5621 5622 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 5623 int offset = off; 5624 5625 for (int z = 0; z < sizeZ; z++) 5626 { 5627 getDataCopyXYCAsInt(t, z, result, offset); 5628 offset += len; 5629 } 5630 5631 return result; 5632 } 5633 5634 /** 5635 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 5636 */ 5637 public float[] getDataCopyXYCZAsFloat(int t) 5638 { 5639 return getDataCopyXYCZAsFloat(t, null, 0); 5640 } 5641 5642 /** 5643 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 5644 * If (out != null) then it's used to store result at the specified offset 5645 */ 5646 public float[] getDataCopyXYCZAsFloat(int t, float[] out, int off) 5647 { 5648 final long sizeZ = getSizeZ(); 5649 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 5650 if ((len * sizeZ) >= Integer.MAX_VALUE) 5651 throw new TooLargeArrayException(); 5652 5653 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 5654 int offset = off; 5655 5656 for (int z = 0; z < sizeZ; z++) 5657 { 5658 getDataCopyXYCAsFloat(t, z, result, offset); 5659 offset += len; 5660 } 5661 5662 return result; 5663 } 5664 5665 /** 5666 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t 5667 */ 5668 public double[] getDataCopyXYCZAsDouble(int t) 5669 { 5670 return getDataCopyXYCZAsDouble(t, null, 0); 5671 } 5672 5673 /** 5674 * Returns a 1D array data copy [XYCZ] of internal 3D array data [Z][C][XY] for specified t<br> 5675 * If (out != null) then it's used to store result at the specified offset 5676 */ 5677 public double[] getDataCopyXYCZAsDouble(int t, double[] out, int off) 5678 { 5679 final long sizeZ = getSizeZ(); 5680 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 5681 if ((len * sizeZ) >= Integer.MAX_VALUE) 5682 throw new TooLargeArrayException(); 5683 5684 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 5685 int offset = off; 5686 5687 for (int z = 0; z < sizeZ; z++) 5688 { 5689 getDataCopyXYCAsDouble(t, z, result, offset); 5690 offset += len; 5691 } 5692 5693 return result; 5694 } 5695 5696 /** 5697 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 5698 */ 5699 public byte[] getDataCopyXYCAsByte(int t, int z) 5700 { 5701 return getDataCopyXYCAsByte(t, z, null, 0); 5702 } 5703 5704 /** 5705 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 5706 * If (out != null) then it's used to store result at the specified offset 5707 */ 5708 public byte[] getDataCopyXYCAsByte(int t, int z, byte[] out, int off) 5709 { 5710 final IcyBufferedImage img = getImage(t, z); 5711 5712 if (img != null) 5713 return img.getDataCopyXYCAsByte(out, off); 5714 5715 return out; 5716 } 5717 5718 /** 5719 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 5720 */ 5721 public short[] getDataCopyXYCAsShort(int t, int z) 5722 { 5723 return getDataCopyXYCAsShort(t, z, null, 0); 5724 } 5725 5726 /** 5727 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 5728 * If (out != null) then it's used to store result at the specified offset 5729 */ 5730 public short[] getDataCopyXYCAsShort(int t, int z, short[] out, int off) 5731 { 5732 final IcyBufferedImage img = getImage(t, z); 5733 5734 if (img != null) 5735 return img.getDataCopyXYCAsShort(out, off); 5736 5737 return out; 5738 } 5739 5740 /** 5741 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 5742 */ 5743 public int[] getDataCopyXYCAsInt(int t, int z) 5744 { 5745 return getDataCopyXYCAsInt(t, z, null, 0); 5746 } 5747 5748 /** 5749 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 5750 * If (out != null) then it's used to store result at the specified offset 5751 */ 5752 public int[] getDataCopyXYCAsInt(int t, int z, int[] out, int off) 5753 { 5754 final IcyBufferedImage img = getImage(t, z); 5755 5756 if (img != null) 5757 return img.getDataCopyXYCAsInt(out, off); 5758 5759 return out; 5760 } 5761 5762 /** 5763 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 5764 */ 5765 public float[] getDataCopyXYCAsFloat(int t, int z) 5766 { 5767 return getDataCopyXYCAsFloat(t, z, null, 0); 5768 } 5769 5770 /** 5771 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 5772 * If (out != null) then it's used to store result at the specified offset 5773 */ 5774 public float[] getDataCopyXYCAsFloat(int t, int z, float[] out, int off) 5775 { 5776 final IcyBufferedImage img = getImage(t, z); 5777 5778 if (img != null) 5779 return img.getDataCopyXYCAsFloat(out, off); 5780 5781 return out; 5782 } 5783 5784 /** 5785 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z 5786 */ 5787 public double[] getDataCopyXYCAsDouble(int t, int z) 5788 { 5789 return getDataCopyXYCAsDouble(t, z, null, 0); 5790 } 5791 5792 /** 5793 * Returns a 1D array data copy [XYC] of internal 2D array data [C][XY] for specified t, z<br> 5794 * If (out != null) then it's used to store result at the specified offset 5795 */ 5796 public double[] getDataCopyXYCAsDouble(int t, int z, double[] out, int off) 5797 { 5798 final IcyBufferedImage img = getImage(t, z); 5799 5800 if (img != null) 5801 return img.getDataCopyXYCAsDouble(out, off); 5802 5803 return out; 5804 } 5805 5806 /** 5807 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 5808 */ 5809 public byte[] getDataCopyXYAsByte(int t, int z, int c) 5810 { 5811 return getDataCopyXYAsByte(t, z, c, null, 0); 5812 } 5813 5814 /** 5815 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 5816 * If (out != null) then it's used to store result at the specified offset 5817 */ 5818 public byte[] getDataCopyXYAsByte(int t, int z, int c, byte[] out, int off) 5819 { 5820 final IcyBufferedImage img = getImage(t, z); 5821 5822 if (img != null) 5823 return img.getDataCopyXYAsByte(c, out, off); 5824 5825 return out; 5826 } 5827 5828 /** 5829 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 5830 */ 5831 public short[] getDataCopyXYAsShort(int t, int z, int c) 5832 { 5833 return getDataCopyXYAsShort(t, z, c, null, 0); 5834 } 5835 5836 /** 5837 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 5838 * If (out != null) then it's used to store result at the specified offset 5839 */ 5840 public short[] getDataCopyXYAsShort(int t, int z, int c, short[] out, int off) 5841 { 5842 final IcyBufferedImage img = getImage(t, z); 5843 5844 if (img != null) 5845 return img.getDataCopyXYAsShort(c, out, off); 5846 5847 return out; 5848 } 5849 5850 /** 5851 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 5852 */ 5853 public int[] getDataCopyXYAsInt(int t, int z, int c) 5854 { 5855 return getDataCopyXYAsInt(t, z, c, null, 0); 5856 } 5857 5858 /** 5859 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 5860 * If (out != null) then it's used to store result at the specified offset 5861 */ 5862 public int[] getDataCopyXYAsInt(int t, int z, int c, int[] out, int off) 5863 { 5864 final IcyBufferedImage img = getImage(t, z); 5865 5866 if (img != null) 5867 return img.getDataCopyXYAsInt(c, out, off); 5868 5869 return out; 5870 } 5871 5872 /** 5873 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 5874 */ 5875 public float[] getDataCopyXYAsFloat(int t, int z, int c) 5876 { 5877 return getDataCopyXYAsFloat(t, z, c, null, 0); 5878 } 5879 5880 /** 5881 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 5882 * If (out != null) then it's used to store result at the specified offset 5883 */ 5884 public float[] getDataCopyXYAsFloat(int t, int z, int c, float[] out, int off) 5885 { 5886 final IcyBufferedImage img = getImage(t, z); 5887 5888 if (img != null) 5889 return img.getDataCopyXYAsFloat(c, out, off); 5890 5891 return out; 5892 } 5893 5894 /** 5895 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c 5896 */ 5897 public double[] getDataCopyXYAsDouble(int t, int z, int c) 5898 { 5899 return getDataCopyXYAsDouble(t, z, c, null, 0); 5900 } 5901 5902 /** 5903 * Returns a 1D array data copy [XY] of internal 1D array data [XY] for specified t, z, c<br> 5904 * If (out != null) then it's used to store result at the specified offset 5905 */ 5906 public double[] getDataCopyXYAsDouble(int t, int z, int c, double[] out, int off) 5907 { 5908 final IcyBufferedImage img = getImage(t, z); 5909 5910 if (img != null) 5911 return img.getDataCopyXYAsDouble(c, out, off); 5912 5913 return out; 5914 } 5915 5916 /** 5917 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 5918 */ 5919 public byte[] getDataCopyCXYZTAsByte() 5920 { 5921 return getDataCopyCXYZTAsByte(null, 0); 5922 } 5923 5924 /** 5925 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 5926 * If (out != null) then it's used to store result at the specified offset 5927 */ 5928 public byte[] getDataCopyCXYZTAsByte(byte[] out, int off) 5929 { 5930 final long sizeT = getSizeT(); 5931 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5932 if ((len * sizeT) >= Integer.MAX_VALUE) 5933 throw new TooLargeArrayException(); 5934 5935 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5936 int offset = off; 5937 5938 for (int t = 0; t < sizeT; t++) 5939 { 5940 getDataCopyCXYZAsByte(t, result, offset); 5941 offset += len; 5942 } 5943 5944 return result; 5945 } 5946 5947 /** 5948 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 5949 */ 5950 public short[] getDataCopyCXYZTAsShort() 5951 { 5952 return getDataCopyCXYZTAsShort(null, 0); 5953 } 5954 5955 /** 5956 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 5957 * If (out != null) then it's used to store result at the specified offset 5958 */ 5959 public short[] getDataCopyCXYZTAsShort(short[] out, int off) 5960 { 5961 final long sizeT = getSizeT(); 5962 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5963 if ((len * sizeT) >= Integer.MAX_VALUE) 5964 throw new TooLargeArrayException(); 5965 5966 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5967 int offset = off; 5968 5969 for (int t = 0; t < sizeT; t++) 5970 { 5971 getDataCopyCXYZAsShort(t, result, offset); 5972 offset += len; 5973 } 5974 5975 return result; 5976 } 5977 5978 /** 5979 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 5980 */ 5981 public int[] getDataCopyCXYZTAsInt() 5982 { 5983 return getDataCopyCXYZTAsInt(null, 0); 5984 } 5985 5986 /** 5987 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 5988 * If (out != null) then it's used to store result at the specified offset 5989 */ 5990 public int[] getDataCopyCXYZTAsInt(int[] out, int off) 5991 { 5992 final long sizeT = getSizeT(); 5993 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 5994 if ((len * sizeT) >= Integer.MAX_VALUE) 5995 throw new TooLargeArrayException(); 5996 5997 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 5998 int offset = off; 5999 6000 for (int t = 0; t < sizeT; t++) 6001 { 6002 getDataCopyCXYZAsInt(t, result, offset); 6003 offset += len; 6004 } 6005 6006 return result; 6007 } 6008 6009 /** 6010 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 6011 */ 6012 public float[] getDataCopyCXYZTAsFloat() 6013 { 6014 return getDataCopyCXYZTAsFloat(null, 0); 6015 } 6016 6017 /** 6018 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 6019 * If (out != null) then it's used to store result at the specified offset 6020 */ 6021 public float[] getDataCopyCXYZTAsFloat(float[] out, int off) 6022 { 6023 final long sizeT = getSizeT(); 6024 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 6025 if ((len * sizeT) >= Integer.MAX_VALUE) 6026 throw new TooLargeArrayException(); 6027 6028 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6029 int offset = off; 6030 6031 for (int t = 0; t < sizeT; t++) 6032 { 6033 getDataCopyCXYZAsFloat(t, result, offset); 6034 offset += len; 6035 } 6036 6037 return result; 6038 } 6039 6040 /** 6041 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY] 6042 */ 6043 public double[] getDataCopyCXYZTAsDouble() 6044 { 6045 return getDataCopyCXYZTAsDouble(null, 0); 6046 } 6047 6048 /** 6049 * Returns a 1D array data copy [CXYZT] of internal 4D array data [T][Z][C][XY]<br> 6050 * If (out != null) then it's used to store result at the specified offset 6051 */ 6052 public double[] getDataCopyCXYZTAsDouble(double[] out, int off) 6053 { 6054 final long sizeT = getSizeT(); 6055 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC() * (long) getSizeZ(); 6056 if ((len * sizeT) >= Integer.MAX_VALUE) 6057 throw new TooLargeArrayException(); 6058 6059 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6060 int offset = off; 6061 6062 for (int t = 0; t < sizeT; t++) 6063 { 6064 getDataCopyCXYZAsDouble(t, result, offset); 6065 offset += len; 6066 } 6067 6068 return result; 6069 } 6070 6071 /** 6072 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 6073 */ 6074 public byte[] getDataCopyCXYZAsByte(int t) 6075 { 6076 return getDataCopyCXYZAsByte(t, null, 0); 6077 } 6078 6079 /** 6080 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 6081 * If (out != null) then it's used to store result at the specified offset 6082 */ 6083 public byte[] getDataCopyCXYZAsByte(int t, byte[] out, int off) 6084 { 6085 final long sizeZ = getSizeZ(); 6086 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 6087 if ((len * sizeZ) >= Integer.MAX_VALUE) 6088 throw new TooLargeArrayException(); 6089 6090 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6091 int offset = off; 6092 6093 for (int z = 0; z < sizeZ; z++) 6094 { 6095 getDataCopyCXYAsByte(t, z, result, offset); 6096 offset += len; 6097 } 6098 6099 return result; 6100 } 6101 6102 /** 6103 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 6104 */ 6105 public short[] getDataCopyCXYZAsShort(int t) 6106 { 6107 return getDataCopyCXYZAsShort(t, null, 0); 6108 } 6109 6110 /** 6111 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 6112 * If (out != null) then it's used to store result at the specified offset 6113 */ 6114 public short[] getDataCopyCXYZAsShort(int t, short[] out, int off) 6115 { 6116 final long sizeZ = getSizeZ(); 6117 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 6118 if ((len * sizeZ) >= Integer.MAX_VALUE) 6119 throw new TooLargeArrayException(); 6120 6121 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6122 int offset = off; 6123 6124 for (int z = 0; z < sizeZ; z++) 6125 { 6126 getDataCopyCXYAsShort(t, z, result, offset); 6127 offset += len; 6128 } 6129 6130 return result; 6131 } 6132 6133 /** 6134 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 6135 */ 6136 public int[] getDataCopyCXYZAsInt(int t) 6137 { 6138 return getDataCopyCXYZAsInt(t, null, 0); 6139 } 6140 6141 /** 6142 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 6143 * If (out != null) then it's used to store result at the specified offset 6144 */ 6145 public int[] getDataCopyCXYZAsInt(int t, int[] out, int off) 6146 { 6147 final long sizeZ = getSizeZ(); 6148 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 6149 if ((len * sizeZ) >= Integer.MAX_VALUE) 6150 throw new TooLargeArrayException(); 6151 6152 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6153 int offset = off; 6154 6155 for (int z = 0; z < sizeZ; z++) 6156 { 6157 getDataCopyCXYAsInt(t, z, result, offset); 6158 offset += len; 6159 } 6160 6161 return result; 6162 } 6163 6164 /** 6165 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 6166 */ 6167 public float[] getDataCopyCXYZAsFloat(int t) 6168 { 6169 return getDataCopyCXYZAsFloat(t, null, 0); 6170 } 6171 6172 /** 6173 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 6174 * If (out != null) then it's used to store result at the specified offset 6175 */ 6176 public float[] getDataCopyCXYZAsFloat(int t, float[] out, int off) 6177 { 6178 final long sizeZ = getSizeZ(); 6179 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 6180 if ((len * sizeZ) >= Integer.MAX_VALUE) 6181 throw new TooLargeArrayException(); 6182 6183 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6184 int offset = off; 6185 6186 for (int z = 0; z < sizeZ; z++) 6187 { 6188 getDataCopyCXYAsFloat(t, z, result, offset); 6189 offset += len; 6190 } 6191 6192 return result; 6193 } 6194 6195 /** 6196 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t 6197 */ 6198 public double[] getDataCopyCXYZAsDouble(int t) 6199 { 6200 return getDataCopyCXYZAsDouble(t, null, 0); 6201 } 6202 6203 /** 6204 * Returns a 1D array data copy [CXYZ] of internal 3D array data [Z][C][XY] for specified t<br> 6205 * If (out != null) then it's used to store result at the specified offset 6206 */ 6207 public double[] getDataCopyCXYZAsDouble(int t, double[] out, int off) 6208 { 6209 final long sizeZ = getSizeZ(); 6210 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeC(); 6211 if ((len * sizeZ) >= Integer.MAX_VALUE) 6212 throw new TooLargeArrayException(); 6213 6214 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6215 int offset = off; 6216 6217 for (int z = 0; z < sizeZ; z++) 6218 { 6219 getDataCopyCXYAsDouble(t, z, result, offset); 6220 offset += len; 6221 } 6222 6223 return result; 6224 } 6225 6226 /** 6227 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 6228 */ 6229 public byte[] getDataCopyCXYAsByte(int t, int z) 6230 { 6231 return getDataCopyCXYAsByte(t, z, null, 0); 6232 } 6233 6234 /** 6235 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 6236 * If (out != null) then it's used to store result at the specified offset 6237 */ 6238 public byte[] getDataCopyCXYAsByte(int t, int z, byte[] out, int off) 6239 { 6240 final IcyBufferedImage img = getImage(t, z); 6241 6242 if (img != null) 6243 return img.getDataCopyCXYAsByte(out, off); 6244 6245 return out; 6246 } 6247 6248 /** 6249 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 6250 */ 6251 public short[] getDataCopyCXYAsShort(int t, int z) 6252 { 6253 return getDataCopyCXYAsShort(t, z, null, 0); 6254 } 6255 6256 /** 6257 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 6258 * If (out != null) then it's used to store result at the specified offset 6259 */ 6260 public short[] getDataCopyCXYAsShort(int t, int z, short[] out, int off) 6261 { 6262 final IcyBufferedImage img = getImage(t, z); 6263 6264 if (img != null) 6265 return img.getDataCopyCXYAsShort(out, off); 6266 6267 return out; 6268 } 6269 6270 /** 6271 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 6272 */ 6273 public int[] getDataCopyCXYAsInt(int t, int z) 6274 { 6275 return getDataCopyCXYAsInt(t, z, null, 0); 6276 } 6277 6278 /** 6279 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 6280 * If (out != null) then it's used to store result at the specified offset 6281 */ 6282 public int[] getDataCopyCXYAsInt(int t, int z, int[] out, int off) 6283 { 6284 final IcyBufferedImage img = getImage(t, z); 6285 6286 if (img != null) 6287 return img.getDataCopyCXYAsInt(out, off); 6288 6289 return out; 6290 } 6291 6292 /** 6293 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 6294 */ 6295 public float[] getDataCopyCXYAsFloat(int t, int z) 6296 { 6297 return getDataCopyCXYAsFloat(t, z, null, 0); 6298 } 6299 6300 /** 6301 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 6302 * If (out != null) then it's used to store result at the specified offset 6303 */ 6304 public float[] getDataCopyCXYAsFloat(int t, int z, float[] out, int off) 6305 { 6306 final IcyBufferedImage img = getImage(t, z); 6307 6308 if (img != null) 6309 return img.getDataCopyCXYAsFloat(out, off); 6310 6311 return out; 6312 } 6313 6314 /** 6315 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z 6316 */ 6317 public double[] getDataCopyCXYAsDouble(int t, int z) 6318 { 6319 return getDataCopyCXYAsDouble(t, z, null, 0); 6320 } 6321 6322 /** 6323 * Returns a 1D array data copy [CXY] of internal 2D array data [C][XY] for specified t, z<br> 6324 * If (out != null) then it's used to store result at the specified offset 6325 */ 6326 public double[] getDataCopyCXYAsDouble(int t, int z, double[] out, int off) 6327 { 6328 final IcyBufferedImage img = getImage(t, z); 6329 6330 if (img != null) 6331 return img.getDataCopyCXYAsDouble(out, off); 6332 6333 return out; 6334 } 6335 6336 /** 6337 * Returns a 1D array data copy [C] of specified t, z, x, y 6338 */ 6339 public byte[] getDataCopyCAsByte(int t, int z, int x, int y) 6340 { 6341 return getDataCopyCAsByte(t, z, x, y, null, 0); 6342 } 6343 6344 /** 6345 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 6346 * If (out != null) then it's used to store result at the specified offset 6347 */ 6348 public byte[] getDataCopyCAsByte(int t, int z, int x, int y, byte[] out, int off) 6349 { 6350 final IcyBufferedImage img = getImage(t, z); 6351 6352 if (img != null) 6353 return img.getDataCopyCAsByte(x, y, out, off); 6354 6355 return out; 6356 } 6357 6358 /** 6359 * Returns a 1D array data copy [C] of specified t, z, x, y 6360 */ 6361 public short[] getDataCopyCAsShort(int t, int z, int x, int y) 6362 { 6363 return getDataCopyCAsShort(t, z, x, y, null, 0); 6364 } 6365 6366 /** 6367 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 6368 * If (out != null) then it's used to store result at the specified offset 6369 */ 6370 public short[] getDataCopyCAsShort(int t, int z, int x, int y, short[] out, int off) 6371 { 6372 final IcyBufferedImage img = getImage(t, z); 6373 6374 if (img != null) 6375 return img.getDataCopyCAsShort(x, y, out, off); 6376 6377 return out; 6378 } 6379 6380 /** 6381 * Returns a 1D array data copy [C] of specified t, z, x, y 6382 */ 6383 public int[] getDataCopyCAsInt(int t, int z, int x, int y) 6384 { 6385 return getDataCopyCAsInt(t, z, x, y, null, 0); 6386 } 6387 6388 /** 6389 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 6390 * If (out != null) then it's used to store result at the specified offset 6391 */ 6392 public int[] getDataCopyCAsInt(int t, int z, int x, int y, int[] out, int off) 6393 { 6394 final IcyBufferedImage img = getImage(t, z); 6395 6396 if (img != null) 6397 return img.getDataCopyCAsInt(x, y, out, off); 6398 6399 return out; 6400 } 6401 6402 /** 6403 * Returns a 1D array data copy [C] of specified t, z, x, y 6404 */ 6405 public float[] getDataCopyCAsFloat(int t, int z, int x, int y) 6406 { 6407 return getDataCopyCAsFloat(t, z, x, y, null, 0); 6408 } 6409 6410 /** 6411 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 6412 * If (out != null) then it's used to store result at the specified offset 6413 */ 6414 public float[] getDataCopyCAsFloat(int t, int z, int x, int y, float[] out, int off) 6415 { 6416 final IcyBufferedImage img = getImage(t, z); 6417 6418 if (img != null) 6419 return img.getDataCopyCAsFloat(x, y, out, off); 6420 6421 return out; 6422 } 6423 6424 /** 6425 * Returns a 1D array data copy [C] of specified t, z, x, y 6426 */ 6427 public double[] getDataCopyCAsDouble(int t, int z, int x, int y) 6428 { 6429 return getDataCopyCAsDouble(t, z, x, y, null, 0); 6430 } 6431 6432 /** 6433 * Returns a 1D array data copy [C] of specified t, z, x, y<br> 6434 * If (out != null) then it's used to store result at the specified offset 6435 */ 6436 public double[] getDataCopyCAsDouble(int t, int z, int x, int y, double[] out, int off) 6437 { 6438 final IcyBufferedImage img = getImage(t, z); 6439 6440 if (img != null) 6441 return img.getDataCopyCAsDouble(x, y, out, off); 6442 6443 return out; 6444 } 6445 6446 /** 6447 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 6448 */ 6449 public byte[] getDataCopyXYZTAsByte(int c) 6450 { 6451 return getDataCopyXYZTAsByte(c, null, 0); 6452 } 6453 6454 /** 6455 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 6456 * If (out != null) then it's used to store result at the specified offset 6457 */ 6458 public byte[] getDataCopyXYZTAsByte(int c, byte[] out, int off) 6459 { 6460 final long sizeT = getSizeT(); 6461 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeZ(); 6462 if ((len * sizeT) >= Integer.MAX_VALUE) 6463 throw new TooLargeArrayException(); 6464 6465 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6466 int offset = off; 6467 6468 for (int t = 0; t < sizeT; t++) 6469 { 6470 getDataCopyXYZAsByte(t, c, result, offset); 6471 offset += len; 6472 } 6473 6474 return result; 6475 } 6476 6477 /** 6478 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 6479 */ 6480 public short[] getDataCopyXYZTAsShort(int c) 6481 { 6482 return getDataCopyXYZTAsShort(c, null, 0); 6483 } 6484 6485 /** 6486 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 6487 * If (out != null) then it's used to store result at the specified offset 6488 */ 6489 public short[] getDataCopyXYZTAsShort(int c, short[] out, int off) 6490 { 6491 final long sizeT = getSizeT(); 6492 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeZ(); 6493 if ((len * sizeT) >= Integer.MAX_VALUE) 6494 throw new TooLargeArrayException(); 6495 6496 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6497 int offset = off; 6498 6499 for (int t = 0; t < sizeT; t++) 6500 { 6501 getDataCopyXYZAsShort(t, c, result, offset); 6502 offset += len; 6503 } 6504 6505 return result; 6506 } 6507 6508 /** 6509 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 6510 */ 6511 public int[] getDataCopyXYZTAsInt(int c) 6512 { 6513 return getDataCopyXYZTAsInt(c, null, 0); 6514 } 6515 6516 /** 6517 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 6518 * If (out != null) then it's used to store result at the specified offset 6519 */ 6520 public int[] getDataCopyXYZTAsInt(int c, int[] out, int off) 6521 { 6522 final long sizeT = getSizeT(); 6523 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeZ(); 6524 if ((len * sizeT) >= Integer.MAX_VALUE) 6525 throw new TooLargeArrayException(); 6526 6527 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6528 int offset = off; 6529 6530 for (int t = 0; t < sizeT; t++) 6531 { 6532 getDataCopyXYZAsInt(t, c, result, offset); 6533 offset += len; 6534 } 6535 6536 return result; 6537 } 6538 6539 /** 6540 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 6541 */ 6542 public float[] getDataCopyXYZTAsFloat(int c) 6543 { 6544 return getDataCopyXYZTAsFloat(c, null, 0); 6545 } 6546 6547 /** 6548 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 6549 * If (out != null) then it's used to store result at the specified offset 6550 */ 6551 public float[] getDataCopyXYZTAsFloat(int c, float[] out, int off) 6552 { 6553 final long sizeT = getSizeT(); 6554 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeZ(); 6555 if ((len * sizeT) >= Integer.MAX_VALUE) 6556 throw new TooLargeArrayException(); 6557 6558 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6559 int offset = off; 6560 6561 for (int t = 0; t < sizeT; t++) 6562 { 6563 getDataCopyXYZAsFloat(t, c, result, offset); 6564 offset += len; 6565 } 6566 6567 return result; 6568 } 6569 6570 /** 6571 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c 6572 */ 6573 public double[] getDataCopyXYZTAsDouble(int c) 6574 { 6575 return getDataCopyXYZTAsDouble(c, null, 0); 6576 } 6577 6578 /** 6579 * Returns a 1D array data copy [XYZT] of internal 3D array data [T][Z][XY] for specified c<br> 6580 * If (out != null) then it's used to store result at the specified offset 6581 */ 6582 public double[] getDataCopyXYZTAsDouble(int c, double[] out, int off) 6583 { 6584 final long sizeT = getSizeT(); 6585 final long len = (long) getSizeX() * (long) getSizeY() * (long) getSizeZ(); 6586 if ((len * sizeT) >= Integer.MAX_VALUE) 6587 throw new TooLargeArrayException(); 6588 6589 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeT)); 6590 int offset = off; 6591 6592 for (int t = 0; t < sizeT; t++) 6593 { 6594 getDataCopyXYZAsDouble(t, c, result, offset); 6595 offset += len; 6596 } 6597 6598 return result; 6599 } 6600 6601 /** 6602 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 6603 */ 6604 public byte[] getDataCopyXYZAsByte(int t, int c) 6605 { 6606 return getDataCopyXYZAsByte(t, c, null, 0); 6607 } 6608 6609 /** 6610 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 6611 * If (out != null) then it's used to store result at the specified offset 6612 */ 6613 public byte[] getDataCopyXYZAsByte(int t, int c, byte[] out, int off) 6614 { 6615 final long sizeZ = getSizeZ(); 6616 final long len = (long) getSizeX() * (long) getSizeY(); 6617 if ((len * sizeZ) >= Integer.MAX_VALUE) 6618 throw new TooLargeArrayException(); 6619 6620 final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6621 int offset = off; 6622 6623 for (int z = 0; z < sizeZ; z++) 6624 { 6625 getDataCopyXYAsByte(t, z, c, result, offset); 6626 offset += len; 6627 } 6628 6629 return result; 6630 } 6631 6632 /** 6633 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 6634 */ 6635 public short[] getDataCopyXYZAsShort(int t, int c) 6636 { 6637 return getDataCopyXYZAsShort(t, c, null, 0); 6638 } 6639 6640 /** 6641 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 6642 * If (out != null) then it's used to store result at the specified offset 6643 */ 6644 public short[] getDataCopyXYZAsShort(int t, int c, short[] out, int off) 6645 { 6646 final long sizeZ = getSizeZ(); 6647 final long len = (long) getSizeX() * (long) getSizeY(); 6648 if ((len * sizeZ) >= Integer.MAX_VALUE) 6649 throw new TooLargeArrayException(); 6650 6651 final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6652 int offset = off; 6653 6654 for (int z = 0; z < sizeZ; z++) 6655 { 6656 getDataCopyXYAsShort(t, z, c, result, offset); 6657 offset += len; 6658 } 6659 6660 return result; 6661 } 6662 6663 /** 6664 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 6665 */ 6666 public int[] getDataCopyXYZAsInt(int t, int c) 6667 { 6668 return getDataCopyXYZAsInt(t, c, null, 0); 6669 } 6670 6671 /** 6672 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 6673 * If (out != null) then it's used to store result at the specified offset 6674 */ 6675 public int[] getDataCopyXYZAsInt(int t, int c, int[] out, int off) 6676 { 6677 final long sizeZ = getSizeZ(); 6678 final long len = (long) getSizeX() * (long) getSizeY(); 6679 if ((len * sizeZ) >= Integer.MAX_VALUE) 6680 throw new TooLargeArrayException(); 6681 6682 final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6683 int offset = off; 6684 6685 for (int z = 0; z < sizeZ; z++) 6686 { 6687 getDataCopyXYAsInt(t, z, c, result, offset); 6688 offset += len; 6689 } 6690 6691 return result; 6692 } 6693 6694 /** 6695 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 6696 */ 6697 public float[] getDataCopyXYZAsFloat(int t, int c) 6698 { 6699 return getDataCopyXYZAsFloat(t, c, null, 0); 6700 } 6701 6702 /** 6703 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 6704 * If (out != null) then it's used to store result at the specified offset 6705 */ 6706 public float[] getDataCopyXYZAsFloat(int t, int c, float[] out, int off) 6707 { 6708 final long sizeZ = getSizeZ(); 6709 final long len = (long) getSizeX() * (long) getSizeY(); 6710 if ((len * sizeZ) >= Integer.MAX_VALUE) 6711 throw new TooLargeArrayException(); 6712 6713 final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6714 int offset = off; 6715 6716 for (int z = 0; z < sizeZ; z++) 6717 { 6718 getDataCopyXYAsFloat(t, z, c, result, offset); 6719 offset += len; 6720 } 6721 6722 return result; 6723 } 6724 6725 /** 6726 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c 6727 */ 6728 public double[] getDataCopyXYZAsDouble(int t, int c) 6729 { 6730 return getDataCopyXYZAsDouble(t, c, null, 0); 6731 } 6732 6733 /** 6734 * Returns a 1D array data copy [XYZ] of internal 2D array data [Z][XY] for specified t, c<br> 6735 * If (out != null) then it's used to store result at the specified offset 6736 */ 6737 public double[] getDataCopyXYZAsDouble(int t, int c, double[] out, int off) 6738 { 6739 final long sizeZ = getSizeZ(); 6740 final long len = (long) getSizeX() * (long) getSizeY(); 6741 if ((len * sizeZ) >= Integer.MAX_VALUE) 6742 throw new TooLargeArrayException(); 6743 6744 final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeZ)); 6745 int offset = off; 6746 6747 for (int z = 0; z < sizeZ; z++) 6748 { 6749 getDataCopyXYAsDouble(t, z, c, result, offset); 6750 offset += len; 6751 } 6752 6753 return result; 6754 } 6755 6756 /** 6757 * Sets 1D array data [XY] for specified t, z, c 6758 */ 6759 public void setDataXY(int t, int z, int c, Object value) 6760 { 6761 final IcyBufferedImage img = getImage(t, z); 6762 6763 if (img != null) 6764 img.setDataXY(c, value); 6765 } 6766 6767 /** 6768 * @deprecated Uses {@link SequenceUtil#getSubSequence(Sequence, int, int, int, int, int, int, int, int)} instead. 6769 */ 6770 @Deprecated 6771 public Sequence getSubSequence(int startX, int startY, int startZ, int startT, int sizeX, int sizeY, int sizeZ, 6772 int sizeT) 6773 { 6774 return SequenceUtil.getSubSequence(this, startX, startY, startZ, startT, sizeX, sizeY, sizeZ, sizeT); 6775 } 6776 6777 /** 6778 * @deprecated Use {@link SequenceUtil#getCopy(Sequence)} instead. 6779 */ 6780 @Deprecated 6781 public Sequence getCopy() 6782 { 6783 return SequenceUtil.getCopy(this); 6784 } 6785 6786 /** 6787 * Set all viewer containing this sequence to time t. 6788 * 6789 * @deprecated Use this piece of code instead :<br> 6790 * <code>for(Viewer v: Icy.getMainInterface().getViewers(sequence))</code></br> 6791 * <code> v.setT(...)</code> 6792 */ 6793 @Deprecated 6794 public void setT(int t) 6795 { 6796 for (Viewer viewer : Icy.getMainInterface().getViewers()) 6797 if (viewer.getSequence() == this) 6798 viewer.setT(t); 6799 } 6800 6801 /** 6802 * Load XML persistent data from file.<br> 6803 * This method should only be called once when the sequence has just be loaded from file.<br> 6804 * Note that it uses {@link #getFilename()} to define the XML filename so be sure that it is correctly filled before 6805 * calling this method. 6806 * 6807 * @return <code>true</code> if XML data has been correctly loaded, <code>false</code> otherwise. 6808 */ 6809 public boolean loadXMLData() 6810 { 6811 return persistent.loadXMLData(); 6812 } 6813 6814 /** 6815 * Synchronize XML data with sequence data :<br> 6816 * This function refresh all the meta data and ROIs of the sequence and put it in the current 6817 * XML document. 6818 */ 6819 public void refreshXMLData() 6820 { 6821 persistent.refreshXMLData(); 6822 } 6823 6824 /** 6825 * Save attached XML data. 6826 */ 6827 public boolean saveXMLData() 6828 { 6829 Exception exc = null; 6830 int retry = 0; 6831 6832 // definitely ugly but the XML parser may throw some exception in multi thread environnement 6833 // and we really don't want to lost the sequence metadata ! 6834 while (retry < 5) 6835 { 6836 try 6837 { 6838 return persistent.saveXMLData(); 6839 } 6840 catch (Exception e) 6841 { 6842 exc = e; 6843 } 6844 6845 retry++; 6846 } 6847 6848 System.err.println("Error while saving Sequence XML persistent data :"); 6849 IcyExceptionHandler.showErrorMessage(exc, true); 6850 6851 return false; 6852 } 6853 6854 /** 6855 * Returns true if the specified XML data node exist 6856 * 6857 * @param name 6858 * name of node 6859 * @see #getNode(String) 6860 */ 6861 public Node isNodeExisting(String name) 6862 { 6863 return persistent.getNode(name); 6864 } 6865 6866 /** 6867 * Get XML data node identified by specified name.<br> 6868 * The node is created if needed.</br> 6869 * Note that the following node names are reserved: <i>image, name, meta, rois, lut</i></br> 6870 * 6871 * @param name 6872 * name of wanted node 6873 * @see #isNodeExisting(String) 6874 */ 6875 public Node getNode(String name) 6876 { 6877 final Node result = persistent.getNode(name); 6878 6879 if (result == null) 6880 return persistent.setNode(name); 6881 6882 return result; 6883 } 6884 6885 /** 6886 * @deprecated Use {@link #getNode(String)} instead. 6887 */ 6888 @Deprecated 6889 public Node setNode(String name) 6890 { 6891 return persistent.setNode(name); 6892 } 6893 6894 @Override 6895 public String toString() 6896 { 6897 return "Sequence: " + getName() + " - " + getSizeX() + " x " + getSizeY() + " x " + getSizeZ() + " x " 6898 + getSizeT() + " - " + getSizeC() + " ch (" + getDataType_() + ")"; 6899 } 6900 6901 /** 6902 * Do common job on "image add" here 6903 * 6904 * @param image 6905 */ 6906 public void onImageAdded(IcyBufferedImage image) 6907 { 6908 // colorModel not yet defined ? 6909 if (colorModel == null) 6910 // define it from the image colorModel 6911 setColorModel(IcyColorModel.createInstance(image.getIcyColorModel(), true, true)); 6912 6913 // add listener to image 6914 image.addListener(this); 6915 6916 // notify changed 6917 dataChanged(image, SequenceEventType.ADDED); 6918 } 6919 6920 /** 6921 * Do common job on "image replaced" here 6922 */ 6923 public void onImageReplaced(IcyBufferedImage oldImage, IcyBufferedImage newImage) 6924 { 6925 // we replaced the only present image 6926 final boolean typeChange = getNumImage() == 1; 6927 6928 beginUpdate(); 6929 try 6930 { 6931 if (typeChange) 6932 { 6933 // colorModel not compatible ? 6934 if (!colorModel.isCompatible(newImage.getIcyColorModel())) 6935 // define it from the new image colorModel 6936 setColorModel(IcyColorModel.createInstance(newImage.getIcyColorModel(), true, true)); 6937 // only inform about a type change if sequence sizeX and sizeY changed 6938 else if ((oldImage.getSizeX() != newImage.getSizeX()) || (oldImage.getSizeY() != newImage.getSizeY())) 6939 typeChanged(); 6940 } 6941 6942 // TODO: improve cleaning here 6943 // need that to avoid memory leak as we manually patch the image colorspace 6944 if (colorModel != null) 6945 colorModel.getIcyColorSpace().removeListener(oldImage.getIcyColorModel()); 6946 // remove listener from old image 6947 oldImage.removeListener(this); 6948 // notify about old image remove 6949 dataChanged(oldImage, SequenceEventType.REMOVED); 6950 6951 // add listener to new image 6952 newImage.addListener(this); 6953 // notify about new image added 6954 dataChanged(newImage, SequenceEventType.ADDED); 6955 } 6956 finally 6957 { 6958 endUpdate(); 6959 } 6960 } 6961 6962 /** 6963 * Do common job on "image remove" here 6964 * 6965 * @param image 6966 */ 6967 public void onImageRemoved(IcyBufferedImage image) 6968 { 6969 // no more image ? --> releasethe global colorModel 6970 if (isEmpty()) 6971 setColorModel(null); 6972 6973 // TODO: improve cleaning here 6974 // need that to avoid memory leak as we manually patch the image colorspace 6975 if (colorModel != null) 6976 colorModel.getIcyColorSpace().removeListener(image.getIcyColorModel()); 6977 // remove listener from image 6978 image.removeListener(this); 6979 6980 // notify changed 6981 dataChanged(image, SequenceEventType.REMOVED); 6982 } 6983 6984 /** 6985 * fire change event 6986 */ 6987 @SuppressWarnings("deprecation") 6988 protected void fireChangedEvent(SequenceEvent e) 6989 { 6990 final List<SequenceListener> cachedListeners = new ArrayList<SequenceListener>(listeners); 6991 6992 for (SequenceListener listener : cachedListeners) 6993 listener.sequenceChanged(e); 6994 6995 // provide backward compatibility for painter 6996 if (e.getSourceType() == SequenceEventSourceType.SEQUENCE_OVERLAY) 6997 { 6998 final Painter painter; 6999 7000 if (e.getSource() instanceof OverlayWrapper) 7001 painter = ((OverlayWrapper) e.getSource()).getPainter(); 7002 else 7003 painter = (Painter) e.getSource(); 7004 7005 final SequenceEvent event = new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_PAINTER, painter, 7006 e.getType(), e.getParam()); 7007 7008 for (SequenceListener listener : cachedListeners) 7009 listener.sequenceChanged(event); 7010 } 7011 } 7012 7013 /** 7014 * fire close event 7015 */ 7016 protected void fireClosedEvent() 7017 { 7018 for (SequenceListener listener : new ArrayList<SequenceListener>(listeners)) 7019 listener.sequenceClosed(this); 7020 } 7021 7022 /** 7023 * fire model image changed event 7024 */ 7025 @Override 7026 public void fireModelImageChangedEvent() 7027 { 7028 for (SequenceModelListener listener : new ArrayList<SequenceModelListener>(modelListeners)) 7029 listener.imageChanged(); 7030 } 7031 7032 /** 7033 * fire model dimension changed event 7034 */ 7035 @Override 7036 public void fireModelDimensionChangedEvent() 7037 { 7038 for (SequenceModelListener listener : new ArrayList<SequenceModelListener>(modelListeners)) 7039 listener.dimensionChanged(); 7040 } 7041 7042 public void beginUpdate() 7043 { 7044 updater.beginUpdate(); 7045 } 7046 7047 public void endUpdate() 7048 { 7049 updater.endUpdate(); 7050 7051 // no more updating 7052 if (!updater.isUpdating()) 7053 { 7054 // lazy channel bounds update 7055 if (channelBoundsInvalid) 7056 { 7057 channelBoundsInvalid = false; 7058 // images channels bounds are valid at this point 7059 internalUpdateChannelsBounds(); 7060 } 7061 } 7062 } 7063 7064 public boolean isUpdating() 7065 { 7066 return updater.isUpdating(); 7067 } 7068 7069 /** 7070 * sequence meta has changed 7071 */ 7072 public void metaChanged(String metaName) 7073 { 7074 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_META, metaName)); 7075 } 7076 7077 /** 7078 * sequence meta has changed 7079 */ 7080 public void metaChanged(String metaName, int param) 7081 { 7082 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_META, metaName, null, param)); 7083 } 7084 7085 /** 7086 * sequence type (colorModel, size) changed 7087 */ 7088 protected void typeChanged() 7089 { 7090 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_TYPE)); 7091 } 7092 7093 /** 7094 * sequence colorMap changed 7095 */ 7096 protected void colormapChanged(IcyColorModel colorModel, int component) 7097 { 7098 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_COLORMAP, colorModel, component)); 7099 } 7100 7101 /** 7102 * sequence component bounds changed 7103 */ 7104 protected void componentBoundsChanged(IcyColorModel colorModel, int component) 7105 { 7106 updater.changed( 7107 new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_COMPONENTBOUNDS, colorModel, component)); 7108 } 7109 7110 // /** 7111 // * @deprecated Use {@link #overlayChanged(Overlay, SequenceEventType)} instead. 7112 // */ 7113 // @Deprecated 7114 // private void painterChanged(Painter painter, SequenceEventType type) 7115 // { 7116 // updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_PAINTER, painter, 7117 // type)); 7118 // } 7119 7120 /** 7121 * @deprecated Use {@link #overlayChanged(Overlay)} instead. 7122 */ 7123 @Deprecated 7124 public void painterChanged(Painter painter) 7125 { 7126 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_OVERLAY, getOverlay(painter), 7127 SequenceEventType.CHANGED)); 7128 // painterChanged(painter, SequenceEventType.CHANGED); 7129 } 7130 7131 /** 7132 * overlay painter has changed 7133 */ 7134 protected void overlayChanged(Overlay overlay, SequenceEventType type) 7135 { 7136 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_OVERLAY, overlay, type)); 7137 } 7138 7139 /** 7140 * Notify specified painter of overlay has changed (the sequence should contains the specified 7141 * Overlay) 7142 */ 7143 public void overlayChanged(Overlay overlay) 7144 { 7145 if (contains(overlay)) 7146 overlayChanged(overlay, SequenceEventType.CHANGED); 7147 } 7148 7149 /** 7150 * Called when an overlay has changed (internal method).<br> 7151 * Use {@link #overlayChanged(Overlay)} instead. 7152 */ 7153 @Override 7154 public void overlayChanged(OverlayEvent event) 7155 { 7156 // only take care about overlay painter change here (need redraw) 7157 if (event.getType() == OverlayEventType.PAINTER_CHANGED) 7158 overlayChanged(event.getSource(), SequenceEventType.CHANGED); 7159 } 7160 7161 /** 7162 * @deprecated Use {@link #roiChanged(ROI)} method instead. 7163 */ 7164 @Deprecated 7165 public void roiChanged() 7166 { 7167 final Iterator<ROI> it = rois.iterator(); 7168 7169 // send a event for all ROI 7170 while (it.hasNext()) 7171 roiChanged(it.next(), SequenceEventType.CHANGED); 7172 } 7173 7174 /** 7175 * Notify specified roi has changed (the sequence should contains the specified ROI) 7176 */ 7177 public void roiChanged(ROI roi) 7178 { 7179 if (contains(roi)) 7180 roiChanged(roi, SequenceEventType.CHANGED); 7181 } 7182 7183 /** 7184 * Notify specified roi has changed 7185 */ 7186 protected void roiChanged(ROI roi, SequenceEventType type) 7187 { 7188 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_ROI, roi, type)); 7189 } 7190 7191 /** 7192 * Data has changed (global change)<br> 7193 * Be careful, this implies all component bounds are recalculated, can be heavy ! 7194 */ 7195 public void dataChanged() 7196 { 7197 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_DATA, null)); 7198 } 7199 7200 /** 7201 * data has changed 7202 */ 7203 protected void dataChanged(IcyBufferedImage image, SequenceEventType type) 7204 { 7205 updater.changed(new SequenceEvent(this, SequenceEventSourceType.SEQUENCE_DATA, image, type, 0)); 7206 } 7207 7208 @Override 7209 public void colorModelChanged(IcyColorModelEvent e) 7210 { 7211 switch (e.getType()) 7212 { 7213 case COLORMAP_CHANGED: 7214 colormapChanged(e.getColorModel(), e.getComponent()); 7215 break; 7216 7217 case SCALER_CHANGED: 7218 componentBoundsChanged(e.getColorModel(), e.getComponent()); 7219 break; 7220 } 7221 } 7222 7223 @Override 7224 public void imageChanged(IcyBufferedImageEvent e) 7225 { 7226 final IcyBufferedImage image = e.getImage(); 7227 7228 switch (e.getType()) 7229 { 7230 case BOUNDS_CHANGED: 7231 // update sequence channel bounds 7232 if (autoUpdateChannelBounds) 7233 { 7234 // updating sequence ? delay update 7235 if (isUpdating()) 7236 channelBoundsInvalid = true; 7237 else 7238 // refresh sequence channel bounds from images bounds 7239 internalUpdateChannelsBounds(); 7240 } 7241 break; 7242 7243 case COLORMAP_CHANGED: 7244 // ignore that, we don't care about image colormap 7245 break; 7246 7247 case DATA_CHANGED: 7248 // image data changed 7249 dataChanged(image, SequenceEventType.CHANGED); 7250 break; 7251 } 7252 } 7253 7254 @Override 7255 public void roiChanged(ROIEvent event) 7256 { 7257 // notify the ROI has changed 7258 roiChanged(event.getSource(), SequenceEventType.CHANGED); 7259 } 7260 7261 /** 7262 * process on sequence change 7263 */ 7264 @Override 7265 public void onChanged(CollapsibleEvent e) 7266 { 7267 final SequenceEvent event = (SequenceEvent) e; 7268 7269 switch (event.getSourceType()) 7270 { 7271 // do here global process on sequence data change 7272 case SEQUENCE_DATA: 7273 // automatic channel bounds update enabled 7274 if (autoUpdateChannelBounds) 7275 { 7276 // generic CHANGED event 7277 if (event.getSource() == null) 7278 // recalculate all images bounds (automatically update sequence bounds in imageChange event) 7279 recalculateAllImageChannelsBounds(); 7280 7281 // refresh sequence channel bounds from images bounds 7282 internalUpdateChannelsBounds(); 7283 } 7284 7285 // fire SequenceModel event 7286 fireModelImageChangedEvent(); 7287 break; 7288 7289 // do here global process on sequence type change 7290 case SEQUENCE_TYPE: 7291 // fire SequenceModel event 7292 fireModelDimensionChangedEvent(); 7293 break; 7294 7295 // do here global process on sequence colormap change 7296 case SEQUENCE_COLORMAP: 7297 break; 7298 7299 // do here global process on sequence component bounds change 7300 case SEQUENCE_COMPONENTBOUNDS: 7301 break; 7302 7303 // do here global process on sequence overlay change 7304 case SEQUENCE_OVERLAY: 7305 break; 7306 7307 // do here global process on sequence ROI change 7308 case SEQUENCE_ROI: 7309 break; 7310 } 7311 7312 // notify listener we have changed 7313 fireChangedEvent(event); 7314 } 7315 7316}