/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2014 GeoSolutions * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.geosolutions.rendered.viewer; import java.awt.BorderLayout; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.image.DataBuffer; import java.awt.image.IndexColorModel; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.renderable.ParameterBlock; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.media.jai.JAI; import javax.media.jai.ParameterBlockJAI; import javax.media.jai.PlanarImage; import javax.media.jai.ROI; import javax.media.jai.RenderedOp; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; //import com.digitalglobe.util.Log4jUtil; //import org.apache.log4j.Logger; /** * Tabbed {@link RenderedImage} information display * * @author Andrea Aime * @author Daniele Romagnoli, GeoSolutions SAS * @author Simone Giannecchini, GeoSolutions SAS * */ public class RenderedImageInfoPanel extends JPanel { // Data buffer type to name map private static final Map<Integer, String> TYPE_MAP = new HashMap<Integer, String>(); // Rendering key to name map private static final Map<Object, String> KEY_MAP = new HashMap<Object, String>(); //private static final Logger logger = Logger.getLogger(RenderedImageInfoPanel.class); private static final Logger logger = Logger.getLogger(RenderedImageInfoPanel.class.toString()); static { TYPE_MAP.put(DataBuffer.TYPE_BYTE, "Byte"); TYPE_MAP.put(DataBuffer.TYPE_DOUBLE, "Double"); TYPE_MAP.put(DataBuffer.TYPE_FLOAT, "Float"); TYPE_MAP.put(DataBuffer.TYPE_INT, "Int"); TYPE_MAP.put(DataBuffer.TYPE_SHORT, "Short"); TYPE_MAP.put(DataBuffer.TYPE_UNDEFINED, "Undefined"); TYPE_MAP.put(DataBuffer.TYPE_USHORT, "Short"); try { Field[] fields = JAI.class.getFields(); for (Field field : fields) { final int modifiers = field.getModifiers(); // funny enough most KEY in JAI are not final... if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getName().startsWith("KEY_")) { KEY_MAP.put(field.get(null), field.getName()); } } } catch (Exception e) { //Log4jUtil.warn(logger, e.getMessage(), e); } } JTabbedPane tabs; JEditorPane generalPanel; JEditorPane propertiesPanel; private JEditorPane operationPanel; private ImageViewer viewer; private ImageViewer roiViewer; private boolean showHistogram = true; private DisplayHistogram histogramPanel = new DisplayHistogram(""); private boolean showRoi; public RenderedImageInfoPanel() { this(false, false); } public RenderedImageInfoPanel(final boolean showHistogram) { this(showHistogram, false); } public RenderedImageInfoPanel(final boolean showHistogram, final boolean showRoi) { setLayout(new BorderLayout()); tabs = new JTabbedPane(); add(tabs, BorderLayout.CENTER); this.showHistogram = showHistogram; this.showRoi = showRoi; generalPanel = buildHtmlPane(); propertiesPanel = buildHtmlPane(); operationPanel = buildHtmlPane(); if (showRoi) { roiViewer = new ImageViewer(); viewer = new ImageViewer(roiViewer); roiViewer.setRelatedViewer(viewer); } else { viewer = new ImageViewer(); } tabs.addTab("General information", scroll(generalPanel)); tabs.addTab("Viewer", viewer); tabs.addTab("Properties", scroll(propertiesPanel)); tabs.addTab("Operation", scroll(operationPanel)); if (showHistogram) { tabs.addTab("Histogram", scroll(histogramPanel)); } if (showRoi) { tabs.addTab("ROIViewer", roiViewer); } } private JScrollPane scroll(JComponent pane) { return new JScrollPane(pane); } private JEditorPane buildHtmlPane() { JEditorPane pane = new ScrollTopEditorPane("text/html", ""); pane.setEditable(false); return pane; } public void setImage(RenderedImage image) { buildGeneralInfoPane(image); buildPropertiesPane(image); if (image instanceof RenderedOp) { operationPanel.setEnabled(true); buildOpPane((RenderedOp) image); } else { operationPanel.setEnabled(false); } if (showHistogram) { histogramPanel.setImage(PlanarImage.wrapRenderedImage(image)); } try { viewer.setImage(image); } catch(Exception e) { viewer.setImage(null); viewer.setStatusMessage("Error:" + e.getMessage()); e.printStackTrace(); } if (showRoi) { try { if (image instanceof RenderedOp) { final Object object = image.getProperty("ROI"); if (object instanceof ROI) { ROI roi = (ROI) object; roiViewer.setImage(roi.getAsImage()); } } } catch(Exception e) { e.printStackTrace(); roiViewer.setImage(null); roiViewer.setStatusMessage("Error:" + e.getMessage()); } } } void buildOpPane(RenderedOp image) { final HTMLBuilder hb = new HTMLBuilder(); hb.title("Operation"); String renderingName = "null"; try { image.getWidth(); renderingName = image.getCurrentRendering().getClass().getName(); } catch (Exception ignored) { // can happen if the op has trouble setting up its rendering // if (logger.isTraceEnabled()) // { // Log4jUtil.trace(logger, ignored.getMessage(), ignored); // } if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, ignored.getMessage()); } } hb.dataLine("Name", image.getOperationName() + " (" + renderingName + ')'); hb.title("Parameters"); final ParameterBlock block = image.getParameterBlock(); Vector<Object> paramValues = block.getParameters(); for (int i = 0; i < paramValues.size(); i++) { String name = "Parameter " + (i + 1); if (block instanceof ParameterBlockJAI) { name = ((ParameterBlockJAI) block).getParameterListDescriptor().getParamNames()[i]; } hb.dataLine(name, paramValues.get(i)); } hb.title("Hints"); RenderingHints hints = image.getRenderingHints(); List keys = new ArrayList(hints.keySet()); for (Object key : keys) { String label = KEY_MAP.get(key); if (label == null) { label = key.toString(); } hb.dataLine(label, hints.get(key)); } operationPanel.setText(hb.getHtml()); } void buildPropertiesPane(RenderedImage source) { HTMLBuilder hb = new HTMLBuilder(); hb.title("Properties"); String[] properties = source.getPropertyNames(); if (properties == null) { return; } Arrays.sort(properties); for (String propName : properties) { hb.dataLine(propName, source.getProperty(propName)); } propertiesPanel.setText(hb.getHtml()); operationPanel.setCaretPosition(0); } void buildGeneralInfoPane(RenderedImage image) { HTMLBuilder hb = new HTMLBuilder(); hb.title("Abstract"); hb.dataLine("Name", getImageName(image)); hb.dataLine("Image class", image.getClass()); hb.dataLine("Image origin", image.getMinX() + " , " + image.getMinY()); hb.dataLine("Image size", image.getWidth() + " x " + image.getHeight()); hb.title("Tiles organisation"); int tw = image.getTileWidth(); int th = image.getTileHeight(); int ytc = image.getNumYTiles(); int xtc = image.getNumXTiles(); hb.dataLine("Tile size", tw + " x " + th); hb.dataLine("Tile grid", xtc + " x " + ytc + // " (" + (tw * xtc) + " x " + (th * ytc) + ')'); hb.dataLine("Tile offsets x,y", image.getTileGridXOffset() + ", " + image.getTileGridYOffset()); hb.dataLine("Min tile x,y", image.getMinTileX() + ", " + image.getMinTileY()); hb.title("Sample model"); SampleModel sm = image.getSampleModel(); hb.dataLine("Sample model", sm.getClass()); hb.dataLine("Size", sm.getWidth() + " x " + sm.getHeight()); hb.dataLine("Bands", sm.getNumBands()); hb.dataLine("Bands", TYPE_MAP.get(sm.getDataType())); hb.title("Color model"); hb.dataLine("Color model", image.getColorModel().getClass()); switch (image.getColorModel().getTransparency()) { case Transparency.OPAQUE: hb.dataLine("Transparency", "Opaque"); break; case Transparency.TRANSLUCENT: hb.dataLine("Transparency", "Translucent"); break; case Transparency.BITMASK: hb.dataLine("Transparency", "Bitmask"); break; } if (image.getColorModel() instanceof IndexColorModel) { final IndexColorModel icm = (IndexColorModel) image.getColorModel(); // transparent pixel hb.dataLine("Transparent Pixel", Integer.toString(icm.getTransparentPixel())); // lut hb.dataLine("ColorMap Size", Integer.toString(icm.getMapSize())); final int numbands = icm.hasAlpha() ? 4 : 3; final byte[][] cmap = new byte[numbands][icm.getMapSize()]; icm.getReds(cmap[0]); icm.getGreens(cmap[1]); icm.getBlues(cmap[2]); if (numbands == 4) { icm.getAlphas(cmap[3]); } final StringBuilder b = new StringBuilder(); for (int i = 0; i < icm.getMapSize(); i++) { b.append('(').append(i).append(")-").append('[').append(cmap[0][i]).append(',').append(cmap[1][i]).append(',').append(cmap[2][i]); if (numbands == 4) { b.append(',').append(cmap[3][i]); } b.append(']').append('\n'); } hb.dataLine("ColorMap", b.toString()); } hb.dataLine("Color space", image.getColorModel().getColorSpace().getClass()); hb.title("Sources"); List<RenderedImage> sources = image.getSources(); final int size; if ((sources != null) && !sources.isEmpty()) { size = sources.size(); } else { size = 0; } for (int i = 0; i < size; i++) { hb.dataLine("Source " + (i + 1), getImageName(sources.get(i))); } generalPanel.setText(hb.getHtml()); } private String getImageName(RenderedImage source) { if (source instanceof RenderedOp) { return "RenderedOp, <i>" + ((RenderedOp) source).getOperationName() + "</i>"; } else { return "Generic <i>" + source.getClass() + "</i>"; } } /** * Simple variation over JEditorPane making the caret be at top each time * the text is set into the pane * * @author Andrea Aime * */ private static class ScrollTopEditorPane extends JEditorPane { public ScrollTopEditorPane(String type, String text) { super(type, text); } @Override public void setText(String t) { super.setText(t); setCaretPosition(0); } } }