package org.xmind.ui.internal.svgsupport; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.SWTGraphics; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Enki Xiong */ public class SVGImageData { private boolean isInit; private boolean documentContainError = false; private String filePath; private Dimension size = new Dimension(-1, -1); private static final Dimension INVALID_DIMENSION = new Dimension(-1, -1); private List<SVGShape> list; public SVGImageData(String filePath) { this.filePath = filePath; this.isInit = false; list = new ArrayList<SVGShape>(); } private void init() { try { Element svg = getRootElement(filePath); // FIXME handle problem : width = 12cm 12 or 100% int height = Integer .parseInt(svg.getAttribute(SVGDefinitionConstants.HEIGHT) .split(SVGDefinitionConstants.PX)[0]); int width = Integer .parseInt(svg.getAttribute(SVGDefinitionConstants.WIDTH) .split(SVGDefinitionConstants.PX)[0]); size = new Dimension(width, height); NodeList nodeList = svg.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element ele = (Element) node; if (SVGDefinitionConstants.TAG_DEFS .equals(ele.getTagName())) parseDefinition(ele); } } for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element ele = (Element) node; SVGShape shape = SVGShape.parseShape(ele, null); if (shape != null) list.add(shape); } } } catch (Exception e) { documentContainError = true; e.printStackTrace(); return; } isInit = true; } private Element getRootElement(String path) { InputStream stream = null; try { URL url = new URL(path); return getRootElement(url.openStream()); } catch (Exception e) { e.printStackTrace(); } finally { if (stream != null) { try { stream.close(); stream = null; } catch (IOException e) { e.printStackTrace(); } } } return null; } private Element getRootElement(InputStream stream) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(true); factory.setFeature("http://xml.org/sax/features/namespaces", //$NON-NLS-1$ false); factory.setFeature("http://xml.org/sax/features/validation", //$NON-NLS-1$ false); factory.setFeature( "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", //$NON-NLS-1$ false); factory.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", //$NON-NLS-1$ false); Document document = factory.newDocumentBuilder().parse(stream); Element element = document.getDocumentElement(); return element; } private void parseDefinition(Element defs) { NodeList list = defs.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node node = list.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element ele = (Element) node; String tagName = ele.getTagName(); if (null != tagName && !"".equals(tagName)) { //$NON-NLS-1$ String id = ele.getAttribute(SVGDefinitionConstants.ID); if (tagName.equals( SVGDefinitionConstants.TAG_LINEARGRADIENT)) { SVGDefinition def = LinearGradient .parseLinearGradient(ele); SVGShape.idRefs.put(id, def); } else { SVGShape def = SVGShape.parseShape(ele, null); if (def != null) SVGShape.idRefs.put(id, def); } } } } } private void paint(Graphics graphics, Display device) { if (!isInit) init(); if (documentContainError) { return; } try { for (SVGShape shape : list) { shape.paintImage(graphics, device); } } catch (Exception e) { e.printStackTrace(); } } /** * create an image * * @param imageSize * size of the image you want to create * @param background * the background color of the image, default value is null * @return */ public ImageData createImage(Dimension imageSize, RGB background) { if (imageSize != null && imageSize.equals(INVALID_DIMENSION)) { if (size.equals(INVALID_DIMENSION)) init(); imageSize = size; } Image image = new Image(Display.getDefault(), imageSize.width, imageSize.height); Rectangle rect = new Rectangle(0, 0, imageSize.width, imageSize.height); paintImage(image, rect, background); ImageData imgData = image.getImageData(); image.dispose(); return imgData; } /** * paint svg image to specific area <B> paintArea</B> in <B>image</B> * * @param image * @param paintArea * @param background * add background for svg image,null if not need */ public void paintImage(Image image, Rectangle paintArea, RGB background) { GC gc = new GC(image); SWTGraphics graphics = new SWTGraphics(gc); paintFigure(graphics, paintArea, null, background); graphics.dispose(); gc.dispose(); } /** * paint svg image to specific area <b>paintArea</b> with <b>graphics</b> * * @param graphics * @param paintArea * @param manager * if this svg image will be painted frequently,you should * provide ResourceManager instance and manager this instance by * yourself <br> * <i>Note:</i> * <ul> * <li>if this image be removed from parent container, you must * invoke manager.dispose() to release OS resource;</li> * <li>if you provide null, this class will create a * LocalResourceManager for painting and dispose it when painting * ended</li> * </ul> */ public void paintFigure(Graphics graphics, Rectangle paintArea, ResourceManager manager) { paintFigure(graphics, paintArea, manager, null); } /** * paint svg image to specific area <b>(paintArea)</b> with <b>graphics</b> * * @param background * the background color of the image, default value is null * @see paintFigure(Graphics graphics, Rectangle paintArea, ResourceManager * manager); */ public void paintFigure(Graphics graphics, Rectangle paintArea, ResourceManager manager, RGB background) { graphics.setAdvanced(true); graphics.setAntialias(SWT.ON); graphics.translate(paintArea.x, paintArea.y); Dimension svgImageSize = getSize(); graphics.scale(((float) paintArea.width) / svgImageSize.width, ((float) paintArea.height) / svgImageSize.height); boolean isNewManager = false; if (manager == null) { ResourceManager resources = JFaceResources.getResources(); resources = resources == null ? JFaceResources.getResources(Display.getDefault()) : resources; manager = new LocalResourceManager(resources); isNewManager = true; } if (background != null) { graphics.pushState(); graphics.setBackgroundColor(manager.createColor(background)); graphics.fillRectangle(0, 0, svgImageSize.width, svgImageSize.height); graphics.popState(); } setResourceManager(manager); paint(graphics, Display.getDefault()); /// reset scale for export graphics.scale(1.0f); if (isNewManager) manager.dispose(); } private void setResourceManager(ResourceManager manager) { for (SVGShape shape : list) shape.setResourceManager(manager); } public Dimension getSize() { if (!isInit) init(); return size; } }