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