/* 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.Transparency; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.renderable.ParameterBlock; import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.media.jai.EnumeratedParameter; import javax.media.jai.Interpolation; import javax.media.jai.JAI; import javax.media.jai.ParameterBlockJAI; import javax.media.jai.RenderedOp; import javax.media.jai.TileCache; import javax.media.jai.TileScheduler; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; //import com.digitalglobe.util.Log4jUtil; //import org.apache.log4j.Logger; /** * Full rendered image browser, made up of tree for rendered image source * hierarchy navigation and a info panel with various information on the * selected {@link RenderedImage} * * @author Andrea Aime * @author Daniele Romagnoli, GeoSolutions SAS * @author Simone Giannecchini, GeoSolutions SAS * */ public class RenderedImageBrowser extends JPanel { private static final Map<Integer, String> TYPE_MAP = new HashMap<Integer, String>(); 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"); } public static void showChain(RenderedImage image, String title) { showChain(image, true, true, title); } public static void showChain(RenderedImage image) { showChain(image, ""); } public static void showChain(RenderedImage image, final boolean showHistogram) { showChain(image, showHistogram, false); } public static void showChain(RenderedImage image, final boolean showHistogram, final boolean showRoi) { showChain(image, showHistogram, showRoi, ""); } /** * Dumps a text description of an image chain, useful to for headless debugging * or logging purposes * @param image * @return */ public static String dumpChain(RenderedImage image) { TextTreeBuilder builder = new TextTreeBuilder(); dumpChain(image, builder); return builder.toString(); } private static void dumpChain(RenderedImage image, TextTreeBuilder builder) { String name; TileCache tcache = null; TileScheduler tscheduler = null; if (image instanceof RenderedOp) { RenderedOp op = (RenderedOp) image; String operationName = op.getOperationName(); String renderingName = "null"; try { op.getWidth(); renderingName = op.getCurrentRendering().getClass().getName(); } catch (Exception ignored) { // can happen if the op has trouble setting up its rendering // Logger logger = Logger.getLogger(RenderedImageBrowser.class); // if (logger.isTraceEnabled()) // { // Log4jUtil.trace(logger, ignored.getMessage(), ignored); // } Logger logger = Logger.getLogger(RenderedImageBrowser.class.toString()); if (logger.isLoggable(Level.WARNING)) { logger.log(Level.WARNING, ignored.getMessage()); } } name = "JAI op: " + operationName + '(' + renderingName + ')'; tcache = (TileCache) op.getRenderingHint(JAI.KEY_TILE_CACHE); tscheduler = (TileScheduler) op.getRenderingHint(JAI.KEY_TILE_SCHEDULER); } else { name = "Non op: " + image.getClass(); } builder.append(name); builder.append(", offset:"); builder.append(image.getMinX() + ", " + image.getMinY()); builder.append(", size:"); builder.append(image.getWidth() + " x " + image.getHeight()); builder.append(", tile size:" + image.getTileWidth() + " x " + image.getTileHeight()); builder.newLine(); // dump the rendered op params if we have some if (image instanceof RenderedOp) { builder.append("Params. "); RenderedOp op = (RenderedOp) image; final ParameterBlock block = op.getParameterBlock(); Vector<Object> paramValues = block.getParameters(); for (int i = 0; i < paramValues.size(); i++) { String pname = "Parameter " + (i + 1); if (block instanceof ParameterBlockJAI) { pname = ((ParameterBlockJAI) block).getParameterListDescriptor().getParamNames()[i]; } builder.append(pname); builder.append(":"); Object value = paramValues.get(i); dumpValue(builder, value); builder.append("; "); } builder.newLine(); } SampleModel sm = image.getSampleModel(); builder.append("Bands: " + sm.getNumBands() + ", type: " + TYPE_MAP.get(sm.getDataType())); builder.append("; Color model:" + image.getColorModel().getClass()); builder.append(", transparency: "); switch (image.getColorModel().getTransparency()) { case Transparency.OPAQUE: builder.append("Opaque"); break; case Transparency.TRANSLUCENT: builder.append("Translucent"); break; case Transparency.BITMASK: builder.append("Bitmas k"); break; } builder.newLine(); builder.append("Tile cache: " + tcache); builder.newLine(); builder.append("Tile scheduler: "); if (tscheduler == null) { builder.append("null"); } else { builder.append(tscheduler + ((tscheduler == JAI.getDefaultInstance().getTileScheduler()) ? "<global>" : "<local>") + ", parallelism " + tscheduler.getParallelism() + ", priority " + tscheduler.getPriority()); } if (image.getSources() != null) { builder.newLine(); builder.append("Number of children: " + image.getSources().size()); for (RenderedImage child : image.getSources()) { builder.newChild(); dumpChain(child, builder); builder.endChild(); } } } private static void dumpValue(TextTreeBuilder builder, Object value) { if ((value != null) && value.getClass().isArray()) { int length = Array.getLength(value); builder.append("["); for (int j = 0; j < length; j++) { dumpValue(builder, Array.get(value, j)); if (j < (length - 1)) { builder.append(", "); } else { builder.append("]"); } } } else if (value instanceof EnumeratedParameter) { String enumName = ((EnumeratedParameter) value).getName(); builder.append(enumName); } else if (value instanceof Interpolation) { String interpName = value.getClass().getSimpleName(); builder.append(interpName); } else { builder.append(String.valueOf(value)); } } public static void showChain(RenderedImage image, final boolean showHistogram, final boolean showRoi, final String title) { String localTitle = (title != null) ? (": " + title) : ""; JFrame frame = new JFrame("Rendered image information tool" + localTitle); RenderedImageBrowser info = new RenderedImageBrowser(showHistogram, showRoi); info.setImage(image); frame.setContentPane(info); frame.setSize(1024, 768); frame.setVisible(true); } ImageTreeModel model; JTree imageTree; RenderedImageInfoPanel imageInfo; JSplitPane split; boolean showHistogram; boolean showRoi; public RenderedImageBrowser() { this(true, false); } public RenderedImageBrowser(final boolean showHistogram, final boolean showRoi) { this.showHistogram = showHistogram; this.showRoi = showRoi; model = new ImageTreeModel(); imageTree = new JTree(model); imageTree.setCellRenderer(new ImageTreeRenderer()); imageTree.setShowsRootHandles(true); imageTree.putClientProperty("JTree.lineStyle", "Angled"); imageInfo = new RenderedImageInfoPanel(showHistogram, showRoi); split = new JSplitPane(); split.setLeftComponent(new JScrollPane(imageTree)); split.setRightComponent(imageInfo); split.setResizeWeight(0.2); setLayout(new BorderLayout()); add(split); imageTree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { final TreePath selectedpath = imageTree.getSelectionPath(); if (selectedpath == null) { imageTree.setSelectionRow(0); } RenderedImage image = (RenderedImage) imageTree.getSelectionPath().getLastPathComponent(); imageInfo.setImage(image); } }); } public void setImage(RenderedImage image) { model.setRoot(image); imageTree.setSelectionPath(new TreePath(image)); int rc; do { rc = imageTree.getRowCount(); for (int x = rc; x >= 0; x--) { imageTree.expandRow(x); } } while (rc != imageTree.getRowCount()); } }