/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.util.graph; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import javax.imageio.ImageIO; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.SWTGraphics; import org.eclipse.draw2d.geometry.Rectangle; //import org.eclipse.gmf.runtime.draw2d.ui.render.awt.internal.svg.export.GraphicsSVG; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.zest.core.viewers.GraphViewer; import org.eclipse.zest.core.widgets.Graph; import org.eclipse.zest.internal.dot.DotExport; import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; import eu.esdihumboldt.hale.ui.util.swing.SwingRcpUtilities; /** * Renders a graph to an image. * * @author Simon Templer */ public abstract class OffscreenGraph { private final Graph graph; private final Shell shell; private final Composite composite; /** * @return the graph */ public Graph getGraph() { return graph; } /** * Create an off-screen graph. * * @param width the graph width * @param height the graph height */ public OffscreenGraph(int width, int height) { shell = new Shell(); shell.setSize(width, height); shell.setLayout(new FillLayout()); composite = new Composite(shell, SWT.NONE); composite.setLayout(new FillLayout()); composite.setVisible(true); // Workaround to draw in background --> graph = new Graph(composite, SWT.NONE); GraphViewer viewer = new GraphViewer(graph); configureViewer(viewer); if (graph.getLayoutAlgorithm() == null) { graph.setLayoutAlgorithm(new TreeLayoutAlgorithm(TreeLayoutAlgorithm.LEFT_RIGHT), true); } graph.setBounds(0, 0, width, height); graph.getViewport().setBounds(new Rectangle(0, 0, width, height)); shell.setVisible(false); Object input = viewer.getInput(); // re-setting the input seems to be needed for the tree layout to place // the nodes correctly viewer.setInput(input); graph.applyLayoutNow(); IFigure root = graph.getRootLayer(); root.getUpdateManager().performUpdate(); } /** * Resize the off-screen graph. * * @param width the graph width * @param height the graph height */ public void resize(int width, int height) { shell.setSize(width, height); graph.setBounds(0, 0, width, height); graph.getViewport().setBounds(new Rectangle(0, 0, width, height)); graph.applyLayoutNow(); IFigure root = graph.getRootLayer(); root.getUpdateManager().performUpdate(); } /** * Dispose the off-screen graph shell. * * @see Shell#dispose() */ public void dispose() { if (shell != null) { shell.dispose(); } } /** * Configure the viewer. * * @param viewer the graph viewer */ protected abstract void configureViewer(GraphViewer viewer); /** * Save the graph as image to an output stream. * * @param out the output stream to write the image to (which is closed after * writing) * @param format the informal name of the image format, if <code>null</code> * defaults to <code>png</code> * @throws IOException if writing the image fails * * @see ImageIO#write(java.awt.image.RenderedImage, String, OutputStream) */ public void saveImage(OutputStream out, String format) throws IOException { saveImage(graph.getRootLayer(), out, format); } /** * Save the graph as Scalable Vector Graphics to an output stream. * * @param out the output stream to write the SVG DOM to (which is closed * after writing) * @throws IOException if writing to the output stream fails * @throws TransformerFactoryConfigurationError if creating the transformer * fails * @throws TransformerException if writing the document fails */ /* * public void saveSVG(OutputStream out) throws IOException, * TransformerFactoryConfigurationError, TransformerException { * saveSVG(graph.getRootLayer(), out); } */ /** * Save a figure as image to an output stream. * * @param root the figure to draw * @param out the output stream to write the image to (which is closed after * writing) * @param format the informal name of the image format, if <code>null</code> * defaults to <code>png</code> * @throws IOException if writing the image fails * * @see ImageIO#write(java.awt.image.RenderedImage, String, OutputStream) */ public static void saveImage(IFigure root, OutputStream out, String format) throws IOException { if (format == null) { format = "png"; } Image drawImage = new Image(Display.getCurrent(), root.getSize().width, root.getSize().height); final GC gc = new GC(drawImage); SWTGraphics graphics = new SWTGraphics(gc); try { gc.setAntialias(SWT.ON); gc.setInterpolation(SWT.HIGH); // paint the graph to an image root.paint(graphics); BufferedImage bufferedImage = SwingRcpUtilities.convertToAWT(drawImage.getImageData()); ImageIO.write(bufferedImage, format, out); } finally { gc.dispose(); drawImage.dispose(); out.close(); } } /** * Save a figure as Scalable Vector Graphics to an output stream. * * @param root the figure to draw * @param out the output stream to write the SVG DOM to (which is closed * after writing) * @throws IOException if writing to the output stream fails * @throws TransformerFactoryConfigurationError if creating the transformer * fails * @throws TransformerException if writing the document fails */ /* * public static void saveSVG(IFigure root, OutputStream out) throws * IOException, TransformerFactoryConfigurationError, TransformerException { * Rectangle viewBox = root.getBounds().getCopy(); GraphicsSVG graphics = * GraphicsSVG.getInstance(viewBox); * * // paint figure try { root.paint(graphics); * * Element svgRoot = graphics.getRoot(); * * // Define the view box svgRoot.setAttributeNS(null, "viewBox", * String.valueOf(viewBox.x) + " " + //$NON-NLS-1$ //$NON-NLS-2$ * String.valueOf(viewBox.y) + " " + //$NON-NLS-1$ * String.valueOf(viewBox.width) + " " + //$NON-NLS-1$ * String.valueOf(viewBox.height)); * * // Write the document to the stream Transformer transformer = * TransformerFactory.newInstance().newTransformer(); * transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ * transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); * //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); * //$NON-NLS-1$ * * DOMSource source = new DOMSource(svgRoot); StreamResult result = new * StreamResult(out); transformer.transform(source, result); } finally { * graphics.dispose(); out.close(); } } */ /** * Save a graph in the dot format to an output stream. * * @param graph the graph * @param out the output stream (which is closed after writing) * @throws IOException if writing to the output stream fails */ public static void saveDot(Graph graph, OutputStream out) throws IOException { OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(out); writer.write(new DotExport(graph).toDotString()); } finally { if (writer != null) writer.close(); out.close(); } } }