我正在使用Batik处理SVG图像。具体来说,我有一个具有多种形状的场景,我需要能够将每个形状转换为单独的BufferedImage。为此,我使用以下代码:
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);
}
这是非常标准的。我启动了Batik并让它来解析SVG文件。这是转换节点到图像功能:
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;
这适用于矩形和直线形状,但它不适用于样条线。对于样条线,边界大于渲染样条线。我认为这是因为getBounds函数包含了边界计算中的控制点。我需要找到样条的边界,即如果样条被描边,我想找到那个笔划的边界。我已经尝试了所有的getBounds()函数(getSensativeBounds,getGeometryBounds ......),它们都给了我相同的结果。所以我想知道我是否错过了什么?这是Batik的一个错误?或者,如果有解决方法?
我想到的解决方法是获取形状顶点列表并手动计算边界。然而,我一直无法找到如何获得轮廓顶点的列表。
非常感谢任何帮助。
答案 0 :(得分:4)
对于遇到此问题的任何人,我找到了解决方案。从文档中可以看出,获取边界不能保证最小边界只是一些完全包含形状的矩形。这意味着必须手动计算边界。样条是形状的数学定义,即分段连续函数。这意味着我们必须将样条计算到一定的精度。这是通过使用路径迭代器和双精度来实现的。此路径迭代器仅返回LINE_TO命令,这意味着它可用于计算形状的实际边界:
BufferedImage bufferedImage;
Graphics2D g2d;
// Manually calculate the bounds
double [] vals = new double[7];
double minX = Double.MAX_VALUE;
double maxX = 0;
double minY = Double.MAX_VALUE;
double maxY = 0;
// Get a path iterator iterating to a certain level of accuracy
PathIterator pi = sn.getOutline().getPathIterator(null, 0.01);
while(!pi.isDone()) {
pi.currentSegment(vals);
if(vals[0] < minX ) {
minX = vals[0];
}
if(vals[0] > maxX ) {
maxX = vals[0];
}
if(vals[1] < minY ) {
minY = vals[1];
}
if(vals[1] > maxY ) {
maxY = vals[1];
}
pi.next();
}
sn.setTransform(AffineTransform.getTranslateInstance(-minX, -minY));
bufferedImage = new BufferedImage((int) (maxX - minX), (int) (maxY - minY),
BufferedImage.TYPE_INT_ARGB);
g2d = (Graphics2D) bufferedImage.getGraphics();
sn.paint(g2d);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", os);
InputStream is = new ByteArrayInputStream(os.toByteArray());