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.Dimension; 020import java.awt.Graphics; 021import java.awt.GridLayout; 022import java.awt.Image; 023import java.awt.Point; 024import java.awt.Toolkit; 025import java.awt.Window; 026import java.awt.event.ActionEvent; 027import java.awt.event.ActionListener; 028import java.awt.event.ItemEvent; 029import java.awt.event.ItemListener; 030import java.awt.event.KeyEvent; 031import java.awt.event.MouseEvent; 032import java.awt.event.MouseListener; 033import java.awt.event.MouseMotionListener; 034import java.awt.image.IndexColorModel; 035import java.awt.image.MemoryImageSource; 036import java.util.Vector; 037 038import javax.swing.BorderFactory; 039import javax.swing.ButtonGroup; 040import javax.swing.CellEditor; 041import javax.swing.JButton; 042import javax.swing.JComboBox; 043import javax.swing.JComponent; 044import javax.swing.JDialog; 045import javax.swing.JFrame; 046import javax.swing.JOptionPane; 047import javax.swing.JPanel; 048import javax.swing.JRadioButton; 049import javax.swing.JScrollPane; 050import javax.swing.JTable; 051import javax.swing.ListSelectionModel; 052import javax.swing.WindowConstants; 053import javax.swing.border.LineBorder; 054import javax.swing.event.ChangeEvent; 055import javax.swing.table.DefaultTableCellRenderer; 056import javax.swing.table.DefaultTableModel; 057 058import hdf.object.FileFormat; 059import hdf.object.HObject; 060import hdf.object.ScalarDS; 061 062/** 063 * To view and change palette. 064 * 065 * @author Peter X. Cao 066 * @version 2.4 9/6/2007 067 */ 068public class DefaultPaletteView extends JDialog implements PaletteView, 069 MouseListener, MouseMotionListener, ActionListener, ItemListener { 070 private static final long serialVersionUID = -5092012421988388661L; 071 private final Color[] lineColors = { Color.red, Color.green, Color.blue }; 072 private final String lineLabels[] = { "Red", "Green", "Blue" }; 073 074 private static String PALETTE_GRAY = "Gray"; 075 private static String PALETTE_DEFAULT = "Default"; 076 private static String PALETTE_REVERSE_GRAY = "Reverse Gray"; 077 private static String PALETTE_GRAY_WAVE = "GrayWave"; 078 private static String PALETTE_RAINBOW = "Rainbow"; 079 private static String PALETTE_NATURE = "Nature"; 080 private static String PALETTE_WAVE = "Wave"; 081 082 private JRadioButton checkRed, checkGreen, checkBlue; 083 /** Panel that draws plot of data values. */ 084 private ChartPanel chartP; 085 private int x0, y0; // starting point of mouse drag 086 private Image originalImage, currentImage; 087 boolean isPaletteChanged = false; 088 byte[][] palette; 089 private ScalarDS dataset; 090 private ImageView imageView; 091 private int[][] paletteData; 092 @SuppressWarnings("rawtypes") 093 private JComboBox choicePalette; 094 private PaletteValueTable paletteValueTable; 095 private int numberOfPalettes; 096 private boolean startEditing = false; 097 098 public DefaultPaletteView(ImageView theImageView) { 099 this(null, theImageView); 100 } 101 102 @SuppressWarnings({ "rawtypes", "unchecked" }) 103 public DefaultPaletteView(ViewManager theViewer, ImageView theImageView) { 104 super((JFrame) theViewer, true); 105 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 106 imageView = theImageView; 107 dataset = (ScalarDS) imageView.getDataObject(); 108 109 numberOfPalettes = 1; 110 choicePalette = new JComboBox(); 111 choicePalette.addItemListener(this); 112 113 boolean isH5 = dataset.getFileFormat().isThisType( 114 FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)); 115 116 choicePalette.addItem("Select palette"); 117 String paletteName = ((ScalarDS) dataset).getPaletteName(0); 118 119 if (paletteName!= null) 120 paletteName = paletteName.trim(); 121 122 if (paletteName!= null && paletteName.length()>0) 123 choicePalette.addItem(paletteName); 124 125 if (isH5 && (dataset instanceof ScalarDS)) { 126 byte[] palRefs = ((ScalarDS) dataset).getPaletteRefs(); 127 if ((palRefs != null) && (palRefs.length > 8)) { 128 numberOfPalettes = palRefs.length / 8; 129 } 130 } 131 for (int i = 1; i < numberOfPalettes; i++) { 132 paletteName = ((ScalarDS) dataset).getPaletteName(i); 133 choicePalette.addItem(paletteName); 134 } 135 choicePalette.addItem(PALETTE_GRAY); 136 choicePalette.addItem(PALETTE_GRAY_WAVE); 137 choicePalette.addItem(PALETTE_RAINBOW); 138 choicePalette.addItem(PALETTE_NATURE); 139 choicePalette.addItem(PALETTE_WAVE); 140 Vector<?> plist = ViewProperties.getPaletteList(); 141 int n = plist.size(); 142 for (int i = 0; i < n; i++) 143 choicePalette.addItem((String) plist.get(i)); 144 145 chartP = new ChartPanel(); 146 chartP.setBackground(Color.white); 147 148 paletteData = new int[3][256]; 149 byte[][] imagePalette = imageView.getPalette(); 150 this.setTitle("Image Palette for - " + dataset.getPath() 151 + dataset.getName()); 152 153 int d = 0; 154 for (int i = 0; i < 3; i++) { 155 for (int j = 0; j < 256; j++) { 156 d = imagePalette[i][j]; 157 if (d < 0) { 158 d += 256; 159 } 160 paletteData[i][j] = d; 161 } 162 } 163 164 imageView = theImageView; 165 chartP.addMouseListener(this); 166 chartP.addMouseMotionListener(this); 167 168 x0 = y0 = 0; 169 originalImage = currentImage = imageView.getImage(); 170 palette = new byte[3][256]; 171 172 createUI(); 173 setVisible(true); 174 } 175 176 /** returns the data object displayed in this data viewer */ 177 public HObject getDataObject() { 178 return dataset; 179 } 180 181 /** 182 * Creates and layouts GUI componentes. 183 */ 184 private void createUI() { 185 Window owner = getOwner(); 186 187 JPanel contentPane = (JPanel) getContentPane(); 188 contentPane.setLayout(new BorderLayout(5, 5)); 189 contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 190 int w = 700 + (ViewProperties.getFontSize() - 12) * 15; 191 int h = 500 + (ViewProperties.getFontSize() - 12) * 10; 192 contentPane.setPreferredSize(new Dimension(w, h)); 193 194 contentPane.add(chartP, BorderLayout.CENTER); 195 196 JButton button = new JButton(" Ok "); 197 button.addActionListener(this); 198 button.setActionCommand("Ok"); 199 JPanel buttonP = new JPanel(); 200 buttonP.setBorder(new LineBorder(Color.GRAY)); 201 buttonP.add(button); 202 button = new JButton("Cancel"); 203 button.addActionListener(this); 204 button.setActionCommand("Cancel"); 205 buttonP.add(button); 206 button = new JButton("Preview"); 207 button.addActionListener(this); 208 button.setActionCommand("Preview"); 209 buttonP.add(button); 210 211 JPanel bottomP = new JPanel(); 212 bottomP.setLayout(new BorderLayout(20, 2)); 213 bottomP.add(buttonP, BorderLayout.EAST); 214 215 checkRed = new JRadioButton("Red"); 216 checkRed.setForeground(Color.red); 217 checkGreen = new JRadioButton("Green"); 218 checkGreen.setForeground(Color.green); 219 checkBlue = new JRadioButton("Blue"); 220 checkBlue.setForeground(Color.blue); 221 checkRed.setSelected(true); 222 ButtonGroup bgroup = new ButtonGroup(); 223 bgroup.add(checkRed); 224 bgroup.add(checkGreen); 225 bgroup.add(checkBlue); 226 JPanel checkP = new JPanel(); 227 checkP.setBorder(new LineBorder(Color.GRAY)); 228 checkP.add(checkRed); 229 checkP.add(checkGreen); 230 checkP.add(checkBlue); 231 bottomP.add(checkP, BorderLayout.WEST); 232 233 JPanel valueP = new JPanel(); 234 valueP.setLayout(new GridLayout(1, 2)); 235 valueP.setBorder(new LineBorder(Color.GRAY)); 236 JButton valueButton = new JButton("Show Values"); 237 valueButton.setActionCommand("Show palette values"); 238 valueButton.addActionListener(this); 239 valueP.add(choicePalette); 240 valueP.add(valueButton); 241 bottomP.add(valueP, BorderLayout.CENTER); 242 243 contentPane.add(bottomP, BorderLayout.SOUTH); 244 245 Point l = owner.getLocation(); 246 l.x += 350; 247 l.y += 200; 248 setLocation(l); 249 pack(); 250 } 251 252 public void actionPerformed(ActionEvent e) { 253 String cmd = e.getActionCommand(); 254 255 if (cmd.equals("Ok")) { 256 if (isPaletteChanged) { 257 this.updatePalette(); 258 isPaletteChanged = false; 259 imageView.setPalette(palette); 260 imageView.setImage(currentImage); 261 } 262 super.dispose(); 263 } 264 else if (cmd.equals("Cancel")) { 265 imageView.setImage(originalImage); 266 super.dispose(); 267 } 268 else if (cmd.equals("Preview")) { 269 this.updatePalette(); 270 imageView.setImage(currentImage); 271 } 272 else if (cmd.equals("Show palette values")) { 273 if (paletteValueTable == null) { 274 paletteValueTable = new PaletteValueTable(this); 275 } 276 paletteValueTable.refresh(); 277 paletteValueTable.setVisible(true); 278 } 279 else if (cmd.equals("Hide palette values")) { 280 if (paletteValueTable != null) { 281 paletteValueTable.setVisible(false); 282 } 283 } 284 } 285 286 @Override 287 public void dispose() { 288 imageView.setImage(originalImage); 289 super.dispose(); 290 } 291 292 public void itemStateChanged(ItemEvent e) { 293 Object src = e.getSource(); 294 295 if (!src.equals(choicePalette)) { 296 return; 297 } 298 299 int idx = choicePalette.getSelectedIndex(); 300 if (idx <= 0) { 301 return; 302 } 303 304 byte[][] imagePalette = null; 305 Object item = choicePalette.getSelectedItem(); 306 307 if (item.equals(PALETTE_DEFAULT)) { 308 imagePalette = dataset.getPalette(); 309 } 310 else if (item.equals(PALETTE_GRAY)) { 311 imagePalette = Tools.createGrayPalette(); 312 } 313 else if (item.equals(PALETTE_REVERSE_GRAY)) { 314 imagePalette = Tools.createReverseGrayPalette(); 315 } 316 else if (item.equals(PALETTE_GRAY_WAVE)) { 317 imagePalette = Tools.createGrayWavePalette(); 318 } 319 else if (item.equals(PALETTE_RAINBOW)) { 320 imagePalette = Tools.createRainbowPalette(); 321 } 322 else if (item.equals(PALETTE_NATURE)) { 323 imagePalette = Tools.createNaturePalette(); 324 } 325 else if (item.equals(PALETTE_WAVE)) { 326 imagePalette = Tools.createWavePalette(); 327 } 328 else if (idx > 0 && idx <= numberOfPalettes) { 329 imagePalette = ((ScalarDS) dataset).readPalette(idx - 1); 330 } 331 else { 332 imagePalette = Tools.readPalette((String)item); 333 } 334 335 if (imagePalette == null) { 336 return; 337 } 338 339 int d = 0; 340 for (int i = 0; i < 3; i++) { 341 for (int j = 0; j < 256; j++) { 342 d = imagePalette[i][j]; 343 if (d < 0) { 344 d += 256; 345 } 346 paletteData[i][j] = d; 347 } 348 } 349 350 chartP.repaint(); 351 isPaletteChanged = true; 352 353 } 354 355 private void updatePalette() { 356 for (int i = 0; i < 256; i++) { 357 palette[0][i] = (byte) paletteData[0][i]; 358 palette[1][i] = (byte) paletteData[1][i]; 359 palette[2][i] = (byte) paletteData[2][i]; 360 } 361 362 IndexColorModel colorModel = new IndexColorModel(8, // bits - the number 363 // of bits each 364 // pixel occupies 365 256, // size - the size of the color component arrays 366 palette[0], // r - the array of red color components 367 palette[1], // g - the array of green color components 368 palette[2]); // b - the array of blue color components 369 370 int w = dataset.getWidth(); 371 int h = dataset.getHeight(); 372 MemoryImageSource memoryImageSource = null; 373 374 try { 375 memoryImageSource = (MemoryImageSource) originalImage.getSource(); 376 } 377 catch (Throwable err) { 378 memoryImageSource = null; 379 } 380 381 if (memoryImageSource == null) { 382 memoryImageSource = new MemoryImageSource(w, h, colorModel, 383 imageView.getImageByteData(), 0, w); 384 } 385 else { 386 memoryImageSource.newPixels(imageView.getImageByteData(), 387 colorModel, 0, w); 388 } 389 390 currentImage = Toolkit.getDefaultToolkit().createImage( 391 memoryImageSource); 392 } 393 394 public void mouseClicked(MouseEvent e) { 395 } // MouseListener 396 397 public void mouseReleased(MouseEvent e) { 398 if ((paletteValueTable != null) && paletteValueTable.isVisible()) { 399 paletteValueTable.refresh(); 400 } 401 } // MouseListener 402 403 public void mouseEntered(MouseEvent e) { 404 } // MouseListener 405 406 public void mouseExited(MouseEvent e) { 407 } // MouseListener 408 409 public void mouseMoved(MouseEvent e) { 410 } // MouseMotionListener 411 412 // implementing MouseListener 413 public void mousePressed(MouseEvent e) { 414 // x0 = e.getX()-40; // takes the horizontal gap 415 // if (x0 < 0) x0 = 0; 416 // y0 = e.getY()+20; 417 } 418 419 // implementing MouseMotionListener 420 public void mouseDragged(MouseEvent e) { 421 int x1 = e.getX() - 40;// takes the vertical gap 422 if (x1 < 0) { 423 x1 = 0; 424 } 425 int y1 = e.getY() + 20; 426 427 Dimension d = chartP.getSize(); 428 double ry = 255 / (double) d.height; 429 double rx = 255 / (double) d.width; 430 431 int lineIdx = 0; 432 if (checkGreen.isSelected()) { 433 lineIdx = 1; 434 } 435 else if (checkBlue.isSelected()) { 436 lineIdx = 2; 437 } 438 439 int idx = 0; 440 double b = (double) (y1 - y0) / (double) (x1 - x0); 441 double a = y0 - b * x0; 442 double value = y0 * ry; 443 int i0 = Math.min(x0, x1); 444 int i1 = Math.max(x0, x1); 445 for (int i = i0; i < i1; i++) { 446 idx = (int) (rx * i); 447 if (idx > 255) { 448 continue; 449 } 450 value = 255 - (a + b * i) * ry; 451 if (value < 0) { 452 value = 0; 453 } 454 else if (value > 255) { 455 value = 255; 456 } 457 paletteData[lineIdx][idx] = (int) value; 458 } 459 460 chartP.repaint(); 461 isPaletteChanged = true; 462 } 463 464 /** The dialog to show the palette values in spreadsheet. */ 465 private final class PaletteValueTable extends JDialog { 466 private static final long serialVersionUID = 6105012612969555535L; 467 private JTable valueTable; 468 private DefaultTableModel valueTableModel; 469 String rgbName = "Color"; 470 String idxName = "Index"; 471 int editingRow =-1, editingCol=-1; 472 473 public PaletteValueTable(DefaultPaletteView owner) { 474 super(owner); 475 String[] columnNames = { idxName, "Red", "Green", "Blue", rgbName }; 476 valueTableModel = new DefaultTableModel(columnNames, 256); 477 478 valueTable = new JTable(valueTableModel) { 479 private static final long serialVersionUID = -2823793138915014637L; 480 481 @Override 482 public boolean isCellEditable(int row, int col) { 483 return (col > 0 && col < 4); 484 } 485 486 @Override 487 public Object getValueAt(int row, int col) { 488 if (startEditing && row==editingRow && col==editingCol) 489 return ""; 490 491 if (col == 0) 492 return String.valueOf(row); 493 else if (col < 4) { 494 return String.valueOf(paletteData[col - 1][row]); 495 } 496 else { 497 return ""; 498 } 499 } 500 501 @Override 502 public boolean editCellAt(int row, int column, java.util.EventObject e) 503 { 504 if (!isCellEditable(row, column)) { 505 return super.editCellAt(row, column, e); 506 } 507 508 if (e instanceof KeyEvent) { 509 KeyEvent ke = (KeyEvent) e; 510 if (ke.getID() == KeyEvent.KEY_PRESSED) { 511 startEditing = true; 512 editingRow = row; 513 editingCol = column; 514 } 515 } 516 517 return super.editCellAt(row, column, e); 518 } 519 520 @Override 521 public void editingStopped(ChangeEvent e) { 522 int row = getEditingRow(); 523 int col = getEditingColumn(); 524 525 if (!isCellEditable(row, col)) { 526 return; 527 } 528 529 String oldValue = (String) getValueAt(row, col); 530 super.editingStopped(e); 531 startEditing = false; 532 editingRow = -1; 533 editingCol = -1; 534 535 Object source = e.getSource(); 536 537 if (source instanceof CellEditor) { 538 CellEditor editor = (CellEditor) source; 539 String newValue = (String) editor.getCellEditorValue(); 540 setValueAt(oldValue, row, col); // set back to what it 541 // is 542 updatePaletteValue(newValue, row, col - 1); 543 } 544 } 545 }; 546 547 valueTable.setName("PaletteValue"); 548 valueTable.getColumn(rgbName).setCellRenderer( 549 new DefaultTableCellRenderer() { 550 private static final long serialVersionUID = 8390954944015521331L; 551 Color color = Color.white; 552 553 @Override 554 public java.awt.Component getTableCellRendererComponent( 555 JTable table, Object value, boolean isSelected, 556 boolean hasFocus, int row, int col) { 557 java.awt.Component comp = super 558 .getTableCellRendererComponent(table, 559 value, isSelected, hasFocus, row, 560 col); 561 color = new Color(paletteData[0][row], 562 paletteData[1][row], paletteData[2][row]); 563 comp.setBackground(color); 564 return comp; 565 } 566 }); 567 568 valueTable.getColumn(idxName).setCellRenderer( 569 new DefaultTableCellRenderer() { 570 private static final long serialVersionUID = 2786027382023940417L; 571 572 @Override 573 public java.awt.Component getTableCellRendererComponent( 574 JTable table, Object value, boolean isSelected, 575 boolean hasFocus, int row, int col) { 576 java.awt.Component comp = super 577 .getTableCellRendererComponent(table, 578 value, isSelected, hasFocus, row, 579 col); 580 comp.setBackground(Color.LIGHT_GRAY); 581 return comp; 582 } 583 }); 584 585 valueTable.setRowSelectionAllowed(false); 586 valueTable.setCellSelectionEnabled(true); 587 valueTable.getTableHeader().setReorderingAllowed(false); 588 valueTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 589 590 // set cell height for large fonts 591 int cellRowHeight = Math.max(16, valueTable.getFontMetrics( 592 valueTable.getFont()).getHeight()); 593 valueTable.setRowHeight(cellRowHeight); 594 595 JScrollPane scroller = new JScrollPane(valueTable); 596 597 JPanel contentPane = (JPanel) getContentPane(); 598 int w = 300 + (ViewProperties.getFontSize() - 12) * 10; 599 int h = 600 + (ViewProperties.getFontSize() - 12) * 15; 600 contentPane.setPreferredSize(new Dimension(w, h)); 601 contentPane.setLayout(new BorderLayout(5, 5)); 602 contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 603 contentPane.add(scroller, BorderLayout.CENTER); 604 605 JButton button = new JButton(" Ok "); 606 button.addActionListener(owner); 607 button.setActionCommand("Hide palette values"); 608 609 JPanel tmpP = new JPanel(); 610 tmpP.add(button); 611 contentPane.add(tmpP, BorderLayout.SOUTH); 612 613 Point l = owner.getLocation(); 614 l.x += 100; 615 l.y += 100; 616 setLocation(l); 617 pack(); 618 } 619 620 private void updatePaletteValue(String strValue, int row, int col) { 621 if (strValue == null) { 622 return; 623 } 624 625 int value = 0; 626 627 try { 628 value = Integer.parseInt(strValue); 629 } 630 catch (Exception ex) { 631 return; 632 } 633 634 if (value < 0 || value > 255) { 635 JOptionPane.showMessageDialog(this, 636 "Value is out of range [0, 255]\n", getTitle(), 637 JOptionPane.ERROR_MESSAGE); 638 return; 639 } 640 641 paletteData[col][row] = value; 642 chartP.repaint(); 643 isPaletteChanged = true; 644 } 645 646 public void refresh() { 647 valueTable.editingStopped(new ChangeEvent(valueTable)); 648 valueTable.updateUI(); 649 } 650 } 651 652 /** The canvas that paints the data lines. */ 653 private final class ChartPanel extends JComponent { 654 private static final long serialVersionUID = -6861041412971944L; 655 656 /** 657 * Paints the plot components. 658 */ 659 @Override 660 public void paint(Graphics g) { 661 Dimension d = getSize(); 662 int gap = 20; 663 int legendSpace = 60; 664 int h = d.height - gap; 665 int w = d.width - 3 * gap - legendSpace; 666 667 // draw the X axis 668 g.drawLine(2 * gap, h, w + 2 * gap, h); 669 670 // draw the Y axis 671 g.drawLine(2 * gap, h, 2 * gap, 0); 672 673 // draw X and Y labels: 10 labels for x and y 674 int dh = h / 10; 675 int dw = w / 10; 676 int dx = 25; 677 double dy = 25; 678 int xp = 2 * gap, yp = 0, x = 0, x0, y0, x1, y1; 679 double y = 0; 680 681 // draw X and Y grid labels 682 g.drawString(String.valueOf((int) y), 0, h + 8); 683 g.drawString(String.valueOf(x), xp - 5, h + gap); 684 for (int i = 0; i < 10; i++) { 685 xp += dw; 686 yp += dh; 687 x += dx; 688 y += dy; 689 g.drawLine(xp, h, xp, h - 5); 690 g.drawLine(2 * gap, h - yp, 2 * gap + 5, h - yp); 691 g.drawString(String.valueOf((int) y), 0, h - yp + 8); 692 g.drawString(String.valueOf(x), xp - 5, h + gap); 693 } 694 695 Color c = g.getColor(); 696 for (int i = 0; i < 3; i++) { 697 g.setColor(lineColors[i]); 698 699 // set up the line data for drawing one line a time 700 for (int j = 0; j < 255; j++) { 701 x0 = (w * j / 255) + 2 * gap; 702 y0 = (h - h * paletteData[i][j] / 255); 703 x1 = (w * (j + 1) / 255) + 2 * gap; 704 y1 = (h - h * (paletteData[i][j + 1]) / 255); 705 g.drawLine(x0, y0, x1, y1); 706 } 707 708 x0 = w + legendSpace; 709 y0 = gap + gap * i; 710 g.drawLine(x0, y0, x0 + 7, y0); 711 g.drawString(lineLabels[i], x0 + 10, y0 + 3); 712 } 713 714 g.setColor(c); // set the color back to its default 715 716 // draw a box on the legend 717 g.drawRect(w + legendSpace - 10, 10, legendSpace, 10 * gap); 718 } // public void paint(Graphics g) 719 720 } // private class ChartPanel extends Canvas 721 722} // private class PaletteView extends ChartView 723