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