001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.view.ImageView; 016 017import java.awt.Color; 018import java.awt.Dimension; 019import java.awt.Graphics; 020import java.awt.Graphics2D; 021import java.awt.Image; 022import java.awt.Rectangle; 023import java.awt.RenderingHints; 024import java.awt.Toolkit; 025import java.awt.image.BufferedImage; 026import java.awt.image.ColorModel; 027import java.awt.image.ComponentColorModel; 028import java.awt.image.DataBufferInt; 029import java.awt.image.DirectColorModel; 030import java.awt.image.FilteredImageSource; 031import java.awt.image.ImageFilter; 032import java.awt.image.ImageObserver; 033import java.awt.image.ImageProducer; 034import java.awt.image.IndexColorModel; 035import java.awt.image.PixelGrabber; 036import java.awt.image.RGBImageFilter; 037import java.awt.image.WritableRaster; 038import java.io.BufferedWriter; 039import java.io.File; 040import java.io.FileWriter; 041import java.io.PrintWriter; 042import java.io.RandomAccessFile; 043import java.lang.reflect.Array; 044import java.text.DecimalFormat; 045import java.util.ArrayList; 046import java.util.BitSet; 047import java.util.HashMap; 048import java.util.Hashtable; 049import java.util.Iterator; 050import java.util.List; 051import java.util.Vector; 052 053import org.eclipse.swt.SWT; 054import org.eclipse.swt.custom.ScrolledComposite; 055import org.eclipse.swt.events.DisposeEvent; 056import org.eclipse.swt.events.DisposeListener; 057import org.eclipse.swt.events.ModifyEvent; 058import org.eclipse.swt.events.ModifyListener; 059import org.eclipse.swt.events.MouseEvent; 060import org.eclipse.swt.events.MouseListener; 061import org.eclipse.swt.events.MouseMoveListener; 062import org.eclipse.swt.events.MouseWheelListener; 063import org.eclipse.swt.events.PaintEvent; 064import org.eclipse.swt.events.PaintListener; 065import org.eclipse.swt.events.SelectionAdapter; 066import org.eclipse.swt.events.SelectionEvent; 067import org.eclipse.swt.events.TraverseEvent; 068import org.eclipse.swt.events.TraverseListener; 069import org.eclipse.swt.graphics.Font; 070import org.eclipse.swt.graphics.FontData; 071import org.eclipse.swt.graphics.GC; 072import org.eclipse.swt.graphics.ImageData; 073import org.eclipse.swt.graphics.PaletteData; 074import org.eclipse.swt.graphics.Point; 075import org.eclipse.swt.graphics.RGB; 076import org.eclipse.swt.layout.GridData; 077import org.eclipse.swt.layout.GridLayout; 078import org.eclipse.swt.widgets.Button; 079import org.eclipse.swt.widgets.Canvas; 080import org.eclipse.swt.widgets.Composite; 081import org.eclipse.swt.widgets.Dialog; 082import org.eclipse.swt.widgets.Display; 083import org.eclipse.swt.widgets.Event; 084import org.eclipse.swt.widgets.FileDialog; 085import org.eclipse.swt.widgets.Label; 086import org.eclipse.swt.widgets.Listener; 087import org.eclipse.swt.widgets.Menu; 088import org.eclipse.swt.widgets.MenuItem; 089import org.eclipse.swt.widgets.Scale; 090import org.eclipse.swt.widgets.ScrollBar; 091import org.eclipse.swt.widgets.Shell; 092import org.eclipse.swt.widgets.Slider; 093import org.eclipse.swt.widgets.Text; 094import org.eclipse.swt.widgets.ToolBar; 095import org.eclipse.swt.widgets.ToolItem; 096import org.eclipse.swt.widgets.TreeItem; 097 098import hdf.object.Group; 099import hdf.object.HObject; 100import hdf.object.ScalarDS; 101import hdf.view.Chart; 102import hdf.view.DefaultFileFilter; 103import hdf.view.Tools; 104import hdf.view.ViewProperties; 105import hdf.view.ViewProperties.BITMASK_OP; 106import hdf.view.ViewProperties.DataViewType; 107import hdf.view.DataView.DataViewFactory; 108import hdf.view.DataView.DataViewFactoryProducer; 109import hdf.view.DataView.DataViewManager; 110import hdf.view.PaletteView.PaletteView; 111import hdf.view.TreeView.TreeView; 112import hdf.view.dialog.NewDatasetDialog; 113 114/** 115 * ImageView displays an HDF dataset as an image. 116 * <p> 117 * A scalar dataset in HDF can be displayed in image or table. By default, an 118 * HDF4 GR image and HDF5 image is displayed as an image. Other scalar datasets 119 * are display in a two-dimensional table. 120 * <p> 121 * Users can also choose to display a scalar dataset as image. Currently verion 122 * of the ImageView only supports 8-bit raster image with indexed RGB color 123 * model of 256 colors or 24-bit true color raster image. Data of other type 124 * will be converted to 8-bit integer. The simple linear conversion is used for 125 * this purpose: 126 * 127 * <pre> 128 * y = f * (x - min), 129 * where y = the value of 8-bit integer, 130 * x = the value of original data, 131 * f = 255/(max-min), conversion factor, 132 * max = the maximum of the original data, 133 * min = the minimum of the original data. 134 * </pre> 135 * <p> 136 * A default color table is provided for images without palette attached to it. 137 * Current choice of default palettes include Gray, Rainbow, Nature and Wave. 138 * For more infomation on palette, 139 * read <a href="https://support.hdfgroup.org/HDF5/doc/ADGuide/ImageSpec.html">HDF5 Image and Palette Specification</a> 140 * 141 * @author Jordan T. Henderson 142 * @version 2.4 2//2016 143 */ 144public class DefaultImageView implements ImageView { 145 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultImageView.class); 146 147 private final Display display = Display.getDefault(); 148 private final Shell shell; 149 private Font curFont; 150 151 /** Horizontal direction to flip an image. */ 152 public static final int FLIP_HORIZONTAL = 0; 153 154 /** Vertical direction to flip an image. */ 155 public static final int FLIP_VERTICAL = 1; 156 157 /** ROTATE IMAGE 90 DEGREE CLOCKWISE. */ 158 public static final int ROTATE_CW_90 = 10; 159 160 /** ROTATE IMAGE COUNTER CLOCKWISE 90 DEGREE. */ 161 public static final int ROTATE_CCW_90 = 11; 162 163 /** 164 * The main HDFView. 165 */ 166 private final DataViewManager viewer; 167 168 private Toolkit toolkit; 169 170 /** 171 * The Scalar Dataset. 172 */ 173 private ScalarDS dataset; 174 175 /** 176 * The Component containing the image. 177 */ 178 private ImageComponent imageComponent; 179 180 /** 181 * The Label for the image origin. 182 */ 183 private Label imageOriginLabel; 184 185 /** 186 * The image contained in the ImageView. 187 */ 188 private Image image; 189 190 /** 191 * The zooming factor of this image. 192 */ 193 private float zoomFactor; 194 195 /** 196 * The byte data array of the image. 197 */ 198 private byte[] imageByteData; 199 200 /** 201 * The color table of the image. 202 */ 203 private byte[][] imagePalette; 204 205 /** 206 * The title of this imageview. 207 */ 208 private String frameTitle; 209 210 /** TextField to show the image value. */ 211 private Text valueField; 212 213 /** Flag to indicate if the image is a true color image */ 214 private boolean isTrueColor; 215 216 /** Flag to indicate if the image is a 3D */ 217 private boolean is3D; 218 219 /** Flag to indicate whether to show pixel values in ImageComponent */ 220 private boolean showValues = false; 221 222 /** Flag to indicate if the image is plane interleaved */ 223 private boolean isPlaneInterlace; 224 225 private boolean isHorizontalFlipped = false; 226 227 private boolean isVerticalFlipped = false; 228 229 private int rotateCount = 0; 230 231 /** the number type of the image data */ 232 private char NT; 233 234 /** the raw data of the image */ 235 private Object data; 236 237 private boolean isUnsignedConverted = false; 238 239 private double[] dataRange; 240 private double[] originalRange = { 0, 0 }; 241 242 private PaletteComponent paletteComponent; 243 244 private int animationSpeed = 2; 245 246 private List rotateRelatedItems; 247 248 private ScrolledComposite imageScroller; 249 250 private Text frameField; 251 252 private long curFrame = 0; 253 private long maxFrame = 1; 254 255 private BufferedImage bufferedImage; 256 257 private ContrastSlider contrastSlider; 258 259 private int indexBase = 0; 260 private int[] dataDist = null; 261 262 /** 263 * equates to brightness 264 */ 265 private boolean doAutoGainContrast = false; 266 private double[] gainBias; 267 private double[] gainBiasCurrent; 268 269 /** 270 * int array to hold unsigned short or signed int data from applying the 271 * autogain 272 */ 273 private Object autoGainData; 274 275 private BitSet bitmask; 276 private boolean convertByteData = false; 277 private BITMASK_OP bitmaskOP = BITMASK_OP.EXTRACT; 278 279 private enum Origin { 280 UPPER_LEFT, LOWER_LEFT, UPPER_RIGHT, LOWER_RIGHT 281 } 282 283 private Origin imageOrigin = null; 284 285 private List<Integer> invalidValueIndex; 286 287 /** 288 * Constructs an ImageView. 289 * 290 * @param theView 291 * the main HDFView. 292 */ 293 public DefaultImageView(DataViewManager theView) { 294 this(theView, null); 295 } 296 297 /** 298 * Constructs an ImageView. 299 * 300 * @param theView 301 * the main HDFView. 302 * @param map 303 * the properties on how to show the data. The map is used to 304 * allow applications to pass properties on how to display the 305 * data, such as, transposing data, showing data as character, 306 * applying bitmask, and etc. Predefined keys are listed at 307 * ViewProperties.DATA_VIEW_KEY. 308 */ 309 @SuppressWarnings("rawtypes") 310 public DefaultImageView(DataViewManager theView, HashMap map) { 311 shell = new Shell(display, SWT.SHELL_TRIM); 312 313 shell.setData(this); 314 315 shell.setImage(ViewProperties.getImageIcon()); 316 shell.setLayout(new GridLayout(1, true)); 317 318 shell.addDisposeListener(new DisposeListener() { 319 @Override 320 public void widgetDisposed(DisposeEvent e) { 321 // reload the data when it is displayed next time 322 // because the display type (table or image) may be 323 // different. 324 if ((dataset != null) && !dataset.isImage()) { 325 dataset.clearData(); 326 } 327 328 if (curFont != null) curFont.dispose(); 329 330 data = null; 331 image = null; 332 imageByteData = null; 333 imageComponent = null; 334 autoGainData = null; 335 ((Vector) rotateRelatedItems).setSize(0); 336 337 viewer.removeDataView(DefaultImageView.this); 338 339 System.runFinalization(); 340 System.gc(); 341 } 342 }); 343 344 try { 345 curFont = new Font( 346 display, 347 ViewProperties.getFontType(), 348 ViewProperties.getFontSize(), 349 SWT.NORMAL); 350 } 351 catch (Exception ex) { 352 curFont = null; 353 } 354 355 shell.setFont(curFont); 356 357 viewer = theView; 358 zoomFactor = 1.0f; 359 imageByteData = null; 360 imagePalette = null; 361 paletteComponent = null; 362 isTrueColor = false; 363 is3D = false; 364 isPlaneInterlace = false; 365 data = null; 366 NT = 0; 367 showValues = ViewProperties.showImageValues(); 368 rotateRelatedItems = new Vector(10); 369 imageScroller = null; 370 gainBias = null; 371 gainBiasCurrent = null; 372 autoGainData = null; 373 contrastSlider = null; 374 bitmask = null; 375 invalidValueIndex = new ArrayList<>(); 376 377 toolkit = Toolkit.getDefaultToolkit(); 378 379 String origStr = ViewProperties.getImageOrigin(); 380 if (ViewProperties.ORIGIN_LL.equalsIgnoreCase(origStr)) 381 imageOrigin = Origin.LOWER_LEFT; 382 else if (ViewProperties.ORIGIN_UR.equalsIgnoreCase(origStr)) 383 imageOrigin = Origin.UPPER_RIGHT; 384 else if (ViewProperties.ORIGIN_LR.equalsIgnoreCase(origStr)) 385 imageOrigin = Origin.LOWER_RIGHT; 386 else 387 imageOrigin = Origin.UPPER_LEFT; 388 389 if (ViewProperties.isIndexBase1()) 390 indexBase = 1; 391 392 HObject hobject = null; 393 394 if (map != null) { 395 hobject = (HObject) map.get(ViewProperties.DATA_VIEW_KEY.OBJECT); 396 bitmask = (BitSet) map.get(ViewProperties.DATA_VIEW_KEY.BITMASK); 397 bitmaskOP = (BITMASK_OP) map.get(ViewProperties.DATA_VIEW_KEY.BITMASKOP); 398 399 Boolean b = (Boolean) map.get(ViewProperties.DATA_VIEW_KEY.CONVERTBYTE); 400 if (b != null) 401 convertByteData = b.booleanValue(); 402 403 b = (Boolean) map.get(ViewProperties.DATA_VIEW_KEY.INDEXBASE1); 404 if (b != null) { 405 if (b.booleanValue()) 406 indexBase = 1; 407 else 408 indexBase = 0; 409 } 410 } 411 412 if (hobject == null) { 413 hobject = theView.getTreeView().getCurrentObject(); 414 } 415 416 if ((hobject == null) || !(hobject instanceof ScalarDS)) { 417 viewer.showError("Display data in image failed for - " + hobject); 418 return; 419 } 420 421 dataset = (ScalarDS) hobject; 422 dataRange = dataset.getImageDataRange(); 423 if (dataRange == null) { 424 dataRange = new double[2]; 425 dataRange[0] = dataRange[1] = 0; 426 if (dataset.getDatatype().getDatatypeSize() == 1 427 && !convertByteData) { 428 dataRange[1] = 255; // byte image data rang = [0, 255] 429 } 430 } 431 else { 432 if (dataRange[0] < dataRange[1]) 433 convertByteData = true; 434 } 435 436 if (image == null) { 437 image = getImage(); 438 } 439 440 if (image == null) { 441 viewer.showError("Loading image failed - " + dataset.getName()); 442 dataset = null; 443 return; 444 } 445 446 originalRange[0] = dataRange[0]; 447 originalRange[1] = dataRange[1]; 448 449 // set title 450 StringBuilder sb = new StringBuilder(hobject.getName()); 451 sb.append(" at ") 452 .append(hobject.getPath()) 453 .append(" [") 454 .append(dataset.getFileFormat().getName()) 455 .append(" in ") 456 .append(dataset.getFileFormat().getParent()) 457 .append("]"); 458 459 frameTitle = sb.toString(); 460 shell.setText(sb.toString()); 461 462 // setup subset information 463 int rank = dataset.getRank(); 464 int[] selectedIndex = dataset.getSelectedIndex(); 465 long[] count = dataset.getSelectedDims(); 466 long[] stride = dataset.getStride(); 467 long[] dims = dataset.getDims(); 468 long[] start = dataset.getStartDims(); 469 int n = Math.min(3, rank); 470 471 if (rank > 2) { 472 curFrame = start[selectedIndex[2]] + indexBase; 473 maxFrame = (indexBase == 1) ? dims[selectedIndex[2]] : dims[selectedIndex[2]] - 1; 474 } 475 476 sb.append(" [ dims"); 477 sb.append(selectedIndex[0]); 478 for (int i = 1; i < n; i++) { 479 sb.append("x"); 480 sb.append(selectedIndex[i]); 481 } 482 sb.append(", start"); 483 sb.append(start[selectedIndex[0]]); 484 for (int i = 1; i < n; i++) { 485 sb.append("x"); 486 sb.append(start[selectedIndex[i]]); 487 } 488 sb.append(", count"); 489 sb.append(count[selectedIndex[0]]); 490 for (int i = 1; i < n; i++) { 491 sb.append("x"); 492 sb.append(count[selectedIndex[i]]); 493 } 494 sb.append(", stride"); 495 sb.append(stride[selectedIndex[0]]); 496 for (int i = 1; i < n; i++) { 497 sb.append("x"); 498 sb.append(stride[selectedIndex[i]]); 499 } 500 sb.append(" ] "); 501 502 viewer.showStatus(sb.toString()); 503 504 shell.setMenuBar(createMenuBar()); 505 506 // Add toolbar for Histogram, Frame selection, etc. 507 ToolBar bar = createToolbar(shell); 508 bar.setSize(shell.getSize().x, 30); 509 bar.setLocation(0, 0); 510 511 String originTag = "(0,0)"; 512 if (ViewProperties.isIndexBase1()) 513 originTag = "(1,1)"; 514 515 // Create main component region 516 org.eclipse.swt.widgets.Group group = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 517 group.setFont(curFont); 518 group.setLayout(new GridLayout(2, false)); 519 group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 520 521 if (imageOrigin == Origin.UPPER_LEFT || imageOrigin == Origin.UPPER_RIGHT) { 522 imageOriginLabel = new Label(group, SWT.NONE); 523 imageOriginLabel.setText(originTag); 524 imageOriginLabel.setLayoutData(new GridData((imageOrigin == Origin.UPPER_LEFT || imageOrigin == Origin.LOWER_LEFT) ? SWT.BEGINNING : SWT.END, SWT.FILL, 525 true, false, (imagePalette == null) ? 2 : 1, 1)); 526 527 /* Dummy label to fill space in second column */ 528 if (imagePalette != null) new Label(group, SWT.NONE); 529 } 530 531 imageScroller = new ScrolledComposite(group, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); 532 imageScroller.getHorizontalBar().setIncrement(50); 533 imageScroller.getVerticalBar().setIncrement(50); 534 imageScroller.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 535 imageScroller.setFont(curFont); 536 537 imageComponent = new ImageComponent(imageScroller, SWT.DOUBLE_BUFFERED, image); 538 imageScroller.setContent(imageComponent); 539 540 if (imageOrigin == Origin.LOWER_LEFT) 541 flip(FLIP_VERTICAL); 542 else if (imageOrigin == Origin.UPPER_RIGHT) 543 flip(FLIP_HORIZONTAL); 544 if (imageOrigin == Origin.LOWER_RIGHT) { 545 rotate(ROTATE_CW_90); 546 rotate(ROTATE_CW_90); 547 } 548 549 // add palette canvas to show the palette 550 if (imagePalette != null) { 551 paletteComponent = new PaletteComponent(group, SWT.DOUBLE_BUFFERED, imagePalette, dataRange); 552 } else { 553 // Make ImageComponent take entire width 554 imageScroller.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 555 } 556 557 if (imageOrigin == Origin.LOWER_LEFT || imageOrigin == Origin.LOWER_RIGHT) { 558 imageOriginLabel = new Label(group, SWT.NONE); 559 imageOriginLabel.setText(originTag); 560 imageOriginLabel.setLayoutData(new GridData((imageOrigin == Origin.UPPER_LEFT || imageOrigin == Origin.LOWER_LEFT) ? SWT.BEGINNING : SWT.END, SWT.FILL, 561 true, false, (imagePalette == null) ? 2 : 1, 1)); 562 563 /* Dummy label to fill space in second column */ 564 if (imagePalette != null) new Label(group, SWT.NONE); 565 } 566 567 // Add the text field to display pixel data 568 valueField = new Text(group, SWT.BORDER | SWT.SINGLE); 569 valueField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 570 valueField.setEditable(false); 571 valueField.setFont(curFont); 572 setValueVisible(showValues); 573 574 shell.pack(); 575 576 int width = 700 + (ViewProperties.getFontSize() - 12) * 15; 577 int height = 500 + (ViewProperties.getFontSize() - 12) * 10; 578 shell.setSize(width, height); 579 580 viewer.addDataView(this); 581 582 shell.open(); 583 } 584 585 private Menu createMenuBar() { 586 Menu menuBar = new Menu(shell, SWT.BAR); 587 588 MenuItem item = new MenuItem(menuBar, SWT.CASCADE); 589 item.setText("Image"); 590 591 Menu menu = new Menu(item); 592 item.setMenu(menu); 593 594 item = new MenuItem(menu, SWT.CASCADE); 595 item.setText("Save Image As"); 596 597 Menu saveAsMenu = new Menu(item); 598 item.setMenu(saveAsMenu); 599 600 item = new MenuItem(saveAsMenu, SWT.PUSH); 601 item.setText("JPEG"); 602 item.addSelectionListener(new SelectionAdapter() { 603 @Override 604 public void widgetSelected(SelectionEvent e) { 605 String filetype = Tools.FILE_TYPE_JPEG; 606 607 try { 608 saveImageAs(filetype); 609 } 610 catch (Exception ex) { 611 shell.getDisplay().beep(); 612 Tools.showError(shell, "Save", ex.getMessage()); 613 } 614 } 615 }); 616 617 /* 618 * ImageIO does not support tiff by default 619 */ 620 /** 621 * item = new MenuItem(saveAsMenu, SWT.PUSH); item.setText("TIFF"); item.addSelectionListener(new 622 * SelectionAdapter() { public void widgetSelected(SelectionEvent e) { String filetype = 623 * Tools.FILE_TYPE_TIFF; 624 * 625 * try { saveImageAs(filetype); } catch (Exception ex) { shell.getDisplay().beep(); 626 * Tools.showError(shell, "Save", ex.getMessage()); } } }); 627 */ 628 629 item = new MenuItem(saveAsMenu, SWT.PUSH); 630 item.setText("PNG"); 631 item.addSelectionListener(new SelectionAdapter() { 632 @Override 633 public void widgetSelected(SelectionEvent e) { 634 String filetype = Tools.FILE_TYPE_PNG; 635 636 try { 637 saveImageAs(filetype); 638 } 639 catch (Exception ex) { 640 Tools.showError(shell, "Save", ex.getMessage()); 641 } 642 } 643 }); 644 645 item = new MenuItem(saveAsMenu, SWT.PUSH); 646 item.setText("GIF"); 647 item.addSelectionListener(new SelectionAdapter() { 648 @Override 649 public void widgetSelected(SelectionEvent e) { 650 String filetype = Tools.FILE_TYPE_GIF; 651 652 try { 653 saveImageAs(filetype); 654 } 655 catch (Exception ex) { 656 Tools.showError(shell, "Save", ex.getMessage()); 657 } 658 } 659 }); 660 661 item = new MenuItem(saveAsMenu, SWT.PUSH); 662 item.setText("BMP"); 663 item.addSelectionListener(new SelectionAdapter() { 664 @Override 665 public void widgetSelected(SelectionEvent e) { 666 String filetype = Tools.FILE_TYPE_BMP; 667 668 try { 669 saveImageAs(filetype); 670 } 671 catch (Exception ex) { 672 Tools.showError(shell, "Save", ex.getMessage()); 673 } 674 } 675 }); 676 677 new MenuItem(menu, SWT.SEPARATOR); 678 679 item = new MenuItem(menu, SWT.PUSH); 680 item.setText("Write Selection to Image"); 681 item.setEnabled(!dataset.getFileFormat().isReadOnly()); 682 item.addSelectionListener(new SelectionAdapter() { 683 @Override 684 public void widgetSelected(SelectionEvent e) { 685 writeSelectionToImage(); 686 } 687 }); 688 689 rotateRelatedItems.add(item); 690 691 new MenuItem(menu, SWT.SEPARATOR); 692 693 item = new MenuItem(menu, SWT.PUSH); 694 item.setText("Change Palette"); 695 item.setEnabled(!isTrueColor); 696 item.addSelectionListener(new SelectionAdapter() { 697 @Override 698 public void widgetSelected(SelectionEvent e) { 699 showColorTable(); 700 } 701 }); 702 703 item = new MenuItem(menu, SWT.PUSH); 704 item.setText("Import Palette"); 705 item.setEnabled(!isTrueColor); 706 item.addSelectionListener(new SelectionAdapter() { 707 @Override 708 public void widgetSelected(SelectionEvent e) { 709 FileDialog fChooser = new FileDialog(shell, SWT.OPEN); 710 fChooser.setFilterPath(ViewProperties.getWorkDir()); 711 712 fChooser.setFilterExtensions(new String[] {"*"}); 713 fChooser.setFilterNames(new String[] {"All Files"}); 714 fChooser.setFilterIndex(0); 715 716 if(fChooser.open() == null) { 717 return; 718 } 719 720 File chosenFile = new File(fChooser.getFilterPath() + File.separator + fChooser.getFileName()); 721 if(chosenFile == null || !chosenFile.exists() || chosenFile.isDirectory()) { 722 return; 723 } 724 725 ArrayList<String> palList = (ArrayList<String>) ViewProperties.getPaletteList(); 726 String palPath = chosenFile.getAbsolutePath(); 727 if (!palList.contains(palPath)) 728 palList.add(palPath); 729 } 730 }); 731 732 item = new MenuItem(menu, SWT.PUSH); 733 item.setText("Export Palette"); 734 item.setEnabled(!isTrueColor); 735 item.addSelectionListener(new SelectionAdapter() { 736 @Override 737 public void widgetSelected(SelectionEvent e) { 738 if (imagePalette == null) return; 739 740 String workDir = ViewProperties.getWorkDir() + File.separator; 741 FileDialog fChooser = new FileDialog(shell, SWT.OPEN); 742 fChooser.setFilterPath(workDir); 743 744 fChooser.setFilterExtensions(new String[] {"*", "*.lut"}); 745 fChooser.setFilterNames(new String[] {"All Files", "Color Lookup Table"}); 746 fChooser.setFilterIndex(1); 747 748 File pfile = Tools.checkNewFile(workDir, ".lut"); 749 750 fChooser.setFileName(pfile.getName()); 751 752 if (fChooser.open() == null) { 753 return; 754 } 755 756 File chosenFile = new File(fChooser.getFilterPath() + File.separator + fChooser.getFileName()); 757 if (chosenFile == null || chosenFile.isDirectory()) { 758 return; 759 } 760 761 if (chosenFile.exists()) { 762 int answer = SWT.NO; 763 if(Tools.showConfirm(shell, "Export", "File exists. Do you want to replace it ?")) 764 answer = SWT.YES; 765 766 if (answer == SWT.NO) return; 767 } 768 769 PrintWriter out = null; 770 771 try { 772 out = new PrintWriter(new BufferedWriter(new FileWriter(chosenFile))); 773 } 774 catch (Exception ex) { 775 out = null; 776 } 777 778 if (out == null) return; 779 780 int cols = 3; 781 int rows = 256; 782 int rgb = 0; 783 for (int i=0; i<rows; i++) { 784 out.print(i); 785 for (int j=0; j<cols; j++) { 786 out.print(' '); 787 rgb = imagePalette[j][i]; 788 if (rgb<0) rgb += 256; 789 out.print(rgb); 790 } 791 out.println(); 792 } 793 794 out.flush(); 795 out.close(); 796 } 797 }); 798 799 new MenuItem(menu, SWT.SEPARATOR); 800 801 item = new MenuItem(menu, SWT.PUSH); 802 item.setText("Set Value Range"); 803 item.setEnabled(!isTrueColor); 804 item.addSelectionListener(new SelectionAdapter() { 805 @Override 806 public void widgetSelected(SelectionEvent e) { 807 if (originalRange == null || originalRange[0] == originalRange[1]) return; 808 809 // Call only once 810 if (dataDist == null) { 811 dataDist = new int[256]; 812 Tools.findDataDist(data, dataDist, originalRange); 813 } 814 815 DataRangeDialog drd = new DataRangeDialog(shell, SWT.NONE, dataRange, originalRange, dataDist); 816 drd.open(); 817 818 double[] drange = drd.getRange(); 819 820 if ((drange == null) 821 || (drange[0] == drange[1]) 822 || ((drange[0] == dataRange[0]) && (drange[1] == dataRange[1]))) { 823 return; 824 } 825 826 applyDataRange(drange); 827 } 828 }); 829 830 new MenuItem(menu, SWT.SEPARATOR); 831 832 item = new MenuItem(menu, SWT.PUSH); 833 item.setText("Show Histogram"); 834 item.setEnabled(!isTrueColor); 835 item.addSelectionListener(new SelectionAdapter() { 836 @Override 837 public void widgetSelected(SelectionEvent e) { 838 showHistogram(); 839 } 840 }); 841 rotateRelatedItems.add(item); 842 843 new MenuItem(menu, SWT.SEPARATOR); 844 845 item = new MenuItem(menu, SWT.PUSH); 846 item.setText("Zoom In"); 847 item.addSelectionListener(new SelectionAdapter() { 848 @Override 849 public void widgetSelected(SelectionEvent e) { 850 zoomIn(); 851 } 852 }); 853 854 item = new MenuItem(menu, SWT.PUSH); 855 item.setText("Zoom Out"); 856 item.addSelectionListener(new SelectionAdapter() { 857 @Override 858 public void widgetSelected(SelectionEvent e) { 859 zoomOut(); 860 } 861 }); 862 863 new MenuItem(menu, SWT.SEPARATOR); 864 865 item = new MenuItem(menu, SWT.CASCADE); 866 item.setText("Flip Image"); 867 868 Menu flipMenu = new Menu(item); 869 item.setMenu(flipMenu); 870 871 item = new MenuItem(flipMenu, SWT.PUSH); 872 item.setText("Horizontal"); 873 item.addSelectionListener(new SelectionAdapter() { 874 @Override 875 public void widgetSelected(SelectionEvent e) { 876 flip(FLIP_HORIZONTAL); 877 } 878 }); 879 880 item = new MenuItem(flipMenu, SWT.PUSH); 881 item.setText("Vertical"); 882 item.addSelectionListener(new SelectionAdapter() { 883 @Override 884 public void widgetSelected(SelectionEvent e) { 885 flip(FLIP_VERTICAL); 886 } 887 }); 888 889 item = new MenuItem(menu, SWT.CASCADE); 890 item.setText("Rotate Image"); 891 892 Menu rotateMenu = new Menu(item); 893 item.setMenu(rotateMenu); 894 895 char t = 186; 896 897 item = new MenuItem(rotateMenu, SWT.PUSH); 898 item.setText("90" + t + " CW"); 899 item.addSelectionListener(new SelectionAdapter() { 900 @Override 901 public void widgetSelected(SelectionEvent e) { 902 rotate(ROTATE_CW_90); 903 904 int n = rotateRelatedItems.size(); 905 for (int i = 0; i < n; i++) { 906 boolean itemState = (rotateCount == 0); 907 ((MenuItem) rotateRelatedItems.get(i)).setEnabled(itemState); 908 } 909 } 910 }); 911 912 item = new MenuItem(rotateMenu, SWT.PUSH); 913 item.setText("90" + t + " CCW"); 914 item.addSelectionListener(new SelectionAdapter() { 915 @Override 916 public void widgetSelected(SelectionEvent e) { 917 rotate(ROTATE_CCW_90); 918 919 int n = rotateRelatedItems.size(); 920 for (int i = 0; i < n; i++) { 921 boolean itemState = (rotateCount == 0); 922 ((MenuItem) rotateRelatedItems.get(i)).setEnabled(itemState); 923 } 924 } 925 }); 926 927 new MenuItem(menu, SWT.SEPARATOR); 928 929 item = new MenuItem(menu, SWT.PUSH); 930 item.setText("Brightness/Contrast"); 931 item.addSelectionListener(new SelectionAdapter() { 932 @Override 933 public void widgetSelected(SelectionEvent e) { 934 if (contrastSlider == null) { 935 contrastSlider = new ContrastSlider(shell, SWT.NONE, image.getSource()); 936 } 937 938 contrastSlider.open(); 939 } 940 }); 941 942 item = new MenuItem(menu, SWT.CASCADE); 943 item.setText("Contour"); 944 945 Menu contourMenu = new Menu(item); 946 item.setMenu(contourMenu); 947 948 for (int i = 3; i < 10; i += 2) { 949 item = new MenuItem(contourMenu, SWT.PUSH); 950 item.setText(String.valueOf(i)); 951 item.addSelectionListener(new SelectionAdapter() { 952 @Override 953 public void widgetSelected(SelectionEvent e) { 954 MenuItem item = (MenuItem) e.widget; 955 contour(Integer.parseInt(item.getText())); 956 } 957 }); 958 } 959 960 new MenuItem(menu, SWT.SEPARATOR); 961 962 item = new MenuItem(menu, SWT.PUSH); 963 item.setText("Show Animation"); 964 item.setEnabled(is3D); 965 item.addSelectionListener(new SelectionAdapter() { 966 @Override 967 public void widgetSelected(SelectionEvent e) { 968 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 969 970 new Animation(shell, SWT.DOUBLE_BUFFERED, dataset).open(); 971 972 shell.setCursor(null); 973 } 974 }); 975 976 item = new MenuItem(menu, SWT.CASCADE); 977 item.setText("Animation Speed (frames/second)"); 978 item.setEnabled(is3D); 979 980 Menu animationSpeedMenu = new Menu(item); 981 item.setMenu(animationSpeedMenu); 982 983 for (int i = 2; i < 12; i += 2) { 984 item = new MenuItem(animationSpeedMenu, SWT.PUSH); 985 item.setText(String.valueOf(i)); 986 item.addSelectionListener(new SelectionAdapter() { 987 @Override 988 public void widgetSelected(SelectionEvent e) { 989 MenuItem item = (MenuItem) e.widget; 990 animationSpeed = Integer.parseInt(item.getText()); 991 } 992 }); 993 } 994 995 new MenuItem(menu, SWT.SEPARATOR); 996 997 item = new MenuItem(menu, SWT.CHECK); 998 item.setText("Show Values"); 999 item.setSelection(showValues); 1000 item.addSelectionListener(new SelectionAdapter() { 1001 @Override 1002 public void widgetSelected(SelectionEvent e) { 1003 showValues = !showValues; 1004 setValueVisible(showValues); 1005 } 1006 }); 1007 rotateRelatedItems.add(item); 1008 1009 item = new MenuItem(menu, SWT.PUSH); 1010 item.setText("Show Statistics"); 1011 item.addSelectionListener(new SelectionAdapter() { 1012 @Override 1013 public void widgetSelected(SelectionEvent e) { 1014 try { 1015 double[] minmax = new double[2]; 1016 double[] stat = new double[2]; 1017 1018 Object theData = null; 1019 theData = getSelectedData(); 1020 1021 if (theData == null) { 1022 theData = data; 1023 } 1024 1025 Tools.findMinMax(theData, minmax, dataset.getFillValue()); 1026 if (Tools.computeStatistics(theData, stat, dataset.getFillValue()) > 0) { 1027 String statistics = "Min = " 1028 + minmax[0] + "\nMax = " 1029 + minmax[1] + "\nMean = " 1030 + stat[0] + "\nStandard deviation = " + stat[1]; 1031 1032 Tools.showInformation(shell, "Statistics", statistics); 1033 } 1034 } 1035 catch (Exception ex) { 1036 shell.getDisplay().beep(); 1037 Tools.showError(shell, "Statistics", ex.getMessage()); 1038 } 1039 } 1040 }); 1041 1042 new MenuItem(menu, SWT.SEPARATOR); 1043 1044 item = new MenuItem(menu, SWT.PUSH); 1045 item.setText("Select All"); 1046 item.addSelectionListener(new SelectionAdapter() { 1047 @Override 1048 public void widgetSelected(SelectionEvent e) { 1049 try { 1050 selectAll(); 1051 } 1052 catch (Exception ex) { 1053 shell.getDisplay().beep(); 1054 Tools.showError(shell, "Select", ex.getMessage()); 1055 } 1056 } 1057 }); 1058 1059 new MenuItem(menu, SWT.SEPARATOR); 1060 1061 item = new MenuItem(menu, SWT.PUSH); 1062 item.setText("Close"); 1063 item.addSelectionListener(new SelectionAdapter() { 1064 @Override 1065 public void widgetSelected(SelectionEvent e) { 1066 shell.dispose(); 1067 } 1068 }); 1069 1070 return menuBar; 1071 } 1072 1073 private ToolBar createToolbar(final Shell shell) { 1074 ToolBar toolbar = new ToolBar(shell, SWT.HORIZONTAL | SWT.RIGHT | SWT.BORDER); 1075 toolbar.setFont(curFont); 1076 toolbar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 1077 1078 // Chart button 1079 ToolItem item = new ToolItem(toolbar, SWT.PUSH); 1080 item.setImage(ViewProperties.getChartIcon()); 1081 item.setToolTipText("Histogram"); 1082 item.setEnabled(!isTrueColor); 1083 item.addSelectionListener(new SelectionAdapter() { 1084 @Override 1085 public void widgetSelected(SelectionEvent e) { 1086 showHistogram(); 1087 } 1088 }); 1089 1090 // Palette button 1091 item = new ToolItem(toolbar, SWT.PUSH); 1092 item.setImage(ViewProperties.getPaletteIcon()); 1093 item.setToolTipText("Palette"); 1094 item.setEnabled(!isTrueColor); 1095 item.addSelectionListener(new SelectionAdapter() { 1096 @Override 1097 public void widgetSelected(SelectionEvent e) { 1098 showColorTable(); 1099 } 1100 }); 1101 1102 // Brightness button 1103 item = new ToolItem(toolbar, SWT.PUSH); 1104 item.setImage(ViewProperties.getBrightIcon()); 1105 item.setToolTipText("Brightness"); 1106 item.addSelectionListener(new SelectionAdapter() { 1107 @Override 1108 public void widgetSelected(SelectionEvent e) { 1109 if (contrastSlider == null) { 1110 contrastSlider = new ContrastSlider(shell, SWT.NONE, image.getSource()); 1111 } 1112 1113 contrastSlider.open(); 1114 } 1115 }); 1116 1117 // Zoom in button 1118 item = new ToolItem(toolbar, SWT.PUSH); 1119 item.setImage(ViewProperties.getZoominIcon()); 1120 item.setToolTipText("Zoom In"); 1121 item.addSelectionListener(new SelectionAdapter() { 1122 @Override 1123 public void widgetSelected(SelectionEvent e) { 1124 zoomIn(); 1125 } 1126 }); 1127 1128 // Zoom out button 1129 item = new ToolItem(toolbar, SWT.PUSH); 1130 item.setImage(ViewProperties.getZoomoutIcon()); 1131 item.setToolTipText("Zoom Out"); 1132 item.addSelectionListener(new SelectionAdapter() { 1133 @Override 1134 public void widgetSelected(SelectionEvent e) { 1135 zoomOut(); 1136 } 1137 }); 1138 1139 if (is3D) { 1140 new ToolItem(toolbar, SWT.SEPARATOR).setWidth(20); 1141 1142 // First frame button 1143 item = new ToolItem(toolbar, SWT.PUSH); 1144 item.setImage(ViewProperties.getFirstIcon()); 1145 item.setToolTipText("First Page"); 1146 item.addSelectionListener(new SelectionAdapter() { 1147 @Override 1148 public void widgetSelected(SelectionEvent e) { 1149 try { 1150 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1151 1152 firstPage(); 1153 } finally { 1154 shell.setCursor(null); 1155 } 1156 } 1157 }); 1158 1159 // Previous frame button 1160 item = new ToolItem(toolbar, SWT.PUSH); 1161 item.setImage(ViewProperties.getPreviousIcon()); 1162 item.setToolTipText("Previous Page"); 1163 item.addSelectionListener(new SelectionAdapter() { 1164 @Override 1165 public void widgetSelected(SelectionEvent e) { 1166 try { 1167 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1168 1169 previousPage(); 1170 } finally { 1171 shell.setCursor(null); 1172 } 1173 } 1174 }); 1175 1176 ToolItem separator = new ToolItem(toolbar, SWT.SEPARATOR); 1177 1178 frameField = new Text(toolbar, SWT.SINGLE | SWT.BORDER | SWT.CENTER); 1179 frameField.setFont(curFont); 1180 frameField.setText(String.valueOf(curFrame)); 1181 frameField.addTraverseListener(new TraverseListener() { 1182 @Override 1183 public void keyTraversed(TraverseEvent e) { 1184 if (e.detail == SWT.TRAVERSE_RETURN) { 1185 try { 1186 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1187 1188 int page = 0; 1189 1190 try { 1191 page = Integer.parseInt(frameField.getText() 1192 .trim()) - indexBase; 1193 } catch (Exception ex) { 1194 page = -1; 1195 } 1196 1197 gotoPage(page); 1198 } finally { 1199 shell.setCursor(null); 1200 } 1201 } 1202 } 1203 }); 1204 1205 frameField.pack(); 1206 1207 separator.setWidth(frameField.getSize().x + 30); 1208 separator.setControl(frameField); 1209 1210 separator = new ToolItem(toolbar, SWT.SEPARATOR); 1211 1212 Text maxFrameText = new Text(toolbar, SWT.SINGLE | SWT.BORDER | SWT.CENTER); 1213 maxFrameText.setFont(curFont); 1214 maxFrameText.setText(String.valueOf(maxFrame)); 1215 maxFrameText.setEditable(false); 1216 maxFrameText.setEnabled(false); 1217 1218 maxFrameText.pack(); 1219 1220 separator.setWidth(maxFrameText.getSize().x + 30); 1221 separator.setControl(maxFrameText); 1222 1223 new ToolItem(toolbar, SWT.SEPARATOR).setWidth(10); 1224 1225 // Next frame button 1226 item = new ToolItem(toolbar, SWT.PUSH); 1227 item.setImage(ViewProperties.getNextIcon()); 1228 item.setToolTipText("Next Page"); 1229 item.addSelectionListener(new SelectionAdapter() { 1230 @Override 1231 public void widgetSelected(SelectionEvent e) { 1232 try { 1233 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1234 1235 nextPage(); 1236 } finally { 1237 shell.setCursor(null); 1238 } 1239 } 1240 }); 1241 1242 // Last frame button 1243 item = new ToolItem(toolbar, SWT.PUSH); 1244 item.setImage(ViewProperties.getLastIcon()); 1245 item.setToolTipText("Last Page"); 1246 item.addSelectionListener(new SelectionAdapter() { 1247 @Override 1248 public void widgetSelected(SelectionEvent e) { 1249 try { 1250 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1251 1252 lastPage(); 1253 } finally { 1254 shell.setCursor(null); 1255 } 1256 } 1257 }); 1258 1259 // Animation button 1260 item = new ToolItem(toolbar, SWT.PUSH); 1261 item.setImage(ViewProperties.getAnimationIcon()); 1262 item.setToolTipText("View Animation"); 1263 item.addSelectionListener(new SelectionAdapter() { 1264 @Override 1265 public void widgetSelected(SelectionEvent e) { 1266 shell.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); 1267 new Animation(shell, SWT.DOUBLE_BUFFERED, dataset).open(); 1268 shell.setCursor(null); 1269 } 1270 }); 1271 } 1272 1273 return toolbar; 1274 } 1275 1276 // Implementing DataObserver. 1277 private void previousPage() { 1278 int rank = dataset.getRank(); 1279 1280 if (rank < 3) { 1281 return; 1282 } 1283 1284 int[] selectedIndex = dataset.getSelectedIndex(); 1285 long[] selectedDims = dataset.getSelectedDims(); 1286 1287 if (selectedDims[selectedIndex[2]] > 1) { 1288 return; // it is a true color image with three color components 1289 } 1290 1291 long[] start = dataset.getStartDims(); 1292 long idx = start[selectedIndex[2]]; 1293 if (idx == 0) { 1294 return; // current page is the first page 1295 } 1296 1297 gotoPage(start[selectedIndex[2]] - 1); 1298 } 1299 1300 // Implementing DataObserver. 1301 private void nextPage() { 1302 int rank = dataset.getRank(); 1303 1304 if (rank < 3) { 1305 return; 1306 } 1307 1308 int[] selectedIndex = dataset.getSelectedIndex(); 1309 long[] selectedDims = dataset.getSelectedDims(); 1310 1311 if (selectedDims[selectedIndex[2]] > 1) { 1312 return; // it is a true color image with three color components 1313 } 1314 1315 long[] start = dataset.getStartDims(); 1316 long[] dims = dataset.getDims(); 1317 long idx = start[selectedIndex[2]]; 1318 if (idx == dims[selectedIndex[2]] - 1) { 1319 return; // current page is the last page 1320 } 1321 1322 gotoPage(start[selectedIndex[2]] + 1); 1323 } 1324 1325 // Implementing DataObserver. 1326 private void firstPage() { 1327 int rank = dataset.getRank(); 1328 1329 if (rank < 3) { 1330 return; 1331 } 1332 1333 int[] selectedIndex = dataset.getSelectedIndex(); 1334 long[] selectedDims = dataset.getSelectedDims(); 1335 1336 if (selectedDims[selectedIndex[2]] > 1) { 1337 return; // it is a true color image with three color components 1338 } 1339 1340 long[] start = dataset.getStartDims(); 1341 long idx = start[selectedIndex[2]]; 1342 if (idx == 0) { 1343 return; // current page is the first page 1344 } 1345 1346 gotoPage(0); 1347 } 1348 1349 // Implementing DataObserver. 1350 private void lastPage() { 1351 int rank = dataset.getRank(); 1352 1353 if (rank < 3) { 1354 return; 1355 } 1356 1357 int[] selectedIndex = dataset.getSelectedIndex(); 1358 long[] selectedDims = dataset.getSelectedDims(); 1359 1360 if (selectedDims[selectedIndex[2]] > 1) { 1361 return; // it is a true color image with three color components 1362 } 1363 1364 long[] start = dataset.getStartDims(); 1365 long[] dims = dataset.getDims(); 1366 long idx = start[selectedIndex[2]]; 1367 if (idx == dims[selectedIndex[2]] - 1) { 1368 return; // current page is the last page 1369 } 1370 1371 gotoPage(dims[selectedIndex[2]] - 1); 1372 } 1373 1374 @Override 1375 public Image getImage() { 1376 if (image != null) { 1377 return image; 1378 } 1379 1380 if (!dataset.isInited()) 1381 dataset.init(); 1382 1383 isTrueColor = dataset.isTrueColor(); 1384 is3D = (dataset.getRank() > 2) && !dataset.isTrueColor(); 1385 1386 try { 1387 if (isTrueColor) { 1388 getTrueColorImage(); 1389 } 1390 else { 1391 getIndexedImage(); 1392 } 1393 } 1394 catch (Exception ex) { 1395 shell.getDisplay().beep(); 1396 Tools.showError(shell, "Select", "ImageView: " + shell.getText()); 1397 return null; 1398 } 1399 1400 // set number type, ... 1401 if (data != null) { 1402 String cname = data.getClass().getName(); 1403 NT = cname.charAt(cname.lastIndexOf('[') + 1); 1404 } 1405 1406 return image; 1407 } 1408 1409 /** 1410 * @throws Exception if a failure occurred 1411 * @throws OutOfMemoryError if memory is exhausted 1412 */ 1413 private void getIndexedImage() throws Exception, OutOfMemoryError { 1414 if (imagePalette == null) 1415 imagePalette = dataset.getPalette(); 1416 1417 boolean noPalette = false; 1418 boolean isLocalFile = dataset.getFileFormat().exists(); 1419 1420 if (imagePalette == null) { 1421 noPalette = true; 1422 imagePalette = Tools.createGrayPalette(); 1423 viewer.showStatus("\nNo attached palette found, default grey palette is used to display image"); 1424 } 1425 1426 // Make sure entire dataset is not loaded when looking at 3D 1427 // datasets using the default display mode (double clicking the 1428 // data object) 1429 if (dataset.getRank() > 2) { 1430 dataset.getSelectedDims()[dataset.getSelectedIndex()[2]] = 1; 1431 } 1432 1433 data = dataset.getData(); 1434 if ((bitmask != null) && Tools.applyBitmask(data, bitmask, bitmaskOP)) { 1435 doAutoGainContrast = false; 1436 } 1437 1438 if (dataset.getDatatype().isInteger() || dataset.getDatatype().isChar()) { 1439 data = dataset.convertFromUnsignedC(); 1440 isUnsignedConverted = true; 1441 doAutoGainContrast = doAutoGainContrast || 1442 (ViewProperties.isAutoContrast() && noPalette && isLocalFile); 1443 } 1444 else 1445 doAutoGainContrast = false; 1446 1447 boolean isAutoContrastFailed = true; 1448 if (doAutoGainContrast) { 1449 isAutoContrastFailed = (!computeAutoGainImageData(gainBias, null)); 1450 } 1451 1452 long w = dataset.getWidth(); 1453 long h = dataset.getHeight(); 1454 1455 if (isAutoContrastFailed) { 1456 doAutoGainContrast = false; 1457 imageByteData = Tools.getBytes(data, dataRange, w, h, !dataset 1458 .isDefaultImageOrder(), dataset.getFilteredImageValues(), 1459 convertByteData, imageByteData, invalidValueIndex); 1460 } 1461 else if (dataRange!= null && dataRange[0]==dataRange[1]) { 1462 Tools.findMinMax(data, dataRange, null); 1463 } 1464 1465 image = createIndexedImage(imageByteData, imagePalette, w, h); 1466 } 1467 1468 /** 1469 * @throws Exception 1470 * @throws OutOfMemoryError 1471 */ 1472 private void getTrueColorImage() throws Exception, OutOfMemoryError { 1473 isPlaneInterlace = (dataset.getInterlace() == ScalarDS.INTERLACE_PLANE); 1474 1475 long[] selected = dataset.getSelectedDims(); 1476 long[] start = dataset.getStartDims(); 1477 int[] selectedIndex = dataset.getSelectedIndex(); 1478 long[] stride = dataset.getStride(); 1479 1480 if (start.length > 2) { 1481 start[selectedIndex[2]] = 0; 1482 selected[selectedIndex[2]] = 3; 1483 stride[selectedIndex[2]] = 1; 1484 } 1485 1486 // reload data 1487 dataset.clearData(); 1488 data = dataset.getData(); 1489 1490 long w = dataset.getWidth(); 1491 long h = dataset.getHeight(); 1492 1493 // converts raw data to image data 1494 imageByteData = Tools.getBytes(data, dataRange, w, h, false, dataset.getFilteredImageValues(), 1495 imageByteData); 1496 1497 image = createTrueColorImage(imageByteData, isPlaneInterlace, (int)w, (int)h); 1498 } 1499 1500 /** 1501 * Compute image data from autogain 1502 * 1503 * @param gb the gain bias 1504 * @param range the contrast range to apply 1505 * 1506 * @return true if the image buffer is converted 1507 */ 1508 private boolean computeAutoGainImageData(double[] gb, double[] range) { 1509 boolean retValue = true; 1510 1511 // data is unsigned short. Convert image byte data using auto-contrast 1512 // image algorithm 1513 1514 if (gainBias == null) { // calculate auto_gain only once 1515 gainBias = new double[2]; 1516 Tools.autoContrastCompute(data, gainBias, dataset.getDatatype().isUnsigned()); 1517 } 1518 1519 if (gb == null) 1520 gb = gainBias; 1521 1522 autoGainData = Tools.autoContrastApply(data, autoGainData, gb, range, dataset.getDatatype().isUnsigned()); 1523 1524 if (autoGainData != null) { 1525 if ((imageByteData == null) 1526 || (imageByteData.length != Array.getLength(data))) { 1527 imageByteData = new byte[Array.getLength(data)]; 1528 } 1529 retValue = (Tools.autoContrastConvertImageBuffer(autoGainData, imageByteData, true) >= 0); 1530 } 1531 else 1532 retValue = false; 1533 1534 if (gainBiasCurrent == null) 1535 gainBiasCurrent = new double[2]; 1536 1537 gainBiasCurrent[0] = gb[0]; 1538 gainBiasCurrent[1] = gb[1]; 1539 1540 return retValue; 1541 } 1542 1543 // implementing ImageObserver 1544 private void zoomIn() { 1545 if (zoomFactor >= 1) { 1546 zoomTo(zoomFactor + 1.0f); 1547 } 1548 else { 1549 zoomTo(zoomFactor + 0.125f); 1550 } 1551 } 1552 1553 // implementing ImageObserver 1554 private void zoomOut() { 1555 if (zoomFactor > 1) { 1556 zoomTo(zoomFactor - 1.0f); 1557 } 1558 else { 1559 zoomTo(zoomFactor - 0.125f); 1560 } 1561 } 1562 1563 // implementing ImageObserver 1564 private void zoomTo(float zf) { 1565 if (zf > 8) 1566 zf = 8; 1567 else if (zf < 0.125) 1568 zf = 0.125f; 1569 1570 if (zoomFactor == zf) 1571 return; // no change in zooming 1572 1573 zoomFactor = zf; 1574 1575 Dimension imageSize = new Dimension( 1576 (int) (imageComponent.originalSize.width * zoomFactor), 1577 (int) (imageComponent.originalSize.height * zoomFactor) 1578 ); 1579 1580 imageComponent.setImageSize(imageSize); 1581 imageComponent.redraw(); 1582 1583 if ((zoomFactor > 0.99) && (zoomFactor < 1.01)) { 1584 shell.setText(frameTitle); 1585 } 1586 else { 1587 shell.setText(frameTitle + " - " + 100 * zoomFactor + "%"); 1588 } 1589 } 1590 1591 // implementing ImageObserver 1592 private void showColorTable() { 1593 if (imagePalette == null) { 1594 return; 1595 } 1596 1597 DataViewFactory paletteViewFactory = null; 1598 try { 1599 paletteViewFactory = DataViewFactoryProducer.getFactory(DataViewType.PALETTE); 1600 } 1601 catch (Exception ex) { 1602 log.debug("showColorTable(): error occurred while instantiating PaletteView factory class", ex); 1603 viewer.showError("Error occurred while instantiating PaletteView factory class"); 1604 return; 1605 } 1606 1607 if (paletteViewFactory == null) { 1608 log.debug("showColorTable(): PaletteView factory is null"); 1609 return; 1610 } 1611 1612 PaletteView theView; 1613 try { 1614 theView = paletteViewFactory.getPaletteView(shell, viewer, this); 1615 1616 if (theView == null) { 1617 log.debug("showColorTable(): error occurred while instantiating PaletteView class"); 1618 viewer.showError("Error occurred while instantiating PaletteView class"); 1619 Tools.showError(shell, "Show Palette", "Error occurred while instantiating PaletteView class"); 1620 } 1621 } 1622 catch (ClassNotFoundException ex) { 1623 log.debug("showColorTable(): no suitable PaletteView class found"); 1624 viewer.showError("Unable to find suitable PaletteView class for object '" + dataset.getName() + "'"); 1625 Tools.showError(shell, "Show Palette", "Unable to find suitable PaletteView class for object '" + dataset.getName() + "'"); 1626 } 1627 } 1628 1629 private void showHistogram() { 1630 Rectangle rec = imageComponent.selectedArea; 1631 1632 if (isTrueColor) { 1633 shell.getDisplay().beep(); 1634 Tools.showError(shell, "Select", "Unsupported operation: unable to draw histogram for true color image."); 1635 return; 1636 } 1637 1638 if ((rec == null) || (rec.width <= 0) || (rec.height <= 0)) { 1639 shell.getDisplay().beep(); 1640 Tools.showError(shell, "Select", 1641 "No data for histogram.\nUse Shift+Mouse_drag to select an image area."); 1642 return; 1643 } 1644 1645 double[][] chartData = new double[1][256]; 1646 for (int i = 0; i < 256; i++) { 1647 chartData[0][i] = 0.0; 1648 } 1649 1650 // Java only allows ints for array indices, may cause an issue with a dataset of width 1651 // larger than an int 1652 int w = (int) dataset.getWidth(); 1653 int x0 = (int) (rec.x / zoomFactor); 1654 int y0 = (int) (rec.y / zoomFactor); 1655 int x = x0 + (int) (rec.width / zoomFactor); 1656 int y = y0 + (int) (rec.height / zoomFactor); 1657 int arrayIndex = 0; 1658 for (int i = y0; i < y; i++) { 1659 for (int j = x0; j < x; j++) { 1660 arrayIndex = imageByteData[i * w + j]; 1661 if (arrayIndex < 0) { 1662 arrayIndex += 256; 1663 } 1664 chartData[0][arrayIndex] += 1.0; 1665 } 1666 } 1667 1668 // Use original data range 1669 double[] xRange = originalRange; 1670 if (xRange == null || xRange[0] == xRange[1]) { 1671 xRange = new double[2]; 1672 Tools.findMinMax(data, xRange, null); 1673 } 1674 1675 Chart cv = new Chart(shell, "Histogram - " + dataset.getPath() 1676 + dataset.getName() + " - by pixel index", Chart.HISTOGRAM, 1677 chartData, xRange, null); 1678 cv.open(); 1679 } 1680 1681 /** 1682 * Selects the whole image. 1683 * 1684 * @throws Exception if a failure occurred 1685 */ 1686 private void selectAll() throws Exception { 1687 imageComponent.selectAll(); 1688 } 1689 1690 // implementing ImageObserver 1691 private void flip(int direction) { 1692 ImageFilter filter = new FlipFilter(direction); 1693 1694 if (applyImageFilter(filter)) { 1695 // toggle flip flag 1696 if (direction == FLIP_HORIZONTAL) { 1697 isHorizontalFlipped = !isHorizontalFlipped; 1698 } 1699 else { 1700 isVerticalFlipped = !isVerticalFlipped; 1701 } 1702 } 1703 } 1704 1705 // implementing ImageObserver 1706 private void rotate(int direction) { 1707 if ( !(direction == ROTATE_CW_90 || direction == ROTATE_CCW_90)) 1708 return; 1709 1710 Rotate90Filter filter = new Rotate90Filter(direction); 1711 applyImageFilter(filter); 1712 1713 if (direction == ROTATE_CW_90) { 1714 rotateCount++; 1715 if (rotateCount == 4) { 1716 rotateCount = 0; 1717 } 1718 } 1719 else { 1720 rotateCount--; 1721 if (rotateCount == -4) { 1722 rotateCount = 0; 1723 } 1724 } 1725 } 1726 1727 // implementing ImageObserver 1728 private void contour(int level) { 1729 applyImageFilter(new ContourFilter(level)); 1730 } 1731 1732 /** Apply contrast/brightness to unsigned short integer 1733 * 1734 * @param gb the gain bias 1735 * @param range the contrast range to apply 1736 */ 1737 private void applyAutoGain(double[] gb, double[] range) { 1738 if (computeAutoGainImageData(gb, range)) { 1739 long w = dataset.getWidth(); 1740 long h = dataset.getHeight(); 1741 image = createIndexedImage(imageByteData, imagePalette, w, h); 1742 imageComponent.setImage(image); 1743 zoomTo(zoomFactor); 1744 } 1745 } 1746 1747 private void setValueVisible(boolean b) { 1748 valueField.setVisible(b); 1749 1750 GridData gridData = (GridData) valueField.getLayoutData(); 1751 1752 if(!b) { 1753 gridData.exclude = true; 1754 } 1755 else { 1756 gridData.exclude = false; 1757 } 1758 1759 valueField.setLayoutData(gridData); 1760 1761 valueField.getParent().pack(); 1762 1763 shell.pack(); 1764 } 1765 1766 /** change alpha value for a given list of pixel locations 1767 * 1768 * @param img the image to adjust 1769 * @param alpha the alpha value 1770 * @param idx the list of indices to adjust 1771 * 1772 */ 1773 private void adjustAlpha(BufferedImage img, int alpha, List<Integer> idx) 1774 { 1775 if (img == null || idx.isEmpty()) 1776 return; 1777 1778 final int[] pixels = ( (DataBufferInt) img.getRaster().getDataBuffer() ).getData(); 1779 int len = pixels.length; 1780 1781 alpha = alpha << 24; 1782 for (Integer i : idx) { 1783 if (i<len) 1784 pixels[i] = alpha | (pixels[i] & 0x00ffffff); 1785 } 1786 } 1787 1788 /** 1789 * Save the image to an image file. 1790 * 1791 * @param type 1792 * the image type. 1793 * 1794 * @throws Exception 1795 * if a failure occurred 1796 */ 1797 private void saveImageAs(String type) throws Exception { 1798 if (image == null) { 1799 return; 1800 } 1801 1802 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 1803 fChooser.setFilterPath(dataset.getFileFormat().getParent()); 1804 fChooser.setOverwrite(true); 1805 1806 DefaultFileFilter filter = null; 1807 1808 if (type.equals(Tools.FILE_TYPE_JPEG)) { 1809 filter = DefaultFileFilter.getFileFilterJPEG(); 1810 } /** 1811 * else if (type.equals(Tools.FILE_TYPE_TIFF)) { filter = DefaultFileFilter.getFileFilterTIFF(); } 1812 */ 1813 else if (type.equals(Tools.FILE_TYPE_PNG)) { 1814 filter = DefaultFileFilter.getFileFilterPNG(); 1815 } 1816 else if (type.equals(Tools.FILE_TYPE_GIF)) { 1817 filter = DefaultFileFilter.getFileFilterGIF(); 1818 } 1819 else if (type.equals(Tools.FILE_TYPE_BMP)) { 1820 filter = DefaultFileFilter.getFileFilterBMP(); 1821 } 1822 1823 if (filter == null) { 1824 fChooser.setFilterExtensions(new String[] {"*"}); 1825 fChooser.setFilterNames(new String[] {"All Files"}); 1826 fChooser.setFilterIndex(0); 1827 } 1828 else { 1829 fChooser.setFilterExtensions(new String[] {"*", filter.getExtensions()}); 1830 fChooser.setFilterNames(new String[] {"All Files", filter.getDescription()}); 1831 fChooser.setFilterIndex(1); 1832 } 1833 1834 fChooser.setText("Save Current Image To " + type + " File --- " + dataset.getName()); 1835 1836 File chosenFile = new File(dataset.getName() + "." + type.toLowerCase()); 1837 fChooser.setFileName(chosenFile.getName()); 1838 1839 String filename = fChooser.open(); 1840 1841 if(filename == null) { 1842 return; 1843 } 1844 1845 chosenFile = new File(filename); 1846 1847 BufferedImage bi = null; 1848 try { 1849 bi = Tools.toBufferedImage(image); 1850 1851 // Convert JPG and BMP images to TYPE_INT_RGB so ImageIO.write succeeds 1852 if (bi.getType() == BufferedImage.TYPE_INT_ARGB && 1853 (type.equals("JPEG") || type.equals("BMP"))) { 1854 BufferedImage newImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB); 1855 Graphics g = newImage.createGraphics(); 1856 g.drawImage(bi, 0, 0, Color.BLACK, null); 1857 g.dispose(); 1858 bi = newImage; 1859 } 1860 } 1861 catch (OutOfMemoryError err) { 1862 shell.getDisplay().beep(); 1863 Tools.showError(shell, "Save", err.getMessage()); 1864 return; 1865 } 1866 1867 Tools.saveImageAs(bi, chosenFile, type); 1868 1869 viewer.showStatus("Current image saved to: " + chosenFile.getAbsolutePath()); 1870 1871 try (RandomAccessFile rf = new RandomAccessFile(chosenFile, "r")) { 1872 long size = rf.length(); 1873 viewer.showStatus("File size (bytes): " + size); 1874 } 1875 catch (Exception ex) { 1876 log.debug("File {} size:", chosenFile.getName(), ex); 1877 } 1878 } 1879 1880 // Implementing DataView. 1881 @Override 1882 public HObject getDataObject() { 1883 return dataset; 1884 } 1885 1886 @Override 1887 public byte[] getImageByteData() { 1888 return imageByteData; 1889 } 1890 1891 /** 1892 * Returns the selected data values. 1893 * 1894 * @return the selected data object. 1895 */ 1896 @Override 1897 public Object getSelectedData() { 1898 Object selectedData = null; 1899 1900 int cols = imageComponent.originalSelectedArea.width; 1901 int rows = imageComponent.originalSelectedArea.height; 1902 1903 if ((cols <= 0) || (rows <= 0)) { 1904 return null; // no data is selected 1905 } 1906 1907 int size = cols * rows; 1908 if (isTrueColor) { 1909 size *= 3; 1910 } 1911 1912 if (NT == 'B') { 1913 selectedData = new byte[size]; 1914 } 1915 else if (NT == 'S') { 1916 selectedData = new short[size]; 1917 } 1918 else if (NT == 'I') { 1919 selectedData = new int[size]; 1920 } 1921 else if (NT == 'J') { 1922 selectedData = new long[size]; 1923 } 1924 else if (NT == 'F') { 1925 selectedData = new float[size]; 1926 } 1927 else if (NT == 'D') { 1928 selectedData = new double[size]; 1929 } 1930 else { 1931 return null; 1932 } 1933 1934 int r0 = imageComponent.originalSelectedArea.y; 1935 int c0 = imageComponent.originalSelectedArea.x; 1936 int w = imageComponent.originalSize.width; 1937 int h = imageComponent.originalSize.height; 1938 1939 // transfer location to the original coordinator 1940 if (isHorizontalFlipped) { 1941 c0 = w - 1 - c0 - cols; 1942 } 1943 1944 if (isVerticalFlipped) { 1945 r0 = h - 1 - r0 - rows; 1946 } 1947 1948 int idxSrc = 0; 1949 int idxDst = 0; 1950 if (isTrueColor) { 1951 int imageSize = w * h; 1952 if (isPlaneInterlace) { 1953 for (int j = 0; j < 3; j++) { 1954 int plane = imageSize * j; 1955 for (int i = 0; i < rows; i++) { 1956 idxSrc = plane + (r0 + i) * w + c0; 1957 System.arraycopy(data, idxSrc, selectedData, idxDst, 1958 cols); 1959 idxDst += cols; 1960 } 1961 } 1962 } 1963 else { 1964 int numberOfDataPoints = cols * 3; 1965 for (int i = 0; i < rows; i++) { 1966 idxSrc = (r0 + i) * w + c0; 1967 System.arraycopy(data, idxSrc * 3, selectedData, idxDst, 1968 numberOfDataPoints); 1969 idxDst += numberOfDataPoints; 1970 } 1971 } 1972 } 1973 else { // indexed image 1974 for (int i = 0; i < rows; i++) { 1975 idxSrc = (r0 + i) * w + c0; 1976 System.arraycopy(data, idxSrc, selectedData, idxDst, cols); 1977 idxDst += cols; 1978 } 1979 } 1980 1981 return selectedData; 1982 } 1983 1984 /** 1985 * returns the selected area of the image 1986 * 1987 * @return the rectangle of the selected image area. 1988 */ 1989 @Override 1990 public Rectangle getSelectedArea() { 1991 return imageComponent.originalSelectedArea; 1992 } 1993 1994 /** @return true if the image is a truecolor image. */ 1995 @Override 1996 public boolean isTrueColor() { 1997 return isTrueColor; 1998 } 1999 2000 /** @return true if the image interlace is plance interlace. */ 2001 @Override 2002 public boolean isPlaneInterlace() { 2003 return isPlaneInterlace; 2004 } 2005 2006 @Override 2007 public void setImage(Image img) { 2008 image = img; 2009 imageComponent.setImage(img); 2010 2011 setImageDirection(); 2012 } 2013 2014 private void setImageDirection() { 2015 boolean isHF = isHorizontalFlipped; 2016 boolean isVF = isVerticalFlipped; 2017 int rc = rotateCount; 2018 2019 if (isHF || isVF || rc != 0) { 2020 isHorizontalFlipped = false; 2021 isVerticalFlipped = false; 2022 rotateCount = 0; 2023 2024 if (isHF) 2025 flip(FLIP_HORIZONTAL); 2026 2027 if (isVF) 2028 flip(FLIP_VERTICAL); 2029 2030 while (rc > 0) { 2031 rotate(ROTATE_CW_90); 2032 rc--; 2033 } 2034 2035 while (rc < 0) { 2036 rotate(ROTATE_CCW_90); 2037 rc++; 2038 } 2039 2040 } 2041 else { 2042 if (imageOrigin == Origin.LOWER_LEFT) 2043 flip(FLIP_VERTICAL); 2044 else if (imageOrigin == Origin.UPPER_RIGHT) 2045 flip(FLIP_HORIZONTAL); 2046 if (imageOrigin == Origin.LOWER_RIGHT) { 2047 rotate(ROTATE_CW_90); 2048 rotate(ROTATE_CW_90); 2049 } 2050 } 2051 2052 zoomTo(zoomFactor); 2053 } 2054 2055 @Override 2056 public byte[][] getPalette() { 2057 return imagePalette; 2058 } 2059 2060 @Override 2061 public void setPalette(byte[][] pal) { 2062 imagePalette = pal; 2063 paletteComponent.updatePalette(pal); 2064 } 2065 2066 private void gotoPage(long idx) { 2067 if (dataset.getRank() < 3 || idx == (curFrame - indexBase)) { 2068 return; 2069 } 2070 2071 long[] start = dataset.getStartDims(); 2072 int[] selectedIndex = dataset.getSelectedIndex(); 2073 long[] dims = dataset.getDims(); 2074 2075 if ((idx < 0) || (idx >= dims[selectedIndex[2]])) { 2076 shell.getDisplay().beep(); 2077 Tools.showError(shell, "Select", "Frame number must be between " + indexBase + " and " 2078 + (dims[selectedIndex[2]] - 1 + indexBase)); 2079 return; 2080 } 2081 2082 start[selectedIndex[2]] = idx; 2083 curFrame = idx + indexBase; 2084 dataset.clearData(); 2085 image = null; 2086 gainBias = null; 2087 imageComponent.setImage(getImage()); 2088 frameField.setText(String.valueOf(curFrame)); 2089 2090 isHorizontalFlipped = false; 2091 isVerticalFlipped = false; 2092 rotateCount = 0; 2093 2094 if (imageOrigin == Origin.LOWER_LEFT) 2095 flip(FLIP_VERTICAL); 2096 else if (imageOrigin == Origin.UPPER_RIGHT) 2097 flip(FLIP_HORIZONTAL); 2098 if (imageOrigin == Origin.LOWER_RIGHT) { 2099 rotate(ROTATE_CW_90); 2100 rotate(ROTATE_CW_90); 2101 } 2102 } 2103 2104 /** 2105 * Converts a given BufferedImage to ImageData for a SWT-readable Image 2106 * 2107 * @param image The BufferedImage to be converted 2108 * 2109 * @return the image object 2110 */ 2111 private org.eclipse.swt.graphics.Image convertBufferedImageToSWTImage(BufferedImage image) { 2112 if (image.getColorModel() instanceof DirectColorModel) { 2113 DirectColorModel colorModel = (DirectColorModel) image 2114 .getColorModel(); 2115 PaletteData palette = new PaletteData(colorModel.getRedMask(), 2116 colorModel.getGreenMask(), colorModel.getBlueMask()); 2117 ImageData imgData = new ImageData(image.getWidth(), 2118 image.getHeight(), colorModel.getPixelSize(), 2119 palette); 2120 2121 for (int y = 0; y < imgData.height; y++) { 2122 for (int x = 0; x < imgData.width; x++) { 2123 int rgb = image.getRGB(x, y); 2124 int pixel = palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF)); 2125 imgData.setPixel(x, y, pixel); 2126 if (colorModel.hasAlpha()) { 2127 imgData.setAlpha(x, y, (rgb >> 24) & 0xFF); 2128 } 2129 } 2130 } 2131 2132 return new org.eclipse.swt.graphics.Image(display, imgData); 2133 } 2134 else if (image.getColorModel() instanceof IndexColorModel) { 2135 IndexColorModel colorModel = (IndexColorModel) image 2136 .getColorModel(); 2137 int size = colorModel.getMapSize(); 2138 byte[] reds = new byte[size]; 2139 byte[] greens = new byte[size]; 2140 byte[] blues = new byte[size]; 2141 colorModel.getReds(reds); 2142 colorModel.getGreens(greens); 2143 colorModel.getBlues(blues); 2144 RGB[] rgbs = new RGB[size]; 2145 for (int i = 0; i < rgbs.length; i++) { 2146 rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, 2147 blues[i] & 0xFF); 2148 } 2149 PaletteData palette = new PaletteData(rgbs); 2150 ImageData imgData = new ImageData(image.getWidth(), 2151 image.getHeight(), colorModel.getPixelSize(), 2152 palette); 2153 imgData.transparentPixel = colorModel.getTransparentPixel(); 2154 WritableRaster raster = image.getRaster(); 2155 int[] pixelArray = new int[1]; 2156 for (int y = 0; y < imgData.height; y++) { 2157 for (int x = 0; x < imgData.width; x++) { 2158 raster.getPixel(x, y, pixelArray); 2159 imgData.setPixel(x, y, pixelArray[0]); 2160 } 2161 } 2162 2163 return new org.eclipse.swt.graphics.Image(display, imgData); 2164 } 2165 else if (image.getColorModel() instanceof ComponentColorModel) { 2166 ComponentColorModel colorModel = (ComponentColorModel) image.getColorModel(); 2167 //ASSUMES: 3 BYTE BGR IMAGE TYPE 2168 PaletteData palette = new PaletteData(0x0000FF, 0x00FF00,0xFF0000); 2169 ImageData imgData = new ImageData(image.getWidth(), image.getHeight(), 2170 colorModel.getPixelSize(), palette); 2171 //This is valid because we are using a 3-byte Data model with no transparent pixels 2172 imgData.transparentPixel = -1; 2173 WritableRaster raster = image.getRaster(); 2174 int[] pixelArray = new int[3]; 2175 for (int y = 0; y < imgData.height; y++) { 2176 for (int x = 0; x < imgData.width; x++) { 2177 raster.getPixel(x, y, pixelArray); 2178 int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2])); 2179 imgData.setPixel(x, y, pixel); 2180 } 2181 } 2182 return new org.eclipse.swt.graphics.Image(display, imgData); 2183 } 2184 2185 return null; 2186 } 2187 2188 /** 2189 * Creates a RGB indexed image of 256 colors. 2190 * 2191 * @param imageData 2192 * the byte array of the image data. 2193 * @param palette 2194 * the color lookup table. 2195 * @param w 2196 * the width of the image. 2197 * @param h 2198 * the height of the image. 2199 * 2200 * @return the image. 2201 */ 2202 private Image createIndexedImage(byte[] imageData, byte[][] palette, long w, long h) 2203 { 2204 bufferedImage = (BufferedImage)Tools.createIndexedImage(bufferedImage, imageData, palette, w, h); 2205 adjustAlpha(bufferedImage, 0, invalidValueIndex); 2206 2207 return bufferedImage; 2208 } 2209 2210 /** 2211 * Creates a true color image. 2212 * <p> 2213 * The data may be arranged in one of two ways: by pixel or by plane. In 2214 * both cases, the dataset will have a dataspace with three dimensions, 2215 * height, width, and components. 2216 * <p> 2217 * For HDF4, the interlace modes specify orders for the dimensions as: 2218 * 2219 * <pre> 2220 * INTERLACE_PIXEL = [width][height][pixel components] 2221 * INTERLACE_PLANE = [pixel components][width][height] 2222 * </pre> 2223 * <p> 2224 * For HDF5, the interlace modes specify orders for the dimensions as: 2225 * 2226 * <pre> 2227 * INTERLACE_PIXEL = [height][width][pixel components] 2228 * INTERLACE_PLANE = [pixel components][height][width] 2229 * </pre> 2230 * 2231 * @param imageData 2232 * the byte array of the image data. 2233 * @param planeInterlace 2234 * flag if the image is plane intelace. 2235 * @param w 2236 * the width of the image. 2237 * @param h 2238 * the height of the image. 2239 * 2240 * @return the image. 2241 */ 2242 private Image createTrueColorImage(byte[] imageData, boolean planeInterlace, 2243 int w, int h) 2244 { 2245 if (bufferedImage == null) 2246 bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 2247 2248 final int[] pixels = ( (DataBufferInt) bufferedImage.getRaster().getDataBuffer() ).getData(); 2249 int len = pixels.length; 2250 2251 int idx = 0, r = 0, g = 0, b = 0; 2252 for (int i = 0; i < h; i++) { 2253 for (int j = 0; j < w; j++) { 2254 if (planeInterlace) { 2255 r = (imageData[idx] & 0xff)<<16; 2256 g = (imageData[len + idx] & 0xff)<<8; 2257 b = (imageData[len * 2 + idx] & 0xff); 2258 } 2259 else { 2260 r = (imageData[idx * 3] & 0xff)<<16; 2261 g = (imageData[idx * 3 + 1] & 0xff)<<8; 2262 b = (imageData[idx * 3 + 2] & 0xff); 2263 } 2264 pixels[idx++] = 0xff000000 | r | g | b; 2265 } 2266 } 2267 2268 adjustAlpha(bufferedImage, 0, invalidValueIndex); 2269 2270 return bufferedImage; 2271 } 2272 2273 private boolean applyImageFilter(ImageFilter filter) { 2274 boolean status = true; 2275 ImageProducer imageProducer = image.getSource(); 2276 2277 try { 2278 image = Tools.toBufferedImage(toolkit.createImage(new FilteredImageSource(imageProducer, filter))); 2279 imageComponent.setImage(image); 2280 zoomTo(zoomFactor); 2281 } 2282 catch (Exception err) { 2283 shell.getDisplay().beep(); 2284 Tools.showError(shell, "Apply Image Filter", err.getMessage()); 2285 status = false; 2286 } 2287 2288 return status; 2289 } 2290 2291 private void applyDataRange(double[] newRange) { 2292 if (doAutoGainContrast && gainBias != null) { 2293 applyAutoGain(gainBiasCurrent, newRange); 2294 } 2295 else { 2296 long w = dataset.getWidth(); 2297 long h = dataset.getHeight(); 2298 2299 invalidValueIndex.clear(); // data range changed. need to reset 2300 2301 // invalid values 2302 imageByteData = Tools.getBytes(data, newRange, w, h, 2303 !dataset.isDefaultImageOrder(), 2304 dataset.getFilteredImageValues(), true, null, 2305 invalidValueIndex); 2306 2307 image = createIndexedImage(imageByteData, imagePalette, w, h); 2308 setImage(image); 2309 zoomTo(zoomFactor); 2310 paletteComponent.updateRange(newRange); 2311 } 2312 2313 dataRange[0] = newRange[0]; 2314 dataRange[1] = newRange[1]; 2315 } 2316 2317 private void writeSelectionToImage() { 2318 if ((getSelectedArea().width <= 0) || (getSelectedArea().height <= 0)) { 2319 Tools.showError(shell, "Select", "No data to write.\nUse Shift+Mouse_drag to select an image area."); 2320 return; 2321 } 2322 2323 TreeView treeView = viewer.getTreeView(); 2324 TreeItem item = treeView.findTreeItem(dataset); 2325 Group pGroup = (Group) item.getParentItem().getData(); 2326 HObject root = dataset.getFileFormat().getRootObject(); 2327 2328 if (root == null) return; 2329 2330 ArrayList<HObject> list = new ArrayList<>(dataset.getFileFormat().getNumberOfMembers() + 5); 2331 Iterator<HObject> it = ((Group) root).depthFirstMemberList().iterator(); 2332 2333 list.add(dataset.getFileFormat().getRootObject()); 2334 2335 while (it.hasNext()) { 2336 list.add(it.next()); 2337 } 2338 2339 NewDatasetDialog dialog = new NewDatasetDialog(shell, pGroup, list, this); 2340 dialog.open(); 2341 2342 HObject obj = dialog.getObject(); 2343 if (obj != null) { 2344 Group pgroup = dialog.getParentGroup(); 2345 try { 2346 treeView.addObject(obj, pgroup); 2347 } 2348 catch (Exception ex) { 2349 log.debug("Write selection to image: ", ex); 2350 } 2351 } 2352 2353 list.clear(); 2354 } 2355 2356 /** PaletteComponent draws the palette on the side of the image. */ 2357 private class PaletteComponent extends Canvas { 2358 2359 private org.eclipse.swt.graphics.Color[] colors = null; 2360 private double[] pixelData = null; 2361 private Dimension paintSize = null; 2362 DecimalFormat format; 2363 double[] dRange = null; 2364 2365 private PaletteComponent(Composite parent, int style, byte[][] palette, double[] range) { 2366 super(parent, style); 2367 2368 paintSize = new Dimension(25, 2); 2369 format = new DecimalFormat("0.00E0"); 2370 dRange = range; 2371 2372 if ((palette != null) && (range != null)) { 2373 double ratio = (dRange[1] - dRange[0]) / 255; 2374 2375 pixelData = new double[256]; 2376 for (int i = 0; i < 256; i++) { 2377 pixelData[i] = (dRange[0] + ratio * i); 2378 } 2379 } 2380 2381 updatePalette(palette); 2382 2383 this.addDisposeListener(new DisposeListener() { 2384 @Override 2385 public void widgetDisposed(DisposeEvent e) { 2386 // Dispose all created colors to prevent memory leak 2387 for(int i = 0; i < colors.length; i++) { 2388 if(colors[i] != null) colors[i].dispose(); 2389 } 2390 } 2391 }); 2392 2393 this.addPaintListener(new PaintListener() { 2394 @Override 2395 public void paintControl(PaintEvent e) { 2396 if ((colors == null) && (pixelData == null)) { 2397 return; 2398 } 2399 2400 GC gc = e.gc; 2401 org.eclipse.swt.graphics.Color oldBackground = gc.getBackground(); 2402 2403 for (int i = 0; i < 256; i++) { 2404 if ((colors != null) && (colors[i] != null)) 2405 gc.setBackground(colors[i]); 2406 gc.fillRectangle(0, paintSize.height * i, paintSize.width, 2407 paintSize.height); 2408 } 2409 2410 FontData[] fontData; 2411 int fontHeight = 10; 2412 2413 if (curFont != null) { 2414 fontData = curFont.getFontData(); 2415 } 2416 else { 2417 fontData = Display.getDefault().getSystemFont().getFontData(); 2418 } 2419 2420 Font newFont = new Font(display, fontData[0].getName(), fontHeight, fontData[0].getStyle()); 2421 gc.setFont(newFont); 2422 2423 gc.setBackground(oldBackground); 2424 gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); 2425 2426 int trueHeight; 2427 int i = 0; 2428 while(i < 25) { 2429 String str = format.format(pixelData[i * 10]); 2430 trueHeight = gc.textExtent(str).y; 2431 2432 gc.drawString(str, paintSize.width + 5, (trueHeight + paintSize.height + 1) * i - ((trueHeight - fontHeight) / 2)); 2433 2434 i++; 2435 } 2436 2437 String str = format.format(pixelData[255]); 2438 trueHeight = gc.textExtent(str).y; 2439 2440 gc.drawString(str, paintSize.width + 5, (trueHeight + paintSize.height + 1) * i - ((trueHeight - fontHeight) / 2)); 2441 2442 newFont.dispose(); 2443 } 2444 }); 2445 2446 GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true); 2447 gridData.widthHint = paintSize.width + 60; 2448 this.setLayoutData(gridData); 2449 } 2450 2451 private void updatePalette(byte[][] palette) { 2452 if ((palette != null) && (dRange != null)) { 2453 colors = new org.eclipse.swt.graphics.Color[256]; 2454 2455 int r, g, b; 2456 for (int i = 0; i < 256; i++) { 2457 r = palette[0][i]; 2458 if (r < 0) { 2459 r += 256; 2460 } 2461 g = palette[1][i]; 2462 if (g < 0) { 2463 g += 256; 2464 } 2465 b = palette[2][i]; 2466 if (b < 0) { 2467 b += 256; 2468 } 2469 2470 colors[i] = new org.eclipse.swt.graphics.Color(display, r, g, b); 2471 } 2472 } 2473 2474 redraw(); 2475 } 2476 2477 private void updateRange(double[] newRange) { 2478 if (newRange == null) { 2479 return; 2480 } 2481 2482 dRange = newRange; 2483 double ratio = (dRange[1] - dRange[0]) / 255; 2484 for (int i = 0; i < 256; i++) { 2485 pixelData[i] = (dRange[0] + ratio * i); 2486 } 2487 2488 redraw(); 2489 } 2490 } 2491 2492 /** ImageComponent draws the image. */ 2493 private class ImageComponent extends Canvas implements ImageObserver { 2494 2495 /* The BufferedImage is converted to an SWT Image for dislay */ 2496 private org.eclipse.swt.graphics.Image convertedImage; 2497 2498 private Dimension originalSize; 2499 private Dimension imageSize; 2500 private Point scrollDim = null; 2501 private Point startPosition; // mouse clicked position 2502 private Point currentPosition; // mouse clicked position 2503 private Rectangle selectedArea; 2504 private Rectangle originalSelectedArea; 2505 private StringBuilder strBuff; // to hold display value 2506 private int yMousePosition = 0; // the vertical position of the current mouse 2507 private ScrollBar hbar = null; 2508 private ScrollBar vbar = null; 2509 2510 public ImageComponent(Composite parent, int style, Image img) { 2511 super(parent, style); 2512 2513 convertedImage = convertBufferedImageToSWTImage((BufferedImage) img); 2514 if (convertedImage != null) 2515 imageSize = new Dimension(convertedImage.getBounds().width, convertedImage.getBounds().height); 2516 2517 originalSize = imageSize; 2518 selectedArea = new Rectangle(); 2519 originalSelectedArea = new Rectangle(); 2520 setSize(imageSize.width, imageSize.height); 2521 strBuff = new StringBuilder(); 2522 2523 this.addDisposeListener(new DisposeListener() { 2524 @Override 2525 public void widgetDisposed(DisposeEvent arg0) { 2526 if (convertedImage != null && !convertedImage.isDisposed()) 2527 convertedImage.dispose(); 2528 } 2529 }); 2530 2531 this.addMouseMoveListener(new MouseMoveListener() { 2532 @Override 2533 public void mouseMove(MouseEvent e) { 2534 currentPosition = new Point(e.x, e.y); 2535 2536 if((e.stateMask & SWT.BUTTON1) != 0) { 2537 // If a drag event has occurred, draw a selection Rectangle 2538 if((e.stateMask & SWT.SHIFT) != 0) { 2539 int x0 = Math.max(0, Math.min(startPosition.x, 2540 currentPosition.x)); 2541 int y0 = Math.max(0, Math.min(startPosition.y, 2542 currentPosition.y)); 2543 int x1 = Math.min(imageSize.width, Math.max(startPosition.x, 2544 currentPosition.x)); 2545 int y1 = Math.min(imageSize.height, Math.max(startPosition.y, 2546 currentPosition.y)); 2547 2548 int w = x1 - x0; 2549 int h = y1 - y0; 2550 2551 selectedArea.setBounds(x0, y0, w, h); 2552 double ratio = 1.0 / zoomFactor; 2553 2554 originalSelectedArea.setBounds((int) (x0 * ratio), 2555 (int) (y0 * ratio), (int) (w * ratio), 2556 (int) (h * ratio)); 2557 } 2558 else { 2559 if((hbar != null) && hbar.isVisible()) { 2560 int dx = startPosition.x - currentPosition.x; 2561 hbar.setSelection(hbar.getSelection() + dx); 2562 } 2563 2564 if((vbar != null) && vbar.isVisible()) { 2565 int dy = startPosition.y - currentPosition.y; 2566 vbar.setSelection(vbar.getSelection() + dy); 2567 } 2568 } 2569 2570 redraw(); 2571 } 2572 2573 if(showValues) { 2574 yMousePosition = e.y; 2575 showPixelValue(e.x, yMousePosition); 2576 } 2577 } 2578 }); 2579 2580 this.addMouseListener(new MouseListener() { 2581 @Override 2582 public void mouseDoubleClick(MouseEvent e) { 2583 // Intentional 2584 } 2585 2586 @Override 2587 public void mouseDown(MouseEvent e) { 2588 startPosition = new Point(e.x, e.y); 2589 2590 selectedArea.x = startPosition.x; selectedArea.y = startPosition.y; 2591 selectedArea.width = 0; selectedArea.height = 0; 2592 2593 scrollDim = imageScroller.getSize(); 2594 hbar = imageScroller.getHorizontalBar(); 2595 vbar = imageScroller.getVerticalBar(); 2596 2597 if((e.stateMask & SWT.SHIFT) != 0) { 2598 shell.setCursor(display.getSystemCursor(SWT.CURSOR_CROSS)); 2599 } else { 2600 shell.setCursor(display.getSystemCursor(SWT.CURSOR_HAND)); 2601 } 2602 } 2603 2604 @Override 2605 public void mouseUp(MouseEvent e) { 2606 shell.setCursor(null); 2607 2608 // Single mouse click 2609 if(e.count == 1) { 2610 if(startPosition.x == e.x && startPosition.y == e.y) { 2611 selectedArea.setBounds(startPosition.x, startPosition.y , 0, 0); 2612 originalSelectedArea.setBounds(startPosition.x, startPosition.y, 0, 0); 2613 } 2614 2615 startPosition = new Point(e.x, e.y); 2616 2617 if (hbar.isVisible()) { 2618 hbar.setSelection(startPosition.x - scrollDim.x / 2); 2619 } 2620 2621 if (vbar.isVisible()) { 2622 vbar.setSelection(startPosition.y - scrollDim.y / 2); 2623 } 2624 2625 redraw(); 2626 } 2627 } 2628 }); 2629 2630 this.addMouseWheelListener(new MouseWheelListener() { 2631 @Override 2632 public void mouseScrolled(MouseEvent e) { 2633 ScrollBar jb = imageScroller.getVerticalBar(); 2634 2635 jb.getSelection(); 2636 showPixelValue(e.x, yMousePosition); 2637 } 2638 }); 2639 2640 this.addPaintListener(new PaintListener() { 2641 @Override 2642 public void paintControl(PaintEvent e) { 2643 GC gc = e.gc; 2644 2645 org.eclipse.swt.graphics.Rectangle sourceBounds = convertedImage.getBounds(); 2646 2647 gc.drawImage(convertedImage, 0, 0, sourceBounds.width, sourceBounds.height, 2648 0, 0, imageSize.width, imageSize.height); 2649 2650 if ((selectedArea.width > 0) && (selectedArea.height > 0)) { 2651 gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); 2652 gc.drawRectangle(selectedArea.x, selectedArea.y, selectedArea.width, 2653 selectedArea.height); 2654 } 2655 } 2656 }); 2657 } 2658 2659 @Override 2660 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 2661 return false; 2662 } 2663 2664 /** 2665 * Create an image using multiple step bilinear, see details at 2666 * http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html 2667 * 2668 * @param img the original image to be scaled 2669 * @param targetWidth the desired width of the scaled instance 2670 * @param targetHeight the desired height of the scaled instance 2671 * @param highquality the quality desired 2672 * 2673 * @return a scaled version of the original 2674 */ 2675 private Image multiBilinear(Image img, int targetWidth, int targetHeight, boolean highquality) 2676 { 2677 Image ret = img; 2678 int w = img.getWidth(null)/2; 2679 int h = img.getHeight(null)/2; 2680 2681 // only do multiple step bilinear for down scale more than two times 2682 if (!highquality || w <=targetWidth || h <=targetHeight) 2683 return ret; 2684 2685 int type = BufferedImage.TYPE_INT_RGB; 2686 if (image instanceof BufferedImage) { 2687 BufferedImage tmp = (BufferedImage)image; 2688 if (tmp.getColorModel().hasAlpha()) 2689 type = BufferedImage.TYPE_INT_ARGB; 2690 } 2691 else { 2692 PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); 2693 ColorModel cm = pg.getColorModel(); 2694 if (cm!=null && cm.hasAlpha()) 2695 type = BufferedImage.TYPE_INT_ARGB; 2696 } 2697 2698 do { 2699 BufferedImage tmp = new BufferedImage(w, h, type); 2700 Graphics2D g2 = tmp.createGraphics(); 2701 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 2702 g2.drawImage(ret, 0, 0, w, h, null); 2703 g2.dispose(); 2704 ret = tmp; 2705 2706 w /= 2; 2707 if (w < targetWidth) { 2708 w = targetWidth; 2709 } 2710 2711 h /= 2; 2712 if (h < targetHeight) { 2713 h = targetHeight; 2714 } 2715 2716 } while (w != targetWidth || h != targetHeight); 2717 2718 return ret; 2719 } 2720 2721 private void showPixelValue(int x, int y) { 2722 if (!valueField.isVisible() || rotateCount != 0) { 2723 return; 2724 } 2725 2726 if (data == null) { 2727 return; 2728 } 2729 2730 x = (int) (x / zoomFactor); 2731 int w = originalSize.width; 2732 2733 if ((x < 0) || (x >= w)) { 2734 return; // out of image bound 2735 } 2736 2737 y = (int) (y / zoomFactor); 2738 int h = originalSize.height; 2739 if ((y < 0) || (y >= h)) { 2740 return; // out of image bound 2741 } 2742 2743 // transfer location to the original coordinator 2744 if (isHorizontalFlipped) { 2745 x = w - 1 - x; 2746 } 2747 2748 if (isVerticalFlipped) { 2749 y = h - 1 - y; 2750 } 2751 2752 strBuff.setLength(0); // reset the string buffer 2753 strBuff.append("x=") 2754 .append(x + indexBase) 2755 .append(", y=") 2756 .append(y + indexBase) 2757 .append(", value="); 2758 2759 if (isTrueColor) { 2760 int i0, i1, i2; 2761 String r, g, b; 2762 2763 if (isPlaneInterlace) { 2764 i0 = y * w + x; // index for the first plane 2765 i1 = i0 + w * h; // index for the second plane 2766 i2 = i0 + 2 * w * h; // index for the third plane 2767 } 2768 else { 2769 i0 = 3 * (y * w + x); // index for the first pixel 2770 i1 = i0 + 1; // index for the second pixel 2771 i2 = i0 + 2; // index for the third pixel 2772 } 2773 2774 if (dataset.getDatatype().isUnsigned() && !isUnsignedConverted) { 2775 r = String.valueOf(convertUnsignedPoint(i0)); 2776 g = String.valueOf(convertUnsignedPoint(i1)); 2777 b = String.valueOf(convertUnsignedPoint(i2)); 2778 } 2779 else { 2780 r = String.valueOf(Array.get(data, i0)); 2781 g = String.valueOf(Array.get(data, i1)); 2782 b = String.valueOf(Array.get(data, i2)); 2783 } 2784 2785 strBuff.append("(").append(r + ", " + g + ", " + b).append(")"); 2786 } // (isTrueColor) 2787 else { 2788 int idx; 2789 2790 if (!dataset.isDefaultImageOrder()) 2791 idx = x * h + y; 2792 else 2793 idx = y * w + x; 2794 2795 if (dataset.getDatatype().isUnsigned() && !isUnsignedConverted) { 2796 strBuff.append(convertUnsignedPoint(idx)); 2797 } 2798 else { 2799 strBuff.append(Array.get(data, idx)); 2800 } 2801 } 2802 2803 valueField.setText(strBuff.toString()); 2804 } // private void showPixelValue 2805 2806 private long convertUnsignedPoint(int idx) { 2807 long l = 0; 2808 2809 if (NT == 'B') { 2810 byte b = Array.getByte(data, idx); 2811 2812 if (b < 0) { 2813 l = (long) b + 256; 2814 } 2815 else { 2816 l = b; 2817 } 2818 } 2819 else if (NT == 'S') { 2820 short s = Array.getShort(data, idx); 2821 if (s < 0) { 2822 l = (long) s + 65536; 2823 } 2824 else { 2825 l = s; 2826 } 2827 } 2828 else if (NT == 'I') { 2829 int i = Array.getInt(data, idx); 2830 if (i < 0) { 2831 l = i + 4294967296L; 2832 } 2833 else { 2834 l = i; 2835 } 2836 } 2837 2838 return l; 2839 } 2840 2841 private void selectAll() { 2842 selectedArea.setBounds(0, 0, imageSize.width, imageSize.height); 2843 originalSelectedArea.setBounds(0, 0, originalSize.width, originalSize.height); 2844 2845 redraw(); 2846 } 2847 2848 private void setImageSize(Dimension size) { 2849 imageSize = size; 2850 setSize(imageSize.width, imageSize.height); 2851 2852 int w = selectedArea.width; 2853 int h = selectedArea.height; 2854 if ((w > 0) && (h > 0)) { 2855 // use fixed selected area to reduce the rounding error 2856 selectedArea.setBounds( 2857 (int) (originalSelectedArea.x * zoomFactor), 2858 (int) (originalSelectedArea.y * zoomFactor), 2859 (int) (originalSelectedArea.width * zoomFactor), 2860 (int) (originalSelectedArea.height * zoomFactor)); 2861 } 2862 2863 redraw(); 2864 } 2865 2866 private void setImage(Image img) { 2867 /* Make sure to dispose the old image first so resources aren't leaked */ 2868 if (convertedImage != null && !convertedImage.isDisposed()) 2869 convertedImage.dispose(); 2870 2871 convertedImage = convertBufferedImageToSWTImage((BufferedImage) img); 2872 if (convertedImage != null) 2873 imageSize = new Dimension(convertedImage.getBounds().width, convertedImage.getBounds().height); 2874 originalSize = imageSize; 2875 selectedArea.width = 0; 2876 selectedArea.height = 0; 2877 setSize(imageSize.width, imageSize.height); 2878 2879 setImageSize(new Dimension((int) (originalSize.width * zoomFactor), 2880 (int) (originalSize.height * zoomFactor))); 2881 2882 redraw(); 2883 } 2884 } 2885 2886 /** 2887 * FlipFilter creates image filter to flip image horizontally or vertically. 2888 */ 2889 public static class FlipFilter extends ImageFilter { 2890 /** flip direction */ 2891 private int direction; 2892 2893 /** pixel value */ 2894 private int[] raster = null; 2895 2896 /** width & height */ 2897 private int imageWidth; 2898 private int imageHeight; 2899 2900 /** 2901 * Constructs an image filter to flip horizontally or vertically. 2902 * <p> 2903 * 2904 * @param d 2905 * the flip direction. 2906 */ 2907 public FlipFilter(int d) { 2908 if (d < FLIP_HORIZONTAL) { 2909 d = FLIP_HORIZONTAL; 2910 } 2911 else if (d > FLIP_VERTICAL) { 2912 d = FLIP_VERTICAL; 2913 } 2914 2915 direction = d; 2916 } 2917 2918 @Override 2919 public void setDimensions(int w, int h) { 2920 imageWidth = w; 2921 imageHeight = h; 2922 2923 // specify the raster 2924 if (raster == null) { 2925 raster = new int[imageWidth * imageHeight]; 2926 } 2927 2928 consumer.setDimensions(imageWidth, imageHeight); 2929 } 2930 2931 @Override 2932 public void setPixels(int x, int y, int w, int h, ColorModel model, 2933 byte[] pixels, int off, int scansize) { 2934 int srcoff = off; 2935 int dstoff = y * imageWidth + x; 2936 for (int yc = 0; yc < h; yc++) { 2937 for (int xc = 0; xc < w; xc++) { 2938 raster[dstoff++] = model.getRGB(pixels[srcoff++] & 0xff); 2939 } 2940 2941 srcoff += (scansize - w); 2942 dstoff += (imageWidth - w); 2943 } 2944 } 2945 2946 @Override 2947 public void setPixels(int x, int y, int w, int h, ColorModel model, 2948 int[] pixels, int off, int scansize) { 2949 int srcoff = off; 2950 int dstoff = y * imageWidth + x; 2951 2952 for (int yc = 0; yc < h; yc++) { 2953 for (int xc = 0; xc < w; xc++) { 2954 raster[dstoff++] = model.getRGB(pixels[srcoff++]); 2955 } 2956 srcoff += (scansize - w); 2957 dstoff += (imageWidth - w); 2958 } 2959 } 2960 2961 @Override 2962 public void imageComplete(int status) { 2963 if ((status == IMAGEERROR) || (status == IMAGEABORTED)) { 2964 consumer.imageComplete(status); 2965 return; 2966 } 2967 2968 int[] pixels = new int[imageWidth]; 2969 for (int y = 0; y < imageHeight; y++) { 2970 if (direction == FLIP_VERTICAL) { 2971 // grab pixel values of the target line ... 2972 int pos = (imageHeight - 1 - y) * imageWidth; 2973 for (int kk = 0; kk < imageWidth; kk++) { 2974 pixels[kk] = raster[pos + kk]; 2975 } 2976 } 2977 else { 2978 int pos = y * imageWidth; 2979 for (int kk = 0; kk < imageWidth; kk++) { 2980 pixels[kk] = raster[pos + kk]; 2981 } 2982 2983 // swap the pixel values of the target line 2984 int hw = imageWidth / 2; 2985 for (int kk = 0; kk < hw; kk++) { 2986 int tmp = pixels[kk]; 2987 pixels[kk] = pixels[imageWidth - kk - 1]; 2988 pixels[imageWidth - kk - 1] = tmp; 2989 } 2990 } 2991 2992 // consumer it .... 2993 consumer.setPixels(0, y, imageWidth, 1, 2994 ColorModel.getRGBdefault(), pixels, 0, imageWidth); 2995 } // (int y = 0; y < imageHeight; y++) 2996 2997 // complete ? 2998 consumer.imageComplete(status); 2999 } 3000 } // private class FlipFilter extends ImageFilter 3001 3002 /** 3003 * Apply general brightness/contrast algorithm. For details, visit 3004 * http://www.developerfusion.co.uk/ 3005 * 3006 * The general algorithm is represented by: If Brighten = True New_Value = 3007 * Old_Value + Adjustment_Amount Else New_Value = Old_Value - 3008 * Adjustment_Amount If New_Value < Value_Minimum New_Value = Value_Minimum 3009 * If New_Value > Value_Maximum New_Value = Value_Maximum 3010 * 3011 * Contrast is a complicated operation. It is hard to formulate a 3012 * "general algorithm". Here is the closest representation 3013 * (Contrast_Value=[0, 2]): 3014 * 3015 * //Converts to a percent //[0, 1] New_Value = Old_Value / 255 3016 * 3017 * //Centers on 0 instead of .5 //[-.5, .5] New_Value -= 0.5 3018 * 3019 * //Adjusts by Contrast_Value //[-127.5, 127.5], usually [-1, 1] New_Value 3020 * *= Contrast_Value 3021 * 3022 * //Re-add .5 (un-center over 0) //[-127, 128] New_Value += 0.5 3023 * 3024 * //Re-multiply by 255 (un-convert to percent) //[-32385, 32640], usually 3025 * [0, 255] New_Value *= 255 //Clamp [0, 255] If(New_Value > 255) New_Value 3026 * = 255 If(New_Value < 0) New_Value = 0 3027 */ 3028 private class BrightnessFilter extends RGBImageFilter { 3029 // brightness level = [-200, 200] 3030 int brightLevel = 0; 3031 3032 // contrast level [0, 4] 3033 float contrastLevel = 0; 3034 3035 public BrightnessFilter(int blevel, int clevel) { 3036 if (blevel < -100) { 3037 brightLevel = -100; 3038 } 3039 else if (blevel > 100) { 3040 brightLevel = 100; 3041 } 3042 else { 3043 brightLevel = blevel; 3044 } 3045 brightLevel *= 2; 3046 3047 if (clevel < -100) { 3048 clevel = -100; 3049 } 3050 else if (clevel > 100) { 3051 clevel = 100; 3052 } 3053 3054 if (clevel > 0) { 3055 contrastLevel = (clevel / 100f + 1) * 2; 3056 } 3057 else if (clevel < 0) { 3058 contrastLevel = (clevel / 100f + 1) / 2; 3059 } 3060 else { 3061 contrastLevel = 0; 3062 } 3063 3064 canFilterIndexColorModel = true; 3065 } 3066 3067 @Override 3068 public int filterRGB(int x, int y, int rgb) { 3069 // adjust brightness first, then adjust contrast 3070 // it gives more color depth 3071 3072 if (brightLevel != 0) { 3073 int r = (rgb & 0x00ff0000) >> 16; 3074 int g = (rgb & 0x0000ff00) >> 8; 3075 int b = (rgb & 0x000000ff); 3076 3077 r += brightLevel; 3078 g += brightLevel; 3079 b += brightLevel; 3080 3081 if (r < 0) { 3082 r = 0; 3083 } 3084 if (r > 255) { 3085 r = 255; 3086 } 3087 if (g < 0) { 3088 g = 0; 3089 } 3090 if (g > 255) { 3091 g = 255; 3092 } 3093 if (b < 0) { 3094 b = 0; 3095 } 3096 if (b > 255) { 3097 b = 255; 3098 } 3099 3100 r = (r << 16) & 0x00ff0000; 3101 g = (g << 8) & 0x0000ff00; 3102 b = b & 0x000000ff; 3103 3104 rgb = ((rgb & 0xff000000) | r | g | b); 3105 } 3106 3107 if (contrastLevel > 0.000001) { // do not compare float using !=0 or 3108 // ==0 3109 int r = (rgb & 0x00ff0000) >> 16; 3110 int g = (rgb & 0x0000ff00) >> 8; 3111 int b = (rgb & 0x000000ff); 3112 3113 float f = r / 255f; 3114 f -= 0.5; 3115 f *= contrastLevel; 3116 f += 0.5; 3117 f *= 255f; 3118 if (f < 0) { 3119 f = 0; 3120 } 3121 if (f > 255) { 3122 f = 255; 3123 } 3124 r = (int) f; 3125 3126 f = g / 255f; 3127 f -= 0.5; 3128 f *= contrastLevel; 3129 f += 0.5; 3130 f *= 255f; 3131 if (f < 0) { 3132 f = 0; 3133 } 3134 if (f > 255) { 3135 f = 255; 3136 } 3137 g = (int) f; 3138 3139 f = b / 255f; 3140 f -= 0.5; 3141 f *= contrastLevel; 3142 f += 0.5; 3143 f *= 255f; 3144 if (f < 0) { 3145 f = 0; 3146 } 3147 if (f > 255) { 3148 f = 255; 3149 } 3150 b = (int) f; 3151 3152 r = (r << 16) & 0x00ff0000; 3153 g = (g << 8) & 0x0000ff00; 3154 b = b & 0x000000ff; 3155 3156 rgb = ((rgb & 0xff000000) | r | g | b); 3157 } 3158 3159 return rgb; 3160 } 3161 } 3162 3163 /** 3164 * Makes an image filter for contour. 3165 */ 3166 private class ContourFilter extends ImageFilter { 3167 // default color model 3168 private ColorModel defaultRGB; 3169 3170 // contour level 3171 int level; 3172 3173 // the table of the contour levels 3174 int[] levels; 3175 3176 // colors for drawable contour line 3177 int[] levelColors; 3178 3179 // default RGB 3180 3181 // pixel value 3182 private int[] raster = null; 3183 3184 // width & height 3185 private int imageWidth; 3186 private int imageHeight; 3187 3188 /** 3189 * Create an contour filter for a given level contouring. 3190 * 3191 * @param theLevel 3192 * the contour level. 3193 */ 3194 private ContourFilter(int theLevel) { 3195 defaultRGB = ColorModel.getRGBdefault(); 3196 3197 levelColors = new int[9]; 3198 levelColors[0] = Color.red.getRGB(); 3199 levelColors[1] = Color.green.getRGB(); 3200 levelColors[2] = Color.blue.getRGB(); 3201 levelColors[3] = Color.magenta.getRGB(); 3202 levelColors[4] = Color.orange.getRGB(); 3203 levelColors[5] = Color.cyan.getRGB(); 3204 levelColors[6] = Color.black.getRGB(); 3205 levelColors[7] = Color.pink.getRGB(); 3206 levelColors[8] = Color.yellow.getRGB(); 3207 3208 if (theLevel < 1) { 3209 theLevel = 1; 3210 } 3211 else if (theLevel > 9) { 3212 theLevel = 9; 3213 } 3214 3215 level = theLevel; 3216 levels = new int[level]; 3217 3218 int dx = 128 / level; 3219 for (int i = 0; i < level; i++) { 3220 levels[i] = (i + 1) * dx; 3221 } 3222 } 3223 3224 @Override 3225 public void setDimensions(int width, int height) { 3226 this.imageWidth = width; 3227 this.imageHeight = height; 3228 3229 // specify the raster 3230 if (raster == null) { 3231 raster = new int[imageWidth * imageHeight]; 3232 } 3233 3234 consumer.setDimensions(width, height); 3235 } 3236 3237 @Override 3238 public void setPixels(int x, int y, int w, int h, ColorModel model, 3239 byte[] pixels, int off, int scansize) { 3240 int rgb = 0; 3241 int srcoff = off; 3242 int dstoff = y * imageWidth + x; 3243 3244 for (int yc = 0; yc < h; yc++) { 3245 for (int xc = 0; xc < w; xc++) { 3246 rgb = model.getRGB(pixels[srcoff++] & 0xff); 3247 raster[dstoff++] = (((rgb >> 16) & 0xff) 3248 + ((rgb >> 8) & 0xff) + (rgb & 0xff)) / 3; 3249 } 3250 srcoff += (scansize - w); 3251 dstoff += (imageWidth - w); 3252 } 3253 3254 } 3255 3256 @Override 3257 public void setPixels(int x, int y, int w, int h, ColorModel model, 3258 int[] pixels, int off, int scansize) { 3259 int rgb = 0; 3260 int srcoff = off; 3261 int dstoff = y * imageWidth + x; 3262 3263 for (int yc = 0; yc < h; yc++) { 3264 for (int xc = 0; xc < w; xc++) { 3265 rgb = model.getRGB(pixels[srcoff++] & 0xff); 3266 raster[dstoff++] = (((rgb >> 16) & 0xff) 3267 + ((rgb >> 8) & 0xff) + (rgb & 0xff)) / 3; 3268 } 3269 3270 srcoff += (scansize - w); 3271 dstoff += (imageWidth - w); 3272 } 3273 } 3274 3275 @Override 3276 public void imageComplete(int status) { 3277 if ((status == IMAGEERROR) || (status == IMAGEABORTED)) { 3278 consumer.imageComplete(status); 3279 return; 3280 } 3281 3282 int[] pixels = new int[imageWidth * imageHeight]; 3283 for (int z = 0; z < levels.length; z++) { 3284 int currentLevel = levels[z]; 3285 int color = levelColors[z]; 3286 3287 setContourLine(raster, pixels, currentLevel, color, imageWidth, 3288 imageHeight); 3289 } 3290 3291 int[] line = new int[imageWidth]; 3292 for (int y = 0; y < imageHeight; y++) { 3293 for (int x = 0; x < imageWidth; x++) { 3294 line[x] = pixels[y * imageWidth + x]; 3295 } 3296 3297 consumer.setPixels(0, y, imageWidth, 1, defaultRGB, line, 0, 3298 imageWidth); 3299 } // (int y = 0; y < imageHeight; y++) 3300 3301 // complete ? 3302 consumer.imageComplete(status); 3303 } 3304 3305 /** 3306 * draw a contour line based on the current parameter---level, color 3307 * 3308 * @param raster 3309 * the data of the raster image. 3310 * @param pixels 3311 * the pixel value of the image. 3312 * @param level 3313 * the contour level. 3314 * @param color 3315 * the color of the contour line. 3316 * @param w 3317 * the width of the image. 3318 * @param h 3319 * the height of the image. 3320 */ 3321 private void setContourLine(int[] raster, int[] pixels, int level, 3322 int color, int w, int h) { 3323 int p = 0; // entrance point 3324 int q = p + (w * h - 1); // bottom right point 3325 int u = 0 + (w - 1); // top right point 3326 3327 // first round 3328 while (true) { 3329 while (p < u) { 3330 int rgb = raster[p]; 3331 if (rgb < level) { 3332 while ((raster[p] < level) && (p < u)) { 3333 p++; 3334 } 3335 if (raster[p] >= level) { 3336 pixels[p] = color; 3337 } 3338 } 3339 else if (rgb == level) { 3340 while ((raster[p] == level) && (p < u)) { 3341 p++; 3342 } 3343 if ((raster[p] < level) || (raster[p] > level)) { 3344 pixels[p] = color; 3345 } 3346 } 3347 else { 3348 while ((raster[p] > level) && (p < u)) { 3349 p++; 3350 } 3351 if ((raster[p] <= level)) { 3352 pixels[p] = color; 3353 } 3354 } 3355 } 3356 3357 if (u == q) { 3358 break; 3359 } 3360 else { 3361 u += w; 3362 p++; 3363 } 3364 } 3365 } 3366 3367 } // private class ContourFilter extends ImageFilter 3368 3369 public static class Rotate90Filter extends ImageFilter { 3370 private ColorModel defaultRGB = ColorModel.getRGBdefault(); 3371 3372 private double[] coord = new double[2]; 3373 3374 private int[] raster; 3375 private int xoffset; 3376 private int yoffset; 3377 private int srcW; 3378 private int srcH; 3379 private int dstW; 3380 private int dstH; 3381 private int direction; 3382 3383 public Rotate90Filter(int dir) { 3384 direction = dir; 3385 } 3386 3387 public void transform(double x, double y, double[] retcoord) { 3388 if (direction == ROTATE_CW_90) { 3389 retcoord[0] = -y; 3390 retcoord[1] = x; 3391 } 3392 else { 3393 retcoord[0] = y; 3394 retcoord[1] = -x; 3395 } 3396 } 3397 3398 public void itransform(double x, double y, double[] retcoord) { 3399 if (direction == ROTATE_CCW_90) { 3400 retcoord[0] = -y; 3401 retcoord[1] = x; 3402 } 3403 else { 3404 retcoord[0] = y; 3405 retcoord[1] = -x; 3406 } 3407 } 3408 3409 public void transformBBox(Rectangle rect) { 3410 double minx = Double.POSITIVE_INFINITY; 3411 double miny = Double.POSITIVE_INFINITY; 3412 double maxx = Double.NEGATIVE_INFINITY; 3413 double maxy = Double.NEGATIVE_INFINITY; 3414 for (int y = 0; y <= 1; y++) { 3415 for (int x = 0; x <= 1; x++) { 3416 transform((double) rect.x + x * rect.width, (double) rect.y + y * rect.height, coord); 3417 minx = Math.min(minx, coord[0]); 3418 miny = Math.min(miny, coord[1]); 3419 maxx = Math.max(maxx, coord[0]); 3420 maxy = Math.max(maxy, coord[1]); 3421 } 3422 } 3423 rect.x = (int) Math.floor(minx); 3424 rect.y = (int) Math.floor(miny); 3425 rect.width = (int) Math.ceil(maxx) - rect.x; 3426 rect.height = (int) Math.ceil(maxy) - rect.y; 3427 } 3428 3429 @Override 3430 public void setDimensions(int width, int height) { 3431 Rectangle rect = new Rectangle(0, 0, width, height); 3432 transformBBox(rect); 3433 xoffset = -rect.x; 3434 yoffset = -rect.y; 3435 srcW = width; 3436 srcH = height; 3437 dstW = rect.width; 3438 dstH = rect.height; 3439 raster = new int[srcW * srcH]; 3440 consumer.setDimensions(dstW, dstH); 3441 } 3442 3443 @Override 3444 public void setProperties(Hashtable props) { 3445 props = (Hashtable) props.clone(); 3446 Object o = props.get("filters"); 3447 if (o == null) { 3448 props.put("filters", toString()); 3449 } 3450 else if (o instanceof String) { 3451 props.put("filters", ((String) o) + toString()); 3452 } 3453 consumer.setProperties(props); 3454 } 3455 3456 @Override 3457 public void setColorModel(ColorModel model) { 3458 consumer.setColorModel(defaultRGB); 3459 } 3460 3461 @Override 3462 public void setHints(int hintflags) { 3463 consumer.setHints(TOPDOWNLEFTRIGHT | COMPLETESCANLINES | SINGLEPASS 3464 | (hintflags & SINGLEFRAME)); 3465 } 3466 3467 @Override 3468 public void setPixels(int x, int y, int w, int h, ColorModel model, 3469 byte[] pixels, int off, int scansize) { 3470 int srcoff = off; 3471 int dstoff = y * srcW + x; 3472 for (int yc = 0; yc < h; yc++) { 3473 for (int xc = 0; xc < w; xc++) { 3474 raster[dstoff++] = model.getRGB(pixels[srcoff++] & 0xff); 3475 } 3476 srcoff += (scansize - w); 3477 dstoff += (srcW - w); 3478 } 3479 } 3480 3481 @Override 3482 public void setPixels(int x, int y, int w, int h, ColorModel model, 3483 int[] pixels, int off, int scansize) { 3484 int srcoff = off; 3485 int dstoff = y * srcW + x; 3486 if (model == defaultRGB) { 3487 for (int yc = 0; yc < h; yc++) { 3488 System.arraycopy(pixels, srcoff, raster, dstoff, w); 3489 srcoff += scansize; 3490 dstoff += srcW; 3491 } 3492 } 3493 else { 3494 for (int yc = 0; yc < h; yc++) { 3495 for (int xc = 0; xc < w; xc++) { 3496 raster[dstoff++] = model.getRGB(pixels[srcoff++]); 3497 } 3498 srcoff += (scansize - w); 3499 dstoff += (srcW - w); 3500 } 3501 } 3502 } 3503 3504 @Override 3505 public void imageComplete(int status) { 3506 if ((status == IMAGEERROR) || (status == IMAGEABORTED)) { 3507 consumer.imageComplete(status); 3508 return; 3509 } 3510 int[] pixels = new int[dstW]; 3511 for (int dy = 0; dy < dstH; dy++) { 3512 itransform(0 - (double) xoffset, dy - (double) yoffset, coord); 3513 double x1 = coord[0]; 3514 double y1 = coord[1]; 3515 itransform(dstW - (double) xoffset, dy - (double) yoffset, coord); 3516 double x2 = coord[0]; 3517 double y2 = coord[1]; 3518 double xinc = (x2 - x1) / dstW; 3519 double yinc = (y2 - y1) / dstW; 3520 for (int dx = 0; dx < dstW; dx++) { 3521 int sx = (int) Math.round(x1); 3522 int sy = (int) Math.round(y1); 3523 if ((sx < 0) || (sy < 0) || (sx >= srcW) || (sy >= srcH)) { 3524 pixels[dx] = 0; 3525 } 3526 else { 3527 pixels[dx] = raster[sy * srcW + sx]; 3528 } 3529 x1 += xinc; 3530 y1 += yinc; 3531 } 3532 consumer.setPixels(0, dy, dstW, 1, defaultRGB, pixels, 0, dstW); 3533 } 3534 consumer.imageComplete(status); 3535 } 3536 } // private class RotateFilter 3537 3538 /** 3539 * Makes animation for 3D images. 3540 */ 3541 private class Animation extends Dialog { 3542 3543 private static final int MAX_ANIMATION_IMAGE_SIZE = 300; 3544 3545 /* A list of frames to display for animation */ 3546 private org.eclipse.swt.graphics.Image[] frames = null; 3547 3548 private Shell shell; 3549 private Canvas canvas; // Canvas to draw the image 3550 private int numberOfImages = 0; 3551 private int currentFrame = 0; 3552 private int sleepTime = 200; 3553 3554 public Animation(Shell parent, int style, ScalarDS dataset) { 3555 super(parent, style); 3556 3557 long[] dims = dataset.getDims(); 3558 long[] stride = dataset.getStride(); 3559 long[] start = dataset.getStartDims(); 3560 long[] selected = dataset.getSelectedDims(); 3561 int[] selectedIndex = dataset.getSelectedIndex(); 3562 int rank = dataset.getRank(); 3563 if (animationSpeed != 0) { 3564 sleepTime = 1000 / animationSpeed; 3565 } 3566 3567 // back up the start and selected size 3568 long[] tstart = new long[rank]; 3569 long[] tselected = new long[rank]; 3570 long[] tstride = new long[rank]; 3571 System.arraycopy(start, 0, tstart, 0, rank); 3572 System.arraycopy(selected, 0, tselected, 0, rank); 3573 System.arraycopy(stride, 0, tstride, 0, rank); 3574 3575 int strideN = 1; 3576 int maxSize = (int) Math.max(selected[selectedIndex[0]], 3577 selected[selectedIndex[1]]); 3578 if (maxSize > MAX_ANIMATION_IMAGE_SIZE) { 3579 strideN = (int) ((double) maxSize / (double) MAX_ANIMATION_IMAGE_SIZE + 0.5); 3580 } 3581 3582 start[selectedIndex[0]] = 0; 3583 start[selectedIndex[1]] = 0; 3584 start[selectedIndex[2]] = 0; 3585 selected[selectedIndex[0]] = dims[selectedIndex[0]] / strideN; 3586 selected[selectedIndex[1]] = dims[selectedIndex[1]] / strideN; 3587 selected[selectedIndex[2]] = 1; 3588 stride[selectedIndex[0]] = strideN; 3589 stride[selectedIndex[1]] = strideN; 3590 stride[selectedIndex[2]] = 1; 3591 3592 Object data3d = null; 3593 byte[] byteData = null; 3594 int h = (int) selected[selectedIndex[0]]; 3595 int w = (int) selected[selectedIndex[1]]; 3596 int size = w * h; 3597 3598 numberOfImages = (int) dims[selectedIndex[2]]; 3599 frames = new org.eclipse.swt.graphics.Image[numberOfImages]; 3600 3601 BufferedImage frameImage; 3602 try { 3603 for (int i = 0; i < numberOfImages; i++) { 3604 start[selectedIndex[2]] = i; 3605 3606 dataset.clearData(); 3607 try { 3608 data3d = dataset.read(); 3609 } 3610 catch (Exception err) { 3611 continue; 3612 } 3613 3614 byteData = new byte[size]; 3615 3616 byteData = Tools.getBytes(data3d, dataRange, w, h, false, dataset.getFilteredImageValues(), 3617 true, byteData); 3618 3619 frameImage = (BufferedImage) createIndexedImage(byteData, imagePalette, w, h); 3620 frames[i] = convertBufferedImageToSWTImage(frameImage); 3621 } 3622 } 3623 finally { 3624 // set back to original state 3625 System.arraycopy(tstart, 0, start, 0, rank); 3626 System.arraycopy(tselected, 0, selected, 0, rank); 3627 System.arraycopy(tstride, 0, stride, 0, rank); 3628 } 3629 } 3630 3631 public void open() { 3632 Shell parent = getParent(); 3633 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 3634 shell.setFont(curFont); 3635 shell.setText("Animation - " + dataset.getName()); 3636 shell.setImage(ViewProperties.getHdfIcon()); 3637 shell.setLayout(new GridLayout(1, true)); 3638 3639 canvas = new Canvas(shell, SWT.DOUBLE_BUFFERED); 3640 canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3641 canvas.addPaintListener(new PaintListener() { 3642 @Override 3643 public void paintControl(PaintEvent e) { 3644 GC gc = e.gc; 3645 3646 if (frames == null) return; 3647 3648 org.eclipse.swt.graphics.Rectangle canvasBounds = canvas.getBounds(); 3649 int x = ((canvasBounds.width / 2) - (frames[currentFrame].getBounds().width / 2)); 3650 int y = ((canvasBounds.height / 2) - (frames[currentFrame].getBounds().height / 2)); 3651 gc.drawImage(frames[currentFrame], x, y); 3652 3653 gc.dispose(); 3654 } 3655 }); 3656 3657 canvas.addDisposeListener(new DisposeListener() { 3658 @Override 3659 public void widgetDisposed(DisposeEvent arg0) { 3660 /* Make sure to dispose of all generated images */ 3661 for (int i = 0; i < frames.length; i++) { 3662 if (frames[i] != null && !frames[i].isDisposed()) 3663 frames[i].dispose(); 3664 } 3665 } 3666 }); 3667 3668 Button closeButton = new Button(shell, SWT.PUSH); 3669 closeButton.setFont(curFont); 3670 closeButton.setText("&Close"); 3671 closeButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3672 closeButton.addSelectionListener(new SelectionAdapter() { 3673 @Override 3674 public void widgetSelected(SelectionEvent e) { 3675 shell.dispose(); 3676 } 3677 }); 3678 3679 shell.pack(); 3680 3681 shell.setSize(MAX_ANIMATION_IMAGE_SIZE, MAX_ANIMATION_IMAGE_SIZE); 3682 3683 org.eclipse.swt.graphics.Rectangle parentBounds = parent.getBounds(); 3684 Point shellSize = shell.getSize(); 3685 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 3686 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 3687 3688 shell.open(); 3689 3690 Runnable runnable = new AnimationThread(); 3691 3692 /** 3693 * Run the animation. This method is called by class Thread. 3694 * 3695 * @see java.lang.Thread 3696 */ 3697 Display.getDefault().timerExec(sleepTime, runnable); 3698 3699 Display openDisplay = parent.getDisplay(); 3700 while(!shell.isDisposed()) { 3701 if (!openDisplay.readAndDispatch()) 3702 openDisplay.sleep(); 3703 } 3704 3705 openDisplay.timerExec(-1, runnable); 3706 } 3707 3708 private class AnimationThread implements Runnable { 3709 @Override 3710 public void run() { 3711 if ((frames == null) || (canvas == null)) { 3712 return; 3713 } 3714 3715 if (++currentFrame >= numberOfImages) 3716 currentFrame = 0; 3717 3718 canvas.redraw(); 3719 3720 Display.getCurrent().timerExec(sleepTime, this); 3721 } 3722 } 3723 } 3724 3725 private class DataRangeDialog extends Dialog { 3726 3727 private Shell shell; 3728 private Slider minSlider; 3729 private Slider maxSlider; 3730 private Text minField; 3731 private Text maxField; 3732 final int nTICKS = 10; 3733 double tickRatio = 1; 3734 final int rangeW = 500; 3735 final int rangeH = 400; 3736 double[] rangeMinMaxCurrent = { 0, 0 }; 3737 double min; 3738 double max; 3739 double minOrg; 3740 double maxOrg; 3741 final double[] minmaxPrevious = { 0, 0 }; 3742 final double[] minmaxDist = { 0, 0 }; 3743 3744 final DecimalFormat numberFormat = new DecimalFormat("#.##E0"); 3745 3746 public DataRangeDialog(Shell parent, int style, double[] minmaxCurrent, 3747 double[] minmaxOriginal, final int[] dataDist) { 3748 3749 super(parent, style); 3750 3751 Tools.findMinMax(dataDist, minmaxDist, null); 3752 3753 if ((minmaxOriginal == null) || (minmaxOriginal.length <= 1)) { 3754 minmaxCurrent[0] = 0; 3755 minmaxCurrent[1] = 255; 3756 } 3757 else { 3758 if (minmaxOriginal[0] == minmaxOriginal[1]) { 3759 Tools.findMinMax(data, minmaxOriginal, dataset.getFillValue()); 3760 } 3761 3762 minmaxCurrent[0] = minmaxOriginal[0]; 3763 minmaxCurrent[1] = minmaxOriginal[1]; 3764 } 3765 3766 minmaxPrevious[0] = min = minmaxCurrent[0]; 3767 minmaxPrevious[1] = max = minmaxCurrent[1]; 3768 minOrg = originalRange[0]; 3769 maxOrg = originalRange[1]; 3770 3771 tickRatio = (maxOrg - minOrg) / nTICKS; 3772 } 3773 3774 public void open() { 3775 Shell parent = getParent(); 3776 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 3777 shell.setFont(curFont); 3778 shell.setText("Image Value Range"); 3779 shell.setImage(ViewProperties.getHdfIcon()); 3780 shell.setLayout(new GridLayout(1, true)); 3781 3782 Canvas chartCanvas = new Canvas(shell, SWT.DOUBLE_BUFFERED); 3783 GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); 3784 gridData.widthHint = 400; 3785 gridData.heightHint = 150; 3786 chartCanvas.setLayoutData(gridData); 3787 3788 final int numberOfPoints = dataDist.length; 3789 int gap = 5; 3790 final int xgap = 2 * gap; 3791 final double xmin = originalRange[0]; 3792 final double xmax = originalRange[1]; 3793 3794 chartCanvas.addPaintListener(new PaintListener() { 3795 @Override 3796 public void paintControl(PaintEvent e) { 3797 GC gc = e.gc; 3798 3799 gc.setFont(curFont); 3800 3801 int h = rangeH / 3 - 50; 3802 int w = rangeW; 3803 int xnpoints = Math.min(10, numberOfPoints - 1); 3804 3805 // draw the X axis 3806 gc.drawLine(xgap, h, w + xgap, h); 3807 3808 // draw x labels 3809 double xp = 0; 3810 double x; 3811 double dw = (double) w / (double) xnpoints; 3812 double dx = (xmax - xmin) / xnpoints; 3813 for (int i = 0; i <= xnpoints; i++) { 3814 x = xmin + i * dx; 3815 xp = xgap + i * dw; 3816 gc.drawLine((int) xp, h, (int) xp, h - 5); 3817 gc.drawString(numberFormat.format(x), (int) xp - 5, h + 20); 3818 } 3819 3820 org.eclipse.swt.graphics.Color c = gc.getBackground(); 3821 double yp = 0; 3822 double ymin = minmaxDist[0]; 3823 double dy = minmaxDist[1] - minmaxDist[0]; 3824 if (dy <= 0) 3825 dy =1; 3826 3827 xp = xgap; 3828 3829 int barWidth = w / numberOfPoints; 3830 if (barWidth <= 0) { 3831 barWidth = 1; 3832 } 3833 dw = (double) w / (double) numberOfPoints; 3834 3835 gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)); 3836 3837 for (int j = 0; j < numberOfPoints; j++) { 3838 xp = xgap + j * dw; 3839 yp = (int) (h * (dataDist[j] - ymin) / dy); 3840 3841 gc.fillRectangle((int) xp, (int) (h - yp), barWidth, (int) yp); 3842 } 3843 3844 gc.setBackground(c); // set the color back to its default 3845 } 3846 }); 3847 3848 org.eclipse.swt.widgets.Group lowerBoundGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 3849 lowerBoundGroup.setFont(curFont); 3850 lowerBoundGroup.setText("Lower Bound"); 3851 lowerBoundGroup.setLayout(new GridLayout(1, true)); 3852 lowerBoundGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3853 3854 minField = new Text(lowerBoundGroup, SWT.SINGLE | SWT.BORDER); 3855 minField.setFont(curFont); 3856 minField.setText(String.valueOf(min)); 3857 minField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3858 minField.addModifyListener(new ModifyListener() { 3859 @Override 3860 public void modifyText(ModifyEvent e) { 3861 if (minSlider != null && minSlider.getEnabled()) { 3862 double value = Double.parseDouble(((Text) e.widget).getText()); 3863 3864 if (value > maxOrg) { 3865 value = maxOrg; 3866 minField.setText(String.valueOf(value)); 3867 } 3868 3869 minSlider.setSelection((int) ((value - minOrg) / tickRatio)); 3870 } 3871 } 3872 }); 3873 3874 minSlider = new Slider(lowerBoundGroup, SWT.HORIZONTAL); 3875 minSlider.setMinimum(0); 3876 minSlider.setMaximum(nTICKS); 3877 minSlider.setIncrement(1); 3878 minSlider.setThumb(1); 3879 minSlider.setSelection(0); 3880 minSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3881 minSlider.addSelectionListener(new SelectionAdapter() { 3882 @Override 3883 public void widgetSelected(SelectionEvent e) { 3884 double value = minSlider.getSelection(); 3885 double maxValue = maxSlider.getSelection(); 3886 if (value > maxValue) { 3887 value = maxValue; 3888 minSlider.setSelection((int) value); 3889 } 3890 3891 minField.setText(String.valueOf(value * tickRatio + minOrg)); 3892 } 3893 }); 3894 3895 3896 org.eclipse.swt.widgets.Group upperBoundGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 3897 upperBoundGroup.setFont(curFont); 3898 upperBoundGroup.setText("Upper Bound"); 3899 upperBoundGroup.setLayout(new GridLayout(1, true)); 3900 upperBoundGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 3901 3902 maxField = new Text(upperBoundGroup, SWT.SINGLE | SWT.BORDER); 3903 maxField.setFont(curFont); 3904 maxField.setText(String.valueOf(max)); 3905 maxField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3906 maxField.addModifyListener(new ModifyListener() { 3907 @Override 3908 public void modifyText(ModifyEvent e) { 3909 if (maxSlider != null && maxSlider.getEnabled()) { 3910 double value = Double.parseDouble(((Text) e.widget).getText()); 3911 3912 if (value < minOrg) { 3913 value = minOrg; 3914 maxField.setText(String.valueOf(value)); 3915 } 3916 3917 maxSlider.setSelection((int) ((value - minOrg) / tickRatio)); 3918 } 3919 } 3920 }); 3921 3922 maxSlider = new Slider(upperBoundGroup, SWT.HORIZONTAL); 3923 maxSlider.setMinimum(0); 3924 maxSlider.setMaximum(nTICKS); 3925 maxSlider.setIncrement(1); 3926 maxSlider.setThumb(1); 3927 maxSlider.setSelection(nTICKS); 3928 maxSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3929 maxSlider.addSelectionListener(new SelectionAdapter() { 3930 @Override 3931 public void widgetSelected(SelectionEvent e) { 3932 double value = maxSlider.getSelection(); 3933 double minValue = minSlider.getSelection(); 3934 if (value < minValue) { 3935 value = minValue; 3936 maxSlider.setSelection((int) value); 3937 } 3938 3939 maxField.setText(String.valueOf(value * tickRatio + minOrg)); 3940 } 3941 }); 3942 3943 3944 // Create Ok/Cancel/Apply button region 3945 Composite buttonComposite = new Composite(shell, SWT.NONE); 3946 buttonComposite.setLayout(new GridLayout(3, false)); 3947 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 3948 3949 Button okButton = new Button(buttonComposite, SWT.PUSH); 3950 okButton.setFont(curFont); 3951 okButton.setText(" &OK "); 3952 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 3953 okButton.addSelectionListener(new SelectionAdapter() { 3954 @Override 3955 public void widgetSelected(SelectionEvent e) { 3956 rangeMinMaxCurrent[0] = Double.valueOf(minField.getText()); 3957 rangeMinMaxCurrent[1] = Double.valueOf(maxField.getText()); 3958 3959 shell.dispose(); 3960 } 3961 }); 3962 3963 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 3964 cancelButton.setFont(curFont); 3965 cancelButton.setText(" &Cancel "); 3966 cancelButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 3967 cancelButton.addSelectionListener(new SelectionAdapter() { 3968 @Override 3969 public void widgetSelected(SelectionEvent e) { 3970 rangeMinMaxCurrent[0] = minmaxPrevious[0]; 3971 rangeMinMaxCurrent[1] = minmaxPrevious[1]; 3972 3973 applyDataRange(minmaxPrevious); 3974 3975 shell.dispose(); 3976 } 3977 }); 3978 3979 Button applyButton = new Button(buttonComposite, SWT.PUSH); 3980 applyButton.setFont(curFont); 3981 applyButton.setText("&Apply"); 3982 applyButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 3983 applyButton.addSelectionListener(new SelectionAdapter() { 3984 @Override 3985 public void widgetSelected(SelectionEvent e) { 3986 minmaxPrevious[0] = rangeMinMaxCurrent[0]; 3987 minmaxPrevious[1] = rangeMinMaxCurrent[1]; 3988 3989 rangeMinMaxCurrent[0] = Double.valueOf(minField.getText()); 3990 rangeMinMaxCurrent[1] = Double.valueOf(maxField.getText()); 3991 3992 applyDataRange(rangeMinMaxCurrent); 3993 rangeMinMaxCurrent[0] = rangeMinMaxCurrent[1] = 0; 3994 } 3995 }); 3996 3997 if (min == max) { 3998 minSlider.setEnabled(false); 3999 maxSlider.setEnabled(false); 4000 } 4001 4002 4003 shell.pack(); 4004 4005 shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 4006 4007 org.eclipse.swt.graphics.Rectangle parentBounds = parent.getBounds(); 4008 Point shellSize = shell.getSize(); 4009 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 4010 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 4011 4012 shell.open(); 4013 4014 Display openDisplay = parent.getDisplay(); 4015 while(!shell.isDisposed()) { 4016 if (!openDisplay.readAndDispatch()) 4017 openDisplay.sleep(); 4018 } 4019 } 4020 4021 public double[] getRange() { 4022 return rangeMinMaxCurrent; 4023 } 4024 } 4025 4026 private class ContrastSlider extends Dialog { 4027 4028 private Shell shell; 4029 private Scale brightSlider; 4030 private Scale cntrastSlider; 4031 private Text brightField; 4032 private Text contrastField; 4033 private String bLabel = "Brightness"; 4034 private String cLabel = "Contrast"; 4035 4036 ImageProducer imageProducer; 4037 double[] autoGainBias = {0, 0}; 4038 int bLevel = 0; 4039 int cLevel = 0; 4040 4041 public ContrastSlider(Shell parent, int style, ImageProducer producer) { 4042 super(parent, style); 4043 4044 imageProducer = producer; 4045 } 4046 4047 public void open() { 4048 Shell parent = getParent(); 4049 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 4050 shell.setFont(curFont); 4051 shell.setText("Brightness/Contrast"); 4052 shell.setImage(ViewProperties.getHdfIcon()); 4053 shell.setLayout(new GridLayout(1, true)); 4054 4055 if (doAutoGainContrast && gainBias!= null) { 4056 bLabel = "Bias"; 4057 cLabel = "Gain"; 4058 shell.setText(bLabel + "/" + cLabel); 4059 } 4060 4061 org.eclipse.swt.widgets.Group brightnessGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 4062 brightnessGroup.setFont(curFont); 4063 brightnessGroup.setText(bLabel + " %"); 4064 brightnessGroup.setLayout(new GridLayout(1, true)); 4065 brightnessGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 4066 4067 brightField = new Text(brightnessGroup, SWT.SINGLE | SWT.BORDER); 4068 brightField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 4069 brightField.setFont(curFont); 4070 brightField.setText(String.valueOf(bLevel)); 4071 brightField.addListener(SWT.Traverse, new Listener() { 4072 @Override 4073 public void handleEvent(Event e) { 4074 if (e.detail == SWT.TRAVERSE_RETURN) { 4075 if (brightSlider != null) { 4076 double value = Double.parseDouble(((Text) e.widget).getText()); 4077 4078 if (value > 100) { 4079 value = 100; 4080 } 4081 else if (value < -100) { 4082 value = -100; 4083 } 4084 4085 brightSlider.setSelection((int) value + 100); 4086 } 4087 } 4088 } 4089 }); 4090 4091 4092 brightSlider = new Scale(brightnessGroup, SWT.HORIZONTAL); 4093 brightSlider.setMinimum(0); 4094 brightSlider.setMaximum(200); 4095 brightSlider.setIncrement(1); 4096 brightSlider.setSelection(bLevel + 100); 4097 brightSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 4098 brightSlider.addSelectionListener(new SelectionAdapter() { 4099 @Override 4100 public void widgetSelected(SelectionEvent e) { 4101 int value = ((Scale) e.widget).getSelection(); 4102 brightField.setText(String.valueOf(value - 100)); 4103 } 4104 }); 4105 4106 4107 org.eclipse.swt.widgets.Group contrastGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 4108 contrastGroup.setFont(curFont); 4109 contrastGroup.setText(cLabel + " %"); 4110 contrastGroup.setLayout(new GridLayout(1, true)); 4111 contrastGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 4112 4113 contrastField = new Text(contrastGroup, SWT.SINGLE | SWT.BORDER); 4114 contrastField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 4115 contrastField.setFont(curFont); 4116 contrastField.setText(String.valueOf(cLevel)); 4117 contrastField.addListener(SWT.Traverse, new Listener() { 4118 @Override 4119 public void handleEvent(Event e) { 4120 if (e.detail == SWT.TRAVERSE_RETURN) { 4121 if (cntrastSlider != null) { 4122 double value = Double.parseDouble(((Text) e.widget).getText()); 4123 4124 if (value > 100) { 4125 value = 100; 4126 } 4127 else if (value < -100) { 4128 value = -100; 4129 } 4130 4131 cntrastSlider.setSelection((int) value + 100); 4132 } 4133 } 4134 } 4135 }); 4136 4137 cntrastSlider = new Scale(contrastGroup, SWT.HORIZONTAL); 4138 cntrastSlider.setMinimum(0); 4139 cntrastSlider.setMaximum(200); 4140 cntrastSlider.setIncrement(1); 4141 cntrastSlider.setSelection(cLevel + 100); 4142 cntrastSlider.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 4143 cntrastSlider.addSelectionListener(new SelectionAdapter() { 4144 @Override 4145 public void widgetSelected(SelectionEvent e) { 4146 int value = ((Scale) e.widget).getSelection(); 4147 contrastField.setText(String.valueOf(value - 100)); 4148 } 4149 }); 4150 4151 4152 // Create Ok/Cancel/Apply button region 4153 Composite buttonComposite = new Composite(shell, SWT.NONE); 4154 buttonComposite.setLayout(new GridLayout(3, false)); 4155 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 4156 4157 Button okButton = new Button(buttonComposite, SWT.PUSH); 4158 okButton.setFont(curFont); 4159 okButton.setText(" &OK "); 4160 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 4161 okButton.addSelectionListener(new SelectionAdapter() { 4162 @Override 4163 public void widgetSelected(SelectionEvent e) { 4164 int b = Integer.parseInt(brightField.getText()); 4165 int c = Integer.parseInt(contrastField.getText()); 4166 4167 applyBrightContrast(b, c); 4168 4169 bLevel = b; 4170 cLevel = c; 4171 4172 shell.dispose(); 4173 } 4174 }); 4175 4176 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 4177 cancelButton.setFont(curFont); 4178 cancelButton.setText(" &Cancel "); 4179 cancelButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 4180 cancelButton.addSelectionListener(new SelectionAdapter() { 4181 @Override 4182 public void widgetSelected(SelectionEvent e) { 4183 applyBrightContrast(bLevel, cLevel); 4184 shell.dispose(); 4185 } 4186 }); 4187 4188 Button applyButton = new Button(buttonComposite, SWT.PUSH); 4189 applyButton.setFont(curFont); 4190 applyButton.setText("&Apply"); 4191 applyButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 4192 applyButton.addSelectionListener(new SelectionAdapter() { 4193 @Override 4194 public void widgetSelected(SelectionEvent e) { 4195 int b = Integer.parseInt(brightField.getText()); 4196 int c = Integer.parseInt(contrastField.getText()); 4197 4198 applyBrightContrast(b, c); 4199 } 4200 }); 4201 4202 4203 shell.pack(); 4204 4205 shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 4206 4207 org.eclipse.swt.graphics.Rectangle parentBounds = parent.getBounds(); 4208 Point shellSize = shell.getSize(); 4209 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 4210 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 4211 4212 shell.open(); 4213 4214 Display openDisplay = parent.getDisplay(); 4215 while(!shell.isDisposed()) { 4216 if (!openDisplay.readAndDispatch()) 4217 openDisplay.sleep(); 4218 } 4219 } 4220 4221 private void applyBrightContrast(int blevel, int clevel) { 4222 // separate autogain and simple contrast process 4223 if (doAutoGainContrast && gainBias!= null) { 4224 autoGainBias[0] = gainBias[0]*(1+(clevel)/100.0); 4225 autoGainBias[1] = gainBias[1]*(1+(blevel)/100.0); 4226 applyAutoGain(autoGainBias, null); 4227 } 4228 else { 4229 ImageFilter filter = new BrightnessFilter(blevel, clevel); 4230 image = Tools.toBufferedImage(toolkit.createImage(new FilteredImageSource(imageProducer, filter))); 4231 imageComponent.setImage(image); 4232 zoomTo(zoomFactor); 4233 } 4234 } 4235 } 4236}