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