There is an XML-file, containing parameters of the most generic shapes. You should load it into stylesheet to make images look exactly as they were drawn in editor. Default stylesheet is default.xml.
So first of all make your code to get 2 things: stylesheet and diagram content.
String diagramText = getAsString(diagramPath);
String stylesheetText = getAsString(stylesheetPath);
Next, the simplest way to create SVG image is to utilize classes from mxgraph-core.jar. It looks like this
mxStylesheet stylesheet = new mxStylesheet(); // mxgraph-core.jar
InputSource is = new InputSource(new StringReader(stylesheetText));
Document document = documentBuilder.parse(is);
mxCodec codec = new mxCodec(document);
codec.decode(document.getDocumentElement(), stylesheet);
mxIGraphModel model = new mxGraphModel();
mxGraph graph = new mxGraph(model, context.stylesheet);
is = new InputSource(new StringReader(diagramText));
document = documentBuilder.parse(new InputSource(is));
codec = new mxCodec(document);
codec.decode(document.getDocumentElement(), model);
final Document svgDocument = documentBuilder.newDocument();
mxCellRenderer.drawCells(
graph,
null,
1d,
null,
new mxCellRenderer.CanvasFactory() {
@Override
public mxICanvas createCanvas(int width, int height) {
Element root = output.createElement("svg");
String w = Integer.toString(width);
String h = Integer.toString(height);
root.setAttribute("width", w);
root.setAttribute("height", h);
root.setAttribute("viewBox", "0 0 " + w + " " + h);
root.setAttribute("version", "1.1");
root.setAttribute("xmlns", "http://www.w3.org/2000/svg");
root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
output.appendChild(root);
mxSvgCanvas canvas = new mxSvgCanvas(svgDocument);
canvas.setEmbedded(true);
return canvas;
}
});
return svgDocument; // this is the result
However, as SergGr pointed, Java implementation of mxgraph library doesn't contain some useful shapes. Their drawing rules are described by JavaScript functions in Shape.js.
I tried to execute that JavaScript in ScriptEngine shipped in Java standard library. Unfortunately this idea didn't work, because the JavaScript code somewhere deep inside interacts with browser.
But if we run the code in a browser, it works well. I did it successfully with HtmlUnit.
Write a JavaScript function to call from Java:
function convertToSVG(diagramText, stylesheetText) {
var stylesheet = new mxStylesheet();
var doc = mxUtils.parseXml(stylesheetText);
var stylesheetRoot = doc.documentElement;
var stylesheetCodec = new mxCodec(doc);
var dom = document.implementation;
stylesheetCodec.decode(stylesheetRoot, stylesheet);
doc = dom.createDocument(null, "div", null);
var model = new mxGraphModel();
var graph = new mxGraph(doc.documentElement, model, "exact", stylesheet);
doc = new DOMParser().parseFromString(diagram, "text/xml");
var codec = new mxCodec(doc);
codec.decode(doc.documentElement, model);
doc = dom.createDocument("http://www.w3.org/2000/svg", "svg", null);
var svgRoot = doc.documentElement;
var bounds = graph.getGraphBounds();
svgRoot.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgRoot.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
svgRoot.setAttribute("width", bounds.width);
svgRoot.setAttribute("height", bounds.height);
svgRoot.setAttribute("viewBox", "0 0 " + bounds.width + " " + bounds.height);
svgRoot.setAttribute("version", "1.1");
var svgCanvas = new mxSvgCanvas2D(svgRoot);
svgCanvas.translate(-bounds.x, -bounds.y);
var exporter = new mxImageExport();
var state = graph.getView().getState(model.root);
exporter.drawState(state, svgCanvas);
var result = new XMLSerializer().serializeToString(doc);
return result;
}
Load this text into String and run the following code
String jsFunction = getAsString("convertToSVG.js");
Path file = Files.createTempFile("44179673-", ".html"); // do not forget to delete it
String hmltText = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head><title>Empty file</title></head><body/></html>";
Files.write(file, Arrays.asList(htmlText));
WebClient webClient = new WebClient(); // net.sourceforge.htmlunit:htmlunit
HtmlPage page = webClient.getPage(file.toUri().toString());
String initScript = ""
+ "var mxLoadResources = false;"
+ "var mxLoadStylesheets = false;"
+ "var urlParams = new Object();";
page.executeJavaScript(initScript);
page.executeJavaScript(getAsString("mxClient.min.js"));
page.executeJavaScript(getAsString("Graph.js")); // Shape.js depends on it
page.executeJavaScript(getAsString("Shapes.js"));
ScriptResult scriptResult = page.executeJavaScript(jsFunction);
Object convertFunc = scriptResult.getJavaScriptResult();
Object args[] = new Object[]{ diagramText, stylesheetText };
scriptResult = page.executeJavaScriptFunction(convertFunc, null, args, null);
String svg = scriptResult.getJavaScriptResult().toString();
The code above seems to work well for me.