java - Batik - 计算三次样条的边界

标签 java svg batik

我正在使用 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 的一个错误?或者是否有解决方法?

我想到的解决方法是获取形状的顶点列表并手动计算边界。但是,我一直无法找到如何获取轮廓顶点列表的方法。

如有任何帮助,我们将不胜感激。

最佳答案

对于遇到此问题的任何人,我都找到了解决方案。从文档中可以看出,get bounds 不能保证提供最小边界,只是一些完全包含形状的矩形。这意味着有必要手动计算边界。样条是形状的数学定义,即分段连续函数。这意味着我们必须以一定的精度计算样条。这是通过使用精度为 double 的路径迭代器来实现的。此路径迭代器仅返回 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());

关于java - Batik - 计算三次样条的边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10610355/

相关文章:

java - 调用 method.getReturnType().newInstance()(静态内部类的静态方法)时出现 InstantiationException

java - 如何通过终端将文本文件输入到java程序中(就像在C++中那样)?

java - 在RESTFul Web服务中调用POST方法

html - SVG 不需要的填充

css - 将 SVG 缩放到它的 viewBox 或更小

java - 我如何在 Batik SVG 库中使用自定义字体?

java - 生成没有安全性的 jHipster 独立服务器应用程序

javascript - 将img嵌入svg标记内不显示

java - 如何将 SVG 转换为 png 或 jpg

使用UTF-8字符将SVG转换为PNG的Java代码