]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.svg/src/org/simantics/diagram/svg/export/SVGBuilder.java
4f2d79b4535e0361edf5f8f48ab183907e00b271
[simantics/platform.git] / bundles / org.simantics.diagram.svg / src / org / simantics / diagram / svg / export / SVGBuilder.java
1 package org.simantics.diagram.svg.export;\r
2 \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
10 \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
26 \r
27 \r
28 /**\r
29  * org.simantics.diagram.export.ImageBuilder with SVG support \r
30  * \r
31  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
32  *\r
33  */\r
34 public class SVGBuilder {\r
35         Double dpi;\r
36         Point size;\r
37         double margin;\r
38         Margins margins;\r
39         \r
40         /**\r
41          * \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
46          */\r
47         public SVGBuilder(Double dpi, Point size, double margin) {\r
48                 this.dpi = dpi;\r
49                 this.size = size;\r
50                 this.margin = Math.max(margin,0.0);\r
51                 this.margins = null;\r
52         }\r
53 \r
54         /**\r
55          * \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
60          */\r
61         public SVGBuilder(Double dpi, Point size, Margins margins) {\r
62                 this.dpi = dpi;\r
63                 this.size = size;\r
64                 this.margin = 0.0;\r
65                 this.margins = margins;\r
66         }\r
67         \r
68         public static SVGGraphics2D defaultSVGGenerator() {\r
69                 DOMImplementation domImpl =  GenericDOMImplementation.getDOMImplementation();\r
70                 \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
74         \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
79         }\r
80 \r
81         /**\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
86          */\r
87         public String paint(ICanvasContext canvasContext) throws Exception {\r
88                 return paint(canvasContext, defaultSVGGenerator());\r
89         }\r
90         \r
91         /**\r
92          * @param canvasContext\r
93          *            the canvas context to paint\r
94          *        svgGenerator \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
98          */\r
99         public String paint(ICanvasContext canvasContext, SVGGraphics2D svgGenerator) throws Exception {\r
100                 \r
101                 Graphics2D g2 = svgGenerator;\r
102                 \r
103                 IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);\r
104                 Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);\r
105 \r
106                 if (diagramRect == null)\r
107                         diagramRect = new Rectangle2D.Double(0, 0, 100, 100);\r
108 \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
112 \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
119                                         );\r
120                 }\r
121                 \r
122                 // Make sure the transformation is reset.\r
123                 AffineTransform tr = new AffineTransform();\r
124 \r
125                 Rectangle2D controlArea;\r
126                 if (dpi != null) {\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
129 \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
138                                                 );\r
139                         }\r
140                 } else {\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
150                                                 );\r
151                         }\r
152                 }\r
153 \r
154                 canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);\r
155                 \r
156                 float width = (float)controlArea.getWidth();\r
157                 float height = (float)controlArea.getHeight();\r
158                 \r
159 \r
160                 QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);\r
161                 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);\r
162 \r
163 \r
164                 g2.setTransform(tr);\r
165                 g2.setClip(new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));\r
166 \r
167                 g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));\r
168 \r
169                 if (canvasContext.isLocked())\r
170                         throw new IllegalStateException("cannot render image, canvas context is locked: " + canvasContext);\r
171 \r
172                 canvasContext.getSceneGraph().render(g2);\r
173                         \r
174 \r
175                 \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
180                 \r
181                 // Finally, stream out SVG to the standard output using\r
182             // UTF-8 encoding.\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
188         }\r
189 }\r