[Home] DMelt member access. Java source code: net.sourceforge.plantuml.svg.SvgGraphics
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2017, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.svg;
import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.SvgString;
import net.sourceforge.plantuml.code.Base64Coder;
import net.sourceforge.plantuml.eps.EpsGraphics;
import net.sourceforge.plantuml.graphic.HtmlColorGradient;
import net.sourceforge.plantuml.ugraphic.ColorMapper;
import net.sourceforge.plantuml.ugraphic.UPath;
import net.sourceforge.plantuml.ugraphic.USegment;
import net.sourceforge.plantuml.ugraphic.USegmentType;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class SvgGraphics {
// http://tutorials.jenkov.com/svg/index.html
// http://www.svgbasics.com/
// http://apike.ca/prog_svg_text.html
// http://www.w3.org/TR/SVG11/shapes.html
// http://en.wikipedia.org/wiki/Scalable_Vector_Graphics
// Animation:
// http://srufaculty.sru.edu/david.dailey/svg/
// Shadow:
// http://www.svgbasics.com/filters3.html
// http://www.w3schools.com/svg/svg_feoffset.asp
// http://www.adobe.com/svg/demos/samples.html
final private Document document;
final private Element root;
final private Element defs;
final private Element gRoot;
private String fill = "black";
private String stroke = "black";
private String strokeWidth;
private String strokeDasharray = null;
private final String backcolor;
private int maxX = 10;
private int maxY = 10;
private final double scale;
private final String filterUid;
private final String shadowId;
private final String gradientId;
final protected void ensureVisible(double x, double y) {
if (x > maxX) {
maxX = (int) (x + 1);
}
if (y > maxY) {
maxY = (int) (y + 1);
}
}
public SvgGraphics(Dimension2D minDim, double scale, String hover, long seed) {
this(minDim, null, scale, hover, seed);
}
public SvgGraphics(Dimension2D minDim, String backcolor, double scale, String hover, long seed) {
try {
this.scale = scale;
this.document = getDocument();
this.backcolor = backcolor;
ensureVisible(minDim.getWidth(), minDim.getHeight());
this.root = getRootNode();
// Create a node named defs, which will be the parent
// for a pair of linear gradient definitions.
defs = simpleElement("defs");
gRoot = simpleElement("g");
strokeWidth = "" + scale;
this.filterUid = "b" + getSeed(seed);
this.shadowId = "f" + getSeed(seed);
this.gradientId = "g" + getSeed(seed);
if (hover != null) {
defs.appendChild(getPathHover(hover));
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
throw new IllegalStateException(e);
}
}
private Element getPathHover(String hover) {
final Element style = simpleElement("style");
final CDATASection cdata = document.createCDATASection("path:hover { stroke: " + hover + " !important;}");
style.setAttribute("type", "text/css");
style.appendChild(cdata);
return style;
}
private static String getSeed(final long seed) {
return Long.toString(Math.abs(seed), 36);
}
private Element pendingBackground;
public void paintBackcolorGradient(ColorMapper mapper, HtmlColorGradient gr) {
final String id = createSvgGradient(StringUtils.getAsHtml(mapper.getMappedColor(gr.getColor1())),
StringUtils.getAsHtml(mapper.getMappedColor(gr.getColor2())), gr.getPolicy());
setFillColor("url(#" + id + ")");
setStrokeColor(null);
pendingBackground = createRectangleInternal(0, 0, 0, 0);
getG().appendChild(pendingBackground);
}
// This method returns a reference to a simple XML
// element node that has no attributes.
private Element simpleElement(String type) {
final Element theElement = (Element) document.createElement(type);
root.appendChild(theElement);
return theElement;
}
private Document getDocument() throws ParserConfigurationException {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document document = builder.newDocument();
document.setXmlStandalone(true);
return document;
}
// This method returns a reference to a root node that
// has already been appended to the document.
private Element getRootNode() {
// Create the root node named svg and append it to
// the document.
final Element svg = (Element) document.createElement("svg");
document.appendChild(svg);
// Set some attributes on the root node that are
// required for proper rendering. Note that the
// approach used here is somewhat different from the
// approach used in the earlier program named Svg01,
// particularly with regard to the style.
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
svg.setAttribute("version", "1.1");
return svg;
}
public void svgEllipse(double x, double y, double xRadius, double yRadius, double deltaShadow) {
manageShadow(deltaShadow);
if (hidden == false) {
final Element elt = (Element) document.createElement("ellipse");
elt.setAttribute("cx", format(x));
elt.setAttribute("cy", format(y));
elt.setAttribute("rx", format(xRadius));
elt.setAttribute("ry", format(yRadius));
elt.setAttribute("fill", fill);
elt.setAttribute("style", getStyle());
addFilterShadowId(elt, deltaShadow);
getG().appendChild(elt);
}
ensureVisible(x + xRadius + deltaShadow * 2, y + yRadius + deltaShadow * 2);
}
public void svgArcEllipse(double rx, double ry, double x1, double y1, double x2, double y2) {
if (hidden == false) {
final String path = "M" + format(x1) + "," + format(y1) + " A" + format(rx) + "," + format(ry) + " 0 0 0 "
+ format(x2) + " " + format(y2);
final Element elt = (Element) document.createElement("path");
elt.setAttribute("d", path);
elt.setAttribute("fill", fill);
elt.setAttribute("style", getStyle());
getG().appendChild(elt);
}
ensureVisible(x1, y1);
ensureVisible(x2, y2);
}
private Map, String> gradients = new HashMap, String>();
public String createSvgGradient(String color1, String color2, char policy) {
final List