--- /dev/null
+package org.simantics.diagram.svg.export;\r
+\r
+import java.awt.Graphics2D;\r
+import java.awt.Point;\r
+import java.awt.RenderingHints;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.StringWriter;\r
+import java.util.UUID;\r
+\r
+import org.apache.batik.dom.GenericDOMImplementation;\r
+import org.apache.batik.svggen.SVGGraphics2D;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.DiagramUtils;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.scenegraph.g2d.G2DRenderingHints;\r
+import org.simantics.scenegraph.utils.QualityHints;\r
+import org.simantics.utils.page.MarginUtils;\r
+import org.simantics.utils.page.MarginUtils.Margin;\r
+import org.simantics.utils.page.MarginUtils.Margins;\r
+import org.w3c.dom.DOMImplementation;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+\r
+/**\r
+ * org.simantics.diagram.export.ImageBuilder with SVG support \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class SVGBuilder {\r
+ Double dpi;\r
+ Point size;\r
+ double margin;\r
+ Margins margins;\r
+ \r
+ /**\r
+ * \r
+ * @param file File to write the image (optional)\r
+ * @param dpi Dots Per Inch\r
+ * @param size Image size in pixels\r
+ * @param margin percentage of image width for margins. 0.05 is 5%.\r
+ */\r
+ public SVGBuilder(Double dpi, Point size, double margin) {\r
+ this.dpi = dpi;\r
+ this.size = size;\r
+ this.margin = Math.max(margin,0.0);\r
+ this.margins = null;\r
+ }\r
+\r
+ /**\r
+ * \r
+ * @param file File to write the image (optional)\r
+ * @param dpi Dots Per Inch\r
+ * @param size Image size in pixels\r
+ * @param margins Margins\r
+ */\r
+ public SVGBuilder(Double dpi, Point size, Margins margins) {\r
+ this.dpi = dpi;\r
+ this.size = size;\r
+ this.margin = 0.0;\r
+ this.margins = margins;\r
+ }\r
+ \r
+ public static SVGGraphics2D defaultSVGGenerator() {\r
+ DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();\r
+ \r
+ // Create an instance of org.w3c.dom.Document.\r
+ String svgNS = "http://www.w3.org/2000/svg";\r
+ Document document = domImpl.createDocument(svgNS, "svg", null);\r
+ \r
+ // Create an instance of the SVG Generator.\r
+ SVGGraphics2D svgGenerator = new SVGGraphics2D(document);\r
+ svgGenerator.getGeneratorContext().setIDGenerator(new UniqueIDGenerator(UUID.randomUUID().toString()));\r
+ return svgGenerator;\r
+ }\r
+\r
+ /**\r
+ * @param canvasContext\r
+ * the canvas context to paint\r
+ * @param writeResults\r
+ * <code>true</code> to actually write the resulting Image to the file.\r
+ */\r
+ public String paint(ICanvasContext canvasContext) throws Exception {\r
+ return paint(canvasContext, defaultSVGGenerator());\r
+ }\r
+ \r
+ /**\r
+ * @param canvasContext\r
+ * the canvas context to paint\r
+ * svgGenerator \r
+ * the svg generator to use\r
+ * @param writeResults\r
+ * <code>true</code> to actually write the resulting Image to the file.\r
+ */\r
+ public String paint(ICanvasContext canvasContext, SVGGraphics2D svgGenerator) throws Exception {\r
+ \r
+ Graphics2D g2 = svgGenerator;\r
+ \r
+ IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);\r
+ Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);\r
+\r
+ if (diagramRect == null)\r
+ diagramRect = new Rectangle2D.Double(0, 0, 100, 100);\r
+\r
+ // add margins to content.\r
+ double off = Math.max(diagramRect.getWidth(), diagramRect.getHeight()) * margin*0.5;\r
+ diagramRect = new Rectangle2D.Double(diagramRect.getX() - off, diagramRect.getY() - off, diagramRect.getWidth() + off * 2.0, diagramRect.getHeight() + off * 2.0);\r
+\r
+ if (margins != null) {\r
+ diagramRect = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(diagramRect,\r
+ margins.top.diagramAbsolute,\r
+ margins.bottom.diagramAbsolute,\r
+ margins.left.diagramAbsolute,\r
+ margins.right.diagramAbsolute\r
+ );\r
+ }\r
+ \r
+ // Make sure the transformation is reset.\r
+ AffineTransform tr = new AffineTransform();\r
+\r
+ Rectangle2D controlArea;\r
+ if (dpi != null) {\r
+ double mmToInch = 1.0 / 25.4;\r
+ controlArea = new Rectangle2D.Double(0, 0, diagramRect.getWidth() * mmToInch * dpi, diagramRect.getHeight() * mmToInch * dpi);\r
+\r
+ if (margins != null) {\r
+ double w = controlArea.getWidth();\r
+ double h = controlArea.getHeight();\r
+ controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,\r
+ margins.top.controlAbsolute + margins.top.controlRelative * h,\r
+ margins.bottom.controlAbsolute + margins.bottom.controlRelative * h,\r
+ margins.left.controlAbsolute + margins.left.controlRelative * w,\r
+ margins.right.controlAbsolute + margins.right.controlRelative * w\r
+ );\r
+ }\r
+ } else {\r
+ controlArea = new Rectangle2D.Double(0, 0, size.getX(), size.getY());\r
+ if (margins != null) {\r
+ double w = controlArea.getWidth();\r
+ double h = controlArea.getHeight();\r
+ controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,\r
+ -(margins.top.controlAbsolute + margins.top.controlRelative * h),\r
+ -(margins.bottom.controlAbsolute + margins.bottom.controlRelative * h),\r
+ -(margins.left.controlAbsolute + margins.left.controlRelative * w),\r
+ -(margins.right.controlAbsolute + margins.right.controlRelative * w)\r
+ );\r
+ }\r
+ }\r
+\r
+ canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);\r
+ \r
+ float width = (float)controlArea.getWidth();\r
+ float height = (float)controlArea.getHeight();\r
+ \r
+\r
+ QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);\r
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);\r
+\r
+\r
+ g2.setTransform(tr);\r
+ g2.setClip(new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));\r
+\r
+ g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));\r
+\r
+ if (canvasContext.isLocked())\r
+ throw new IllegalStateException("cannot render image, canvas context is locked: " + canvasContext);\r
+\r
+ canvasContext.getSceneGraph().render(g2);\r
+ \r
+\r
+ \r
+ Element root = svgGenerator.getRoot();\r
+ root.setAttributeNS(null, "viewBox", "0 0 " + width + " " + height); \r
+ root.setAttributeNS(null, "height", Float.toString(height));\r
+ root.setAttributeNS(null, "width", Float.toString(width));\r
+ \r
+ // Finally, stream out SVG to the standard output using\r
+ // UTF-8 encoding.\r
+ boolean useCSS = false; // we want to use CSS style attributes\r
+ StringWriter writer = new StringWriter();\r
+ //svgGenerator.stream(writer, useCSS);\r
+ svgGenerator.stream(root,writer, useCSS, false);\r
+ return writer.toString();\r
+ }\r
+}\r