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