/* * ------------------------------------------------------------------------ * * Copyright (C) 2003 - 2013 * University of Konstanz, Germany and * KNIME GmbH, Konstanz, Germany * Website: http://www.knime.org; Email: contact@knime.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. * * Additional permission under GNU GPL version 3 section 7: * * KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs. * Hence, KNIME and ECLIPSE are both independent programs and are not * derived from each other. Should, however, the interpretation of the * GNU GPL Version 3 ("License") under any applicable laws result in * KNIME and ECLIPSE being a combined program, KNIME GMBH herewith grants * you the additional permission to use and propagate KNIME together with * ECLIPSE with only the license terms in place for ECLIPSE applying to * ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the * license terms of ECLIPSE themselves allow for the respective use and * propagation of ECLIPSE together with KNIME. * * Additional permission relating to nodes for KNIME that extend the Node * Extension (and in particular that are based on subclasses of NodeModel, * NodeDialog, and NodeView) and that only interoperate with KNIME through * standard APIs ("Nodes"): * Nodes are deemed to be separate and independent programs and to not be * covered works. Notwithstanding anything to the contrary in the * License, the License does not apply to Nodes, you are not required to * license Nodes under the License, and you are granted a license to * prepare and propagate Nodes, in each case even if such Nodes are * propagated with or for interoperation with KNIME. The owner of a Node * may freely choose the license terms applicable to such Node, including * when such Node is propagated with or for interoperation with KNIME. * --------------------------------------------------------------------- * * */ package org.knime.knip.io.node.dialog; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Collection; import java.util.Hashtable; import java.util.Set; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.table.AbstractTableModel; import loci.formats.FormatException; import loci.formats.ImageReader; import loci.formats.gui.BufferedImageReader; /** * A JPanel to provide a preview of the image itself or the meta data. * * @author <a href="mailto:dietzc85@googlemail.com">Christian Dietz</a> * @author <a href="mailto:horn_martin@gmx.de">Martin Horn</a> * @author <a href="mailto:michael.zinsmaier@googlemail.com">Michael * Zinsmaier</a> */ public class ImagePreviewPanel extends JPanel implements Runnable { /** * */ private static final long serialVersionUID = 1L; private final BufferedImageReader m_reader; private JLabel m_iconLabel; private String m_openedFile = null; private String[][] m_metadata; private JTable m_metadataTable; private final JPanel m_image = new JPanel(); private final JPanel m_table = new JPanel(); private static final String[] CORE_METADATA = new String[]{"SizeX", "SizeY", "SizeZ", "SizeT", "SizeC", "IsRGB", "PixelType", "LittleEndian", "DimensionsOrder", "IsInterleaved"}; /** * */ public ImagePreviewPanel() { super(); m_table.setLayout(new BoxLayout(m_table, BoxLayout.Y_AXIS)); m_reader = new BufferedImageReader(new ImageReader()); setPreferredSize(new Dimension(300, 250)); setFont(new Font(getFont().getName(), Font.PLAIN, 20)); m_iconLabel = new JLabel(); m_iconLabel.setAlignmentX(Component.CENTER_ALIGNMENT); m_image.add("Image", m_iconLabel); m_metadata = new String[][]{{"", ""}}; m_metadataTable = new JTable(new AbstractTableModel() { /** * */ private static final long serialVersionUID = 1L; @Override public int getColumnCount() { return m_metadata[0].length; } @Override public int getRowCount() { return m_metadata != null ? m_metadata.length : 0; } @Override public Object getValueAt(final int rowIndex, final int columnIndex) { return m_metadata[rowIndex][columnIndex]; } @Override public String getColumnName(final int index) { if (index == 0) { return "key"; } return "value"; } }); final JScrollPane sp = new JScrollPane(m_metadataTable); sp.setPreferredSize(new Dimension(300, 100)); m_table.add("Metadata", sp); add(m_image); add(m_table); } /** * Sets the preview to the specified file. This methods opens the file and * updates the preview panel. * * @param filename */ public void setImage(final String filename) { if (filename.equals(m_openedFile)) { return; } m_openedFile = filename; final Thread loader = new Thread(this); loader.start(); } /** * Thumbnail loading routine. */ @Override public void run() { try { // catch-all for unanticipated exceptions try { m_reader.setId(m_openedFile); final ImageIcon ico = new ImageIcon(); // get image Size final int x = m_reader.getSizeX(); final int y = m_reader.getSizeY(); // Calculate the Size of the Preview final int scx = (int)(x * (290.0 / new Double(x))); final int scy = (int)(y * (240 / new Double(y))); // Workaround for bigger ImageIcon ico.setImage(m_reader.openThumbImage(0).getScaledInstance(scx, scy, Image.SCALE_DEFAULT)); m_iconLabel.setIcon(ico); m_metadata = new String[][]{{"", ""}}; final Hashtable<String, Object> gm = m_reader.getGlobalMetadata(); m_metadata = new String[CORE_METADATA.length + gm.size()][2]; for (int i = 0; i < CORE_METADATA.length; i++) { m_metadata[i][0] = CORE_METADATA[i]; } m_metadata[0][1] = "" + x; m_metadata[1][1] = "" + y; m_metadata[2][1] = "" + m_reader.getSizeZ(); m_metadata[3][1] = "" + m_reader.getSizeT(); m_metadata[4][1] = "" + m_reader.getEffectiveSizeC(); m_metadata[5][1] = "" + m_reader.isRGB(); m_metadata[6][1] = "" + m_reader.getPixelType(); m_metadata[7][1] = "" + m_reader.isLittleEndian(); m_metadata[8][1] = "" + m_reader.getDimensionOrder(); m_metadata[9][1] = "" + m_reader.isInterleaved(); final Set<String> keys = gm.keySet(); int i = 0; for (final Object o : keys) { m_metadata[(CORE_METADATA.length + (i++)) - 1][0] = o.toString(); } final Collection<Object> values = gm.values(); i = 0; for (final Object o : values) { m_metadata[(CORE_METADATA.length + (i++)) - 1][1] = o.toString(); } m_metadataTable.tableChanged(new TableModelEvent( m_metadataTable.getModel())); } catch (final FormatException e) { m_iconLabel.setIcon(new ImageIcon( makeImage("unsupported format"))); } catch (final IOException e) { m_iconLabel.setIcon(new ImageIcon(makeImage("failed"))); m_metadata = null; } } catch (final Exception exc) { m_iconLabel.setIcon(new ImageIcon(makeImage("error"))); } } /** * Creates a blank image with the given message painted on top (e.g., a * loading or error message), matching the size of the active reader's * thumbnails. */ private BufferedImage makeImage(final String message) { int w = getSize().width, h = getSize().height; if (w < 128) { w = 128; } if (h < 32) { h = 32; } final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); final Graphics2D g = image.createGraphics(); final Rectangle2D.Float r = (Rectangle2D.Float)g.getFont().getStringBounds(message, g.getFontRenderContext()); g.drawString(message, (w - r.width) / 2, ((h - r.height) / 2) + r.height); g.dispose(); return image; } }