If using gradle, the minimal dependencies can be included using:
implementation 'org.apache.xmlgraphics:batik-anim:1.13'
implementation 'org.apache.xmlgraphics:batik-awt-util:1.13'
implementation 'org.apache.xmlgraphics:batik-bridge:1.13'
implementation 'org.apache.xmlgraphics:batik-css:1.13'
implementation 'org.apache.xmlgraphics:batik-dom:1.13'
implementation 'org.apache.xmlgraphics:batik-ext:1.13'
implementation 'org.apache.xmlgraphics:batik-gvt:1.13'
implementation 'org.apache.xmlgraphics:batik-parser:1.13'
implementation 'org.apache.xmlgraphics:batik-script:1.13'
implementation 'org.apache.xmlgraphics:batik-svg-dom:1.13'
implementation 'org.apache.xmlgraphics:batik-svggen:1.13'
implementation 'org.apache.xmlgraphics:batik-transcoder:1.13'
implementation 'org.apache.xmlgraphics:batik-util:1.13'
implementation 'org.apache.xmlgraphics:batik-xml:1.13'
JasperReports 5.0 suggests essentially the same collection when deploying reports to a server. The difference is that batik-transcoder (relatively new?) isn't on their list (though I imagine it is required for later versions of JasperReports):
batik-anim.jar
batik-awt-util.jar
batik-bridge.jar
batik-css.jar
batik-dom.jar
batik-ext.jar
batik-gvt.jar
batik-parser.jar
batik-script.jar
batik-svg-dom.jar
batik-svggen.jar
batik-util.jar
batik-xml.jar
To get everything:
implementation 'org.apache.xmlgraphics:batik-all:1.13'
Change the version number as necessary.
Note: I've only tested this against two SVG illustrations. Both rendered flawlessly. There could be some dependencies that aren't required (such as batik-anim
) depending on your requirements.
SVG Salamander is another SVG Engine. Lighter than Batik, it isn't as robust. Note that Batik cannot handle textual flowRoot
elements easily and may result in black boxes. Eliminating the black boxes requires removing all flowRoot
elements, which can take some time. (The other possibility is to perform an XSL transformation on the SVG file to fix the flowRoot
issue, but that approach probably won't address all the issues encountered.)
Here's an example SVGRasterizer
class that builds and works with the aforementioned subset of Batik library files:
public class SVGRasterizer {
private final static SAXSVGDocumentFactory mFactory =
new SAXSVGDocumentFactory( getXMLParserClassName() );
private final static Map<Object, Object> RENDERING_HINTS = Map.of(
KEY_ALPHA_INTERPOLATION,
VALUE_ALPHA_INTERPOLATION_QUALITY,
KEY_INTERPOLATION,
VALUE_INTERPOLATION_BICUBIC,
KEY_ANTIALIASING,
VALUE_ANTIALIAS_ON,
KEY_COLOR_RENDERING,
VALUE_COLOR_RENDER_QUALITY,
KEY_DITHERING,
VALUE_DITHER_DISABLE,
KEY_RENDERING,
VALUE_RENDER_QUALITY,
KEY_STROKE_CONTROL,
VALUE_STROKE_PURE,
KEY_FRACTIONALMETRICS,
VALUE_FRACTIONALMETRICS_ON,
KEY_TEXT_ANTIALIASING,
VALUE_TEXT_ANTIALIAS_OFF
);
private static class BufferedImageTranscoder extends ImageTranscoder {
private BufferedImage mImage;
@Override
public BufferedImage createImage( final int w, final int h ) {
return new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB );
}
@Override
public void writeImage(
final BufferedImage image, final TranscoderOutput output ) {
mImage = image;
}
public Image getImage() {
return mImage;
}
@Override
protected ImageRenderer createRenderer() {
final ImageRenderer renderer = super.createRenderer();
final RenderingHints hints = renderer.getRenderingHints();
hints.putAll( RENDERING_HINTS );
renderer.setRenderingHints( hints );
return renderer;
}
}
/**
* Rasterizes the vector graphic file at the given URL. If any exception
* happens, a red circle is returned instead.
*
* @param url The URL to a vector graphic file, which must include the
* protocol scheme (such as file:// or https://).
* @param width The number of pixels wide to render the image. The aspect
* ratio is maintained.
* @return Either the rasterized image upon success or a red circle.
*/
public static Image rasterize( final String url, final int width ) {
try {
return rasterize( new URL( url ), width );
} catch( final Exception e ) {
return createPlaceholderImage( width );
}
}
/**
* Converts an SVG drawing into a rasterized image that can be drawn on
* a graphics context.
*
* @param url The path to the image (can be web address).
* @param width Scale the image width to this size (aspect ratio is
* maintained).
* @return The vector graphic transcoded into a raster image format.
* @throws IOException Could not read the vector graphic.
* @throws TranscoderException Could not convert the vector graphic to an
* instance of {@link Image}.
*/
public static Image rasterize( final URL url, final int width )
throws IOException, TranscoderException {
return rasterize(
(SVGDocument) mFactory.createDocument( url.toString() ), width );
}
public static Image rasterize(
final SVGDocument svg, final int width ) throws TranscoderException {
final var transcoder = new BufferedImageTranscoder();
final var input = new TranscoderInput( svg );
transcoder.addTranscodingHint( KEY_BACKGROUND_COLOR, WHITE );
transcoder.addTranscodingHint( KEY_WIDTH, (float) width );
transcoder.transcode( input, null );
return transcoder.getImage();
}
@SuppressWarnings("SuspiciousNameCombination")
private static Image createPlaceholderImage( final int width ) {
final var image = new BufferedImage( width, width, TYPE_INT_RGB );
final var graphics = (Graphics2D) image.getGraphics();
graphics.setColor( RED );
graphics.setStroke( new BasicStroke( 5 ) );
graphics.drawOval( 5, 5, width / 2, width / 2 );
return image;
}
}