As SVG (Scalable Vector Graphics) is emerging as a promising graphics format
for a wide range of domains and applications, bridging it with Java becomes important.
This page explains how Batik's SVGGraphics2D
, referred to as the SVG Generator, makes
this possible. It is divided into three parts:
SVGGraphics2D
?SVGGraphics2D
?
On the Java platform, all rendering goes through the java.awt.Graphics2D
abstract class, which offers methods such as drawRect
, fillRect
, or
drawString
. There are specialized
implementations of this abstract class for each type of output, such as a monitor or a printer.
SVGGraphics2D
is a new implementation of that interface that generates SVG content instead of
drawing to a screen or a printer.
SVGGraphics2D
provides the following:
The above figure shows how the generator works with the DOM API. The W3C has defined an API for representing
XML content with a Java programming language object. That API allows programmers to manipulate, create,
and/or modify XML content in memory. The DOM API contains interfaces such as Document
,
Element
, and Attr
,
which model the Java programming language equivalent of XML documents, elements and attributes.
The generator manages a tree of DOM objects that represent the SVG content corresponding to the rendering
calls made on the SVGGraphics2D
instance. In other words, every time a program invokes a rendering method,
such as fillRect
, on a SVGGraphics2D
instance, a new DOM object, representing
the SVG equivalent, is appended
to the DOM tree (for example a <rect> element will be appended after the fillRect
method
has been invoked).
The programmer using this generator can then access the DOM tree to further manipulate it or can directly write the content to an output stream, as we see in the following section.
From the figure in the previous section we can see that in order for an instance of SVGGraphics2D
to build
the SVG content (the DOM tree), an instance of DOM's Document
class is needed. The DOM tree is an in-memory
representation of the SVG document, which can be further manipulated by the user using DOM API or be streamed
out into any java.io.Writer
.
The following excerpted code example shows how to generate SVG content from Java graphics.
We can see that generating SVG content from our TestSVGGen
instance is a three step
process:
1. Create an instance of org.w3c.dom.Document
that the generator will use to build its XML content;
create an SVG generator using the Document
instance.
2. Invoke the rendering code on our SVG generator. In our example, we invoke TestSVGGen
's
paint
method:
3. Stream out the SVG content. The SVG generator can stream its content into any java.io.Writer
. In our
example, we stream the content to the standard output stream:
SVG has two ways of expressing properties, such as the fill color: either XML attributes or CSS inline properties. The 'useCss' parameter allows the user to control that option.
In the previous section, we have just seen that the SVG generation process can be customized to output SVG style as XML attributes or CSS inline properties. In this section we will talk about some examples of more advanced customizations.
Instead of creating the SVGGraphics2D
just by using the Document
that will be used as a factory for creating the SVG elements, we can use the constructor that use an SVGGeneratorContext
instance. By providing your own SVGGeneratorContext
instance, you will be able to do advanced customization. You will find below several examples of possible customizations.
We begin with the simplest possible example. If you integrate the Batik SVG generator in your own Java application, you may want to specialize the comment generated in the XML code. You can proceed as below.
In order to have a self-contained SVG file that doesn't have to use system fonts to be displayed, you can embed the fonts you used for drawing strings in the SVG file through the SVG fonts facility.
Every time you call one of the drawImage
methods provided by the Graphics2D
class,
a default representation of your image is created in a location and put in a default file. For instance, a base64
encoding is created and embedded in the SVG file by default. Alternatively, you
can choose to have your images written to separate files in a predefined directory, in one of the two raster
formats required by the SVG specification, JPEG, PNG or Tiff.
You can change the default behavior by explicitly providing the image handler to be used by the SVG generator. Once again, you use the SVGGeneratorContext for this. In the example below, all images are converted to PNG format and written to directory "res/images".
Using the default image handlers results in a new copy of the image data being written to the SVG file or an
external file, for every single drawImage
call. If you use the same images over and over again,
then this may result in an SVG file containing a lot of redundant data. At the price of a slight performance
penalty during initial generation of the SVG DOM tree, you can choose to have your image data reused. For this
you use a specialized image handler, as shown below.
With the caching image handlers, it is even possible to reuse the same copy of your image data across
several different SVG documents. Just keep a reference to the image handler, and pass it to the
SVGGraphics2D
instance used for generating the SVG DOM tree. The following
simplified example shows how different SVG trees might be created by separate SVG generators,
efficiently storing any common images just once.
Your needs in matter of styling may be different from the two provided options (XML attributes or CSS inline properties). For example you may want to put the CSS properties in a stylesheet SVG element section and reference them through the class attribute. In this case you will need to define a new StyleHandler
as below.
Then you can create and use an SVGGraphics2D
with a correctly configured
SVGGeneratorContext
.
The SVGGraphics2D
is able to generate SVG elements for generic Java 2D objects, but you sometimes have your own classes such as implementations of the Java 2D java.awt.Paint
interface. In this case, you will need to write an ExtensionHandler
that you will set on your SVGGeneratorContext
.
In the following example we define the first draft of an ExtensionHandler
allowing to translate a Batik implementation of the java.awt.Paint
interface named org.apache.batik.ext.awt.LinearGradientPaint
.
You should then set it on the SVGGeneratorContext
by using the setExtensionHandler
method.
The following code example illustrates how to view the SVG content generated
by an SVGGraphics2D
object.