/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.mindmap; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.eclipse.draw2d.Layer; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.xmind.core.IFileEntry; import org.xmind.core.IManifest; import org.xmind.core.IWorkbook; import org.xmind.core.internal.dom.FileEntryImpl; import org.xmind.core.util.FileUtils; import org.xmind.gef.GEF; import org.xmind.gef.IGraphicalViewer; import org.xmind.gef.image.FigureRenderer; import org.xmind.gef.image.IExportAreaProvider; import org.xmind.gef.image.ImageExportUtils; import org.xmind.gef.image.ResizeConstants; import org.xmind.gef.util.Properties; import org.xmind.ui.resources.ColorUtils; import org.xmind.ui.util.ImageFormat; import org.xmind.ui.viewers.ICompositeProvider; /** * @author Frank Shaka * */ public class MindMapImageExporter { private Display display = null; /* ==== What to Export? ==== */ private MindMapViewerExportSourceProvider sourceProvider = null; private Object input = null; private ICompositeProvider parent = null; private Insets margins = null; private Properties properties = null; /* ==== How to Export? ==== */ private int resizeStrategy = ResizeConstants.RESIZE_NONE; private int wHint = -1; private int hHint = -1; private ImageFormat format = ImageFormat.PNG; /* ==== Where to Export to? ==== */ private OutputStream targetStream = null; private File targetFile = null; private IWorkbook targetWorkbook = null; private String targetEntryPath = null; private boolean ignoreEntryEncryption = true; /* ==== What to Clean Out After Exporting? ==== */ private GhostShellProvider ghostShellProvider = null; private IGraphicalViewer exportViewer = null; private OutputStream streamToClose = null; private IFileEntry fileEntry = null; private IExportAreaProvider area = null; /** * */ public MindMapImageExporter(Display display) { this.display = display; } public void setResize(int strategy, int wHint, int hHint) { this.resizeStrategy = strategy; this.wHint = wHint; this.hHint = hHint; } public void setImageFormat(ImageFormat format) { this.format = format; } public void setSourceProvider( MindMapViewerExportSourceProvider sourceProvider) { setSources(sourceProvider, null, null, null, null); } public void setSourceViewer(IGraphicalViewer viewer) { setSources( new MindMapViewerExportSourceProvider(viewer, MindMapUI.DEFAULT_EXPORT_MARGIN), null, null, null, null); } public void setSourceViewer(IGraphicalViewer viewer, Insets margins) { setSources(new MindMapViewerExportSourceProvider(viewer, margins), null, null, null, null); } public void setSourceViewer(IGraphicalViewer viewer, ICompositeProvider parent, Properties properties, Insets margins) { // Check if viewer has been drilled down: IMindMap map = (IMindMap) viewer.getAdapter(IMindMap.class); if (map == null || map.getCentralTopic() == map.getSheet().getRootTopic()) { setSourceViewer(viewer, margins); } else { setSource(new MindMap(map.getSheet()), parent, properties, margins); } } public void setSource(Object input, Properties properties, Insets margins) { setSources(null, input, null, properties, margins); } public void setSource(Object input, ICompositeProvider parent, Properties properties, Insets margins) { setSources(null, input, parent, properties, margins); } protected void setSources(MindMapViewerExportSourceProvider sourceProvider, Object input, ICompositeProvider parent, Properties properties, Insets margins) { this.sourceProvider = sourceProvider; this.input = input; this.parent = parent; this.properties = properties; this.margins = margins; cleanUpSources(); } public void setTargetStream(OutputStream stream) { setTargets(stream, null, null, null, true); } public void setTargetFile(File file) { setTargets(null, file, null, null, true); } public void setTargetFileEntry(IWorkbook workbook, String entryPath) { setTargets(null, null, workbook, entryPath, true); } public void setTargetWorkbook(IWorkbook workbook) { setTargets(null, null, workbook, null, true); } public void setTargetFileEntry(IWorkbook workbook, String entryPath, boolean ignoreEncryption) { setTargets(null, null, workbook, entryPath, ignoreEncryption); } public void setTargetFileEntry(IWorkbook workbook, boolean ignoreEncryption) { setTargets(null, null, workbook, null, ignoreEncryption); } protected void setTargets(OutputStream stream, File file, IWorkbook workbook, String entryPath, boolean ignoreEncryption) { this.targetStream = stream; this.targetFile = file; this.targetWorkbook = workbook; this.targetEntryPath = entryPath; this.ignoreEntryEncryption = ignoreEncryption; cleanUpTargets(); } /** * @return the sourceProvider */ public MindMapViewerExportSourceProvider getSourceProvider() { return sourceProvider; } public Point calcRelativeOrigin() { if (sourceProvider == null || area == null) return null; Point origin = sourceProvider.getOriginPoint(); Rectangle bounds = area.getExportArea(); return bounds.getLocation().negate().translate(origin); } public void initRenderer(FigureRenderer renderer) { if (this.sourceProvider == null) { prepareSourceProvider(); } if (this.area == null) { this.area = ImageExportUtils.createExportAreaProvider( sourceProvider.getSourceArea(), resizeStrategy, wHint, hHint, sourceProvider.getMargins()); } renderer.init(sourceProvider, area); } public Image createImage() { prepareSourceProvider(); try { final FigureRenderer renderer = new FigureRenderer(); initRenderer(renderer); final Image[] image = new Image[1]; final Throwable[] error = new Throwable[1]; display.syncExec(new Runnable() { @Override public void run() { try { image[0] = ImageExportUtils.createImage(display, renderer); } catch (RuntimeException e) { error[0] = e; } catch (Error e) { error[0] = e; } } }); if (error[0] != null) throw new RuntimeException(error[0].getMessage(), error[0]); return image[0]; } finally { cleanUpSources(); } } public void export() { Image image = createImage(); try { export(image); } finally { image.dispose(); } } public void export(Image image) { prepareTargetStream(); try { ImageExportUtils.saveImage(image, targetStream, format.getSWTFormat()); if (fileEntry != null) { fileEntry.decreaseReference(); fileEntry.increaseReference(); fileEntry = null; } } finally { cleanUpTargets(); } } public void export(InputStream sourceStream) throws IOException { prepareTargetStream(); try { FileUtils.transfer(sourceStream, targetStream, true); if (fileEntry != null) { fileEntry.decreaseReference(); fileEntry.increaseReference(); fileEntry = null; } } finally { cleanUpTargets(); } } public void prepareSourceProvider() { cleanUpSources(); if (input != null) { display.syncExec(new Runnable() { public void run() { recreateSourceProviderFromInput(); } }); } if (sourceProvider == null) throw new IllegalArgumentException( "No source to export image from"); //$NON-NLS-1$ } private void recreateSourceProviderFromInput() { if (parent != null) { this.exportViewer = new MindMapExportViewer(parent, input, properties); } else { this.ghostShellProvider = new GhostShellProvider(display); this.exportViewer = new MindMapExportViewer(ghostShellProvider, input, properties); } if (margins != null) { this.sourceProvider = new MindMapViewerExportSourceProvider( this.exportViewer, margins); } else { this.sourceProvider = new MindMapViewerExportSourceProvider( this.exportViewer); } } /** * */ public void prepareTargetStream() { cleanUpTargets(); if (targetFile != null) { recreateTargetStreamFromFile(); } else if (targetWorkbook != null) { recreateTargetStreamFromFileEntry(); } if (targetStream == null) throw new IllegalArgumentException("No target to export image to"); //$NON-NLS-1$ } /** * */ private void recreateTargetStreamFromFileEntry() { IManifest manifest = targetWorkbook.getManifest(); String entryPath = this.targetEntryPath; if (entryPath == null) { entryPath = toThumbnailArchivePath(format); } this.fileEntry = manifest.createFileEntry(entryPath, format.getMediaType()); try { this.targetStream = this.fileEntry.openOutputStream(); } catch (IOException e) { } this.streamToClose = this.targetStream; } /** * */ private void recreateTargetStreamFromFile() { FileUtils.ensureFileParent(targetFile); try { this.targetStream = new FileOutputStream(targetFile); this.streamToClose = this.targetStream; } catch (FileNotFoundException e) { throw new IllegalArgumentException(e.getMessage()); } } /** * */ public void cleanUpSources() { if (exportViewer != null) { if (exportViewer.getControl() != null) { display.syncExec(new Runnable() { public void run() { exportViewer.getControl().dispose(); } }); } exportViewer = null; } if (ghostShellProvider != null) { display.syncExec(new Runnable() { public void run() { ghostShellProvider.dispose(); } }); ghostShellProvider = null; } } /** * */ public void cleanUpTargets() { if (streamToClose != null) { try { streamToClose.close(); } catch (IOException e) { //ignore } streamToClose = null; } } public Properties getProperties() { return properties; } /** * Must be called after export. * * @return */ public String getBackgroundColor() { return getBackgroundColor(getSourceProvider().getViewer()); } public static String toThumbnailArchivePath(ImageFormat format) { return "Thumbnails/thumbnail" + format.getExtensions().get(0); //$NON-NLS-1$ } private static String getBackgroundColor(IGraphicalViewer sourceViewer) { if (sourceViewer != null) { Layer layer = sourceViewer.getLayer(GEF.LAYER_BACKGROUND); if (layer != null) { Color color = layer.getBackgroundColor(); if (color != null) return ColorUtils.toString(color); } } return "#ffffff"; //$NON-NLS-1$ } }