I'm using Batik to work with SVG images. Specifically I have a scene with a number of shapes and I need to be able to convert each shape to a separate BufferedImage. To do this I use the following code:
SVGDocument document = null;
// Load the document
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
File file = new File(inPath);
try {
document = (SVGDocument) f.createDocument(file.toURL().toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Build the tree and get the document dimensions
UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
GVTBuilder builder = new GVTBuilder();
GraphicsNode graphicsNode = builder.build(bridgeContext, document);
CanvasGraphicsNode canvasGraphicsNode = (CanvasGraphicsNode)
graphicsNode.getRoot().getChildren().get(0);
if(canvasGraphicsNode.getChildren().get(i) instanceof ShapeNode) {
currentNode = (ShapeNode) canvasGraphicsNode.getChildren().get(i);
convertNodeToImage (currentNode);
}
This is pretty standard. I fire up Batik and get it to parse the SVG file. Here's the convert node to image function:
Rectangle2D bounds;
BufferedImage bufferedImage;
Graphics2D g2d;
// This is supposed to get the bounds of the svg node. i.e. the rectangle which would
// fit perfectly around the shape
bounds = sn.getSensitiveBounds();
// Transform the shape so it's in the top left hand corner based on the bounds
sn.setTransform(AffineTransform.getTranslateInstance(-bounds.getX(), -bounds.getY()));
// Create a buffered image of the same size as the svg node
bufferedImage = new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(),
BufferedImage.TYPE_INT_ARGB);
// Paint the node to the buffered image and convert the buffered image to an input
// stream
g2d = (Graphics2D) bufferedImage.getGraphics();
sn.paint(g2d);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", os);
InputStream is = new ByteArrayInputStream(os.toByteArray());
return is;
This works fine for rectangles and straight line shapes but it doesn't work for splines. For splines the bounds are greater than the rendered spline. I think this is because the getBounds function is including the control points in the bounds calculation. I need to find the bounds of just the spline i.e. if the spline were stroked I'd like to find the bounds of that stroke. I've tried all the getBounds() functions (getSensativeBounds, getGeometryBounds...) and they all give me the same result. So I'm wondering if I've missed something? This is a bug in Batik? Or if there's a workaround?
A workaround I thought of would be to get a list of vertices of the shape and calculate the bounds manually. I've been unable to find how to get a list of the outline vertices however.
Any help would be greatly appreciated.