]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.svg/src/org/simantics/diagram/svg/export/SVGBuilder.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.diagram.svg / src / org / simantics / diagram / svg / export / SVGBuilder.java
1 package org.simantics.diagram.svg.export;
2
3 import java.awt.Graphics2D;
4 import java.awt.Point;
5 import java.awt.RenderingHints;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.Rectangle2D;
8 import java.io.StringWriter;
9 import java.util.UUID;
10
11 import org.apache.batik.dom.GenericDOMImplementation;
12 import org.apache.batik.svggen.SVGGraphics2D;
13 import org.simantics.g2d.canvas.ICanvasContext;
14 import org.simantics.g2d.diagram.DiagramHints;
15 import org.simantics.g2d.diagram.DiagramUtils;
16 import org.simantics.g2d.diagram.IDiagram;
17 import org.simantics.g2d.participant.TransformUtil;
18 import org.simantics.scenegraph.g2d.G2DRenderingHints;
19 import org.simantics.scenegraph.utils.QualityHints;
20 import org.simantics.utils.page.MarginUtils;
21 import org.simantics.utils.page.MarginUtils.Margins;
22 import org.w3c.dom.DOMImplementation;
23 import org.w3c.dom.Document;
24 import org.w3c.dom.Element;
25
26
27 /**
28  * org.simantics.diagram.export.ImageBuilder with SVG support 
29  * 
30  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
31  *
32  */
33 public class SVGBuilder {
34         Double dpi;
35         Point size;
36         double margin;
37         Margins margins;
38         
39         /**
40          * 
41          * @param file File to write the image (optional)
42          * @param dpi Dots Per Inch
43          * @param size Image size in pixels
44          * @param margin percentage of image width for margins. 0.05 is 5%.
45          */
46         public SVGBuilder(Double dpi, Point size, double margin) {
47                 this.dpi = dpi;
48                 this.size = size;
49                 this.margin = Math.max(margin,0.0);
50                 this.margins = null;
51         }
52
53         /**
54          * 
55          * @param file File to write the image (optional)
56          * @param dpi Dots Per Inch
57          * @param size Image size in pixels
58          * @param margins Margins
59          */
60         public SVGBuilder(Double dpi, Point size, Margins margins) {
61                 this.dpi = dpi;
62                 this.size = size;
63                 this.margin = 0.0;
64                 this.margins = margins;
65         }
66         
67         public static SVGGraphics2D defaultSVGGenerator() {
68                 DOMImplementation domImpl =  GenericDOMImplementation.getDOMImplementation();
69                 
70                 // Create an instance of org.w3c.dom.Document.
71             String svgNS = "http://www.w3.org/2000/svg";
72             Document document = domImpl.createDocument(svgNS, "svg", null);
73         
74             // Create an instance of the SVG Generator.
75             SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
76             svgGenerator.getGeneratorContext().setIDGenerator(new UniqueIDGenerator(UUID.randomUUID().toString()));
77             return svgGenerator;
78         }
79
80         /**
81          * @param canvasContext
82          *            the canvas context to paint
83          * @param writeResults
84          *            <code>true</code> to actually write the resulting Image to the file.
85          */
86         public String paint(ICanvasContext canvasContext) throws Exception {
87                 return paint(canvasContext, defaultSVGGenerator());
88         }
89         
90         /**
91          * @param canvasContext
92          *            the canvas context to paint
93          *        svgGenerator 
94          *            the svg generator to use
95          * @param writeResults
96          *            <code>true</code> to actually write the resulting Image to the file.
97          */
98         public String paint(ICanvasContext canvasContext, SVGGraphics2D svgGenerator) throws Exception {
99                 
100                 Graphics2D g2 = svgGenerator;
101                 
102                 IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
103                 Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);
104
105                 if (diagramRect == null)
106                         diagramRect = new Rectangle2D.Double(0, 0, 100, 100);
107
108                 // add margins to content.
109                 double off = Math.max(diagramRect.getWidth(), diagramRect.getHeight()) * margin*0.5;
110                 diagramRect = new Rectangle2D.Double(diagramRect.getX() - off, diagramRect.getY() - off, diagramRect.getWidth() + off * 2.0, diagramRect.getHeight() + off * 2.0);
111
112                 if (margins != null) {
113                         diagramRect = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(diagramRect,
114                                         margins.top.diagramAbsolute,
115                                         margins.bottom.diagramAbsolute,
116                                         margins.left.diagramAbsolute,
117                                         margins.right.diagramAbsolute
118                                         );
119                 }
120                 
121                 // Make sure the transformation is reset.
122                 AffineTransform tr = new AffineTransform();
123
124                 Rectangle2D controlArea;
125                 if (dpi != null) {
126                         double mmToInch = 1.0 / 25.4;
127                         controlArea = new Rectangle2D.Double(0, 0, diagramRect.getWidth() * mmToInch * dpi, diagramRect.getHeight() * mmToInch * dpi);
128
129                         if (margins != null) {
130                                 double w = controlArea.getWidth();
131                                 double h = controlArea.getHeight();
132                                 controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,
133                                                 margins.top.controlAbsolute + margins.top.controlRelative * h,
134                                                 margins.bottom.controlAbsolute + margins.bottom.controlRelative * h,
135                                                 margins.left.controlAbsolute + margins.left.controlRelative * w,
136                                                 margins.right.controlAbsolute + margins.right.controlRelative * w
137                                                 );
138                         }
139                 } else {
140                         controlArea = new Rectangle2D.Double(0, 0, size.getX(), size.getY());
141                         if (margins != null) {
142                                 double w = controlArea.getWidth();
143                                 double h = controlArea.getHeight();
144                                 controlArea = org.simantics.scenegraph.utils.GeometryUtils.expandRectangle(controlArea,
145                                                 -(margins.top.controlAbsolute + margins.top.controlRelative * h),
146                                                 -(margins.bottom.controlAbsolute + margins.bottom.controlRelative * h),
147                                                 -(margins.left.controlAbsolute + margins.left.controlRelative * w),
148                                                 -(margins.right.controlAbsolute + margins.right.controlRelative * w)
149                                                 );
150                         }
151                 }
152
153                 canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);
154                 
155                 float width = (float)controlArea.getWidth();
156                 float height = (float)controlArea.getHeight();
157                 
158
159                 QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);
160                 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
161
162
163                 g2.setTransform(tr);
164                 g2.setClip(new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
165
166                 g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
167
168                 if (canvasContext.isLocked())
169                         throw new IllegalStateException("cannot render image, canvas context is locked: " + canvasContext);
170
171                 canvasContext.getSceneGraph().render(g2);
172                         
173
174                 
175                 Element root = svgGenerator.getRoot();
176                 root.setAttributeNS(null, "viewBox", "0 0 " + width + " " + height); 
177                 root.setAttributeNS(null, "height", Float.toString(height));
178                 root.setAttributeNS(null, "width", Float.toString(width));
179                 
180                 // Finally, stream out SVG to the standard output using
181             // UTF-8 encoding.
182             boolean useCSS = false; // we want to use CSS style attributes
183             StringWriter writer = new StringWriter();
184             //svgGenerator.stream(writer, useCSS);
185             svgGenerator.stream(root,writer, useCSS, false);
186             return writer.toString();
187         }
188 }