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