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