1 package org.simantics.diagram.svg.export;
\r
3 import java.awt.Graphics2D;
\r
4 import java.awt.Point;
\r
5 import java.awt.RenderingHints;
\r
6 import java.awt.geom.AffineTransform;
\r
7 import java.awt.geom.Rectangle2D;
\r
8 import java.io.StringWriter;
\r
9 import java.util.UUID;
\r
11 import org.apache.batik.dom.GenericDOMImplementation;
\r
12 import org.apache.batik.svggen.SVGGraphics2D;
\r
13 import org.simantics.g2d.canvas.ICanvasContext;
\r
14 import org.simantics.g2d.diagram.DiagramHints;
\r
15 import org.simantics.g2d.diagram.DiagramUtils;
\r
16 import org.simantics.g2d.diagram.IDiagram;
\r
17 import org.simantics.g2d.participant.TransformUtil;
\r
18 import org.simantics.scenegraph.g2d.G2DRenderingHints;
\r
19 import org.simantics.scenegraph.utils.QualityHints;
\r
20 import org.simantics.utils.page.MarginUtils;
\r
21 import org.simantics.utils.page.MarginUtils.Margin;
\r
22 import org.simantics.utils.page.MarginUtils.Margins;
\r
23 import org.w3c.dom.DOMImplementation;
\r
24 import org.w3c.dom.Document;
\r
25 import org.w3c.dom.Element;
\r
29 * org.simantics.diagram.export.ImageBuilder with SVG support
\r
31 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
\r
34 public class SVGBuilder {
\r
42 * @param file File to write the image (optional)
\r
43 * @param dpi Dots Per Inch
\r
44 * @param size Image size in pixels
\r
45 * @param margin percentage of image width for margins. 0.05 is 5%.
\r
47 public SVGBuilder(Double dpi, Point size, double margin) {
\r
50 this.margin = Math.max(margin,0.0);
\r
51 this.margins = null;
\r
56 * @param file File to write the image (optional)
\r
57 * @param dpi Dots Per Inch
\r
58 * @param size Image size in pixels
\r
59 * @param margins Margins
\r
61 public SVGBuilder(Double dpi, Point size, Margins margins) {
\r
65 this.margins = margins;
\r
68 public static SVGGraphics2D defaultSVGGenerator() {
\r
69 DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
\r
71 // Create an instance of org.w3c.dom.Document.
\r
72 String svgNS = "http://www.w3.org/2000/svg";
\r
73 Document document = domImpl.createDocument(svgNS, "svg", null);
\r
75 // Create an instance of the SVG Generator.
\r
76 SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
\r
77 svgGenerator.getGeneratorContext().setIDGenerator(new UniqueIDGenerator(UUID.randomUUID().toString()));
\r
78 return svgGenerator;
\r
82 * @param canvasContext
\r
83 * the canvas context to paint
\r
84 * @param writeResults
\r
85 * <code>true</code> to actually write the resulting Image to the file.
\r
87 public String paint(ICanvasContext canvasContext) throws Exception {
\r
88 return paint(canvasContext, defaultSVGGenerator());
\r
92 * @param canvasContext
\r
93 * the canvas context to paint
\r
95 * the svg generator to use
\r
96 * @param writeResults
\r
97 * <code>true</code> to actually write the resulting Image to the file.
\r
99 public String paint(ICanvasContext canvasContext, SVGGraphics2D svgGenerator) throws Exception {
\r
101 Graphics2D g2 = svgGenerator;
\r
103 IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
\r
104 Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);
\r
106 if (diagramRect == null)
\r
107 diagramRect = new Rectangle2D.Double(0, 0, 100, 100);
\r
109 // add margins to content.
\r
110 double off = Math.max(diagramRect.getWidth(), diagramRect.getHeight()) * margin*0.5;
\r
111 diagramRect = new Rectangle2D.Double(diagramRect.getX() - off, diagramRect.getY() - off, diagramRect.getWidth() + off * 2.0, diagramRect.getHeight() + off * 2.0);
\r
113 if (margins != null) {
\r
114 diagramRect = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(diagramRect,
\r
115 margins.top.diagramAbsolute,
\r
116 margins.bottom.diagramAbsolute,
\r
117 margins.left.diagramAbsolute,
\r
118 margins.right.diagramAbsolute
\r
122 // Make sure the transformation is reset.
\r
123 AffineTransform tr = new AffineTransform();
\r
125 Rectangle2D controlArea;
\r
127 double mmToInch = 1.0 / 25.4;
\r
128 controlArea = new Rectangle2D.Double(0, 0, diagramRect.getWidth() * mmToInch * dpi, diagramRect.getHeight() * mmToInch * dpi);
\r
130 if (margins != null) {
\r
131 double w = controlArea.getWidth();
\r
132 double h = controlArea.getHeight();
\r
133 controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,
\r
134 margins.top.controlAbsolute + margins.top.controlRelative * h,
\r
135 margins.bottom.controlAbsolute + margins.bottom.controlRelative * h,
\r
136 margins.left.controlAbsolute + margins.left.controlRelative * w,
\r
137 margins.right.controlAbsolute + margins.right.controlRelative * w
\r
141 controlArea = new Rectangle2D.Double(0, 0, size.getX(), size.getY());
\r
142 if (margins != null) {
\r
143 double w = controlArea.getWidth();
\r
144 double h = controlArea.getHeight();
\r
145 controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,
\r
146 -(margins.top.controlAbsolute + margins.top.controlRelative * h),
\r
147 -(margins.bottom.controlAbsolute + margins.bottom.controlRelative * h),
\r
148 -(margins.left.controlAbsolute + margins.left.controlRelative * w),
\r
149 -(margins.right.controlAbsolute + margins.right.controlRelative * w)
\r
154 canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);
\r
156 float width = (float)controlArea.getWidth();
\r
157 float height = (float)controlArea.getHeight();
\r
160 QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);
\r
161 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
\r
164 g2.setTransform(tr);
\r
165 g2.setClip(new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
\r
167 g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
\r
169 if (canvasContext.isLocked())
\r
170 throw new IllegalStateException("cannot render image, canvas context is locked: " + canvasContext);
\r
172 canvasContext.getSceneGraph().render(g2);
\r
176 Element root = svgGenerator.getRoot();
\r
177 root.setAttributeNS(null, "viewBox", "0 0 " + width + " " + height);
\r
178 root.setAttributeNS(null, "height", Float.toString(height));
\r
179 root.setAttributeNS(null, "width", Float.toString(width));
\r
181 // Finally, stream out SVG to the standard output using
\r
183 boolean useCSS = false; // we want to use CSS style attributes
\r
184 StringWriter writer = new StringWriter();
\r
185 //svgGenerator.stream(writer, useCSS);
\r
186 svgGenerator.stream(root,writer, useCSS, false);
\r
187 return writer.toString();
\r