-
Notifications
You must be signed in to change notification settings - Fork 2
SVG Generator
The echosvg-svggen
module can generate SVG images using an SVG-specific Graphics2D
implementation. Assuming that you are familiar with Graphics2D
, the following example shows the basic usage of svggen
.
If your build process is based on Gradle, declare a dependency on echosvg-svggen
:
dependencies {
implementation "io.sf.carte:echosvg-svggen:${echosvgVersion}"
}
Or if you manage your classpath manually, clone this repository and create a fat jar with
./gradlew echosvg-svggen-jar-with-deps
The archive shall be available at echosvg-svggen/build/libs/echosvg-svggen-<version>-with-deps.jar
.
First, let's have an example class that writes to a Graphics2D
. Please change the used fonts if you prefer others, or your system does not have them installed.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;
import java.util.HashMap;
import java.util.Map;
/**
* Draw text with decoration attributes.
*/
public class FontDecorationPainter {
public void paint(Graphics2D g) {
// Set anti-aliasing
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Set a background color
Color backgroundColor = new Color(0x08081a);
g.setBackground(backgroundColor);
// Set default font
g.setFont(new Font("Arial", Font.BOLD, 12));
// Create a font with the desired attributes, including STRIKETHROUGH
Map<TextAttribute, Object> attributes = new HashMap<>();
attributes.put(TextAttribute.FAMILY, "Helvetica");
attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_EXTRABOLD);
attributes.put(TextAttribute.SIZE, 20);
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
Font fontST = new Font(attributes);
// A similar font but with UNDERLINE instead of STRIKETHROUGH
Map<TextAttribute, Object> attributes2 = new HashMap<>(attributes);
attributes2.remove(TextAttribute.STRIKETHROUGH);
attributes2.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
Font fontUL = new Font(attributes2);
// Set the STRIKETHROUGH font and a color
g.setFont(fontST);
g.setPaint(new Color(0x666699));
// Draw a string
g.drawString("Strike Through", 10, 40);
// Now draw with a different color and the UNDERLINE font
g.setPaint(Color.black);
g.setFont(fontUL);
g.translate(0, 30);
// Draw a new string
g.drawString("Underline", 10, 70);
}
}
Then we need a few svggen
classes to produce the SVG.
import java.awt.Dimension;
import java.awt.Font;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import io.sf.carte.echosvg.svggen.SVGGeneratorContext;
import io.sf.carte.echosvg.svggen.SVGGeneratorContext.GraphicContextDefaults;
import io.sf.carte.echosvg.svggen.SVGGraphics2D;
public class SVGGraphics2DExample {
/**
* Generate SVG from the drawings of the <code>FontDecorationPainter</code> class.
*
* @param filename the filename to write the SVG to.
* @throws IOException in case of I/O error.
*/
public static void generateSVG(String filename) throws IOException {
FontDecorationPainter painter = new FontDecorationPainter();
SVGGraphics2D g2d = createSVGGraphics2D();
// Set some appropriate dimension
g2d.setSVGCanvasSize(new Dimension(300, 400));
try (FileWriter fw = new FileWriter(filename, StandardCharsets.UTF_8)) {
painter.paint(g2d);
g2d.stream(fw);
fw.flush();
}
}
/**
* Creates a <code>SVGGraphics2D</code> with certain defaults.
*
* @return the <code>SVGGraphics2D</code>.
*/
static SVGGraphics2D createSVGGraphics2D() {
// We need a Document that holds an SVG root element.
// First obtain a DocumentBuilder as a way to get it.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new IllegalStateException(e);
}
// Now the document which is what is needed
Document doc = builder.newDocument();
// Create a SVG DTD
DocumentType dtd = builder.getDOMImplementation().createDocumentType("svg",
"-//W3C//DTD SVG 1.1//EN",
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd");
// And the root element in the SVG namespace
Element svgRoot = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
// Append those to the document
doc.appendChild(dtd);
doc.appendChild(svgRoot);
/*
* Now the document is ready: let's create some context objects and
* then the SVGGraphics2D.
*/
// For simplicity, create a generator context with some defaults
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc);
// Set a comment to put in the SVG documents, overriding the default
ctx.setComment("Generated by My Application");
// Set a compression higher than the default
ctx.setCompressionLevel(8);
// Create the context defaults, with a default font just in case
GraphicContextDefaults defaults = new GraphicContextDefaults();
defaults.setFont(new Font("Arial", Font.PLAIN, 12));
// Set the defaults
ctx.setGraphicContextDefaults(defaults);
return new SVGGraphics2D(ctx, false);
}
}
and executing the generateSVG("filename.svg")
method, the SVG would be written to the filename.svg
file. Note that so far we haven't used EchoSVG's DOM, as the document was produced with the JDK's built-in DOM.
Since version 1.1 you can generate graphics in color spaces other than sRGB, for example:
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.InputStream;
[...]
Color pColor;
// Load a color profile from classpath
try (InputStream is = getClass().getResourceAsStream(
"/my/color/profiles/Display P3.icc")) {
ICC_Profile profile = ICC_Profile.getInstance(is);
ICC_ColorSpace cs = new ICC_ColorSpace(profile);
float[] comps = { .36f, .35f, .33f };
pColor = new Color(cs, comps, 1f);
} catch (IOException e) {
pColor = new Color(0x5c5954);
}
// Now draw with the new color
g.setPaint(pColor);
The default compression level for embedded rasterized PNG images (via drawImage()
) is 4
, but if the generated SVG is intended to be downloaded multiple times from the Internet, you may want to increase it.
// Set a compression higher than the default
ctx.setCompressionLevel(8);
See SVGGeneratorContext.setCompressionLevel()
.
The Batik website has detailed documentation about using svggen
which you may want to read.