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