【问题标题】:getBBox for embedded SVG element with batikgetBBox 用于带有蜡染的嵌入式 SVG 元素
【发布时间】:2016-03-08 18:58:08
【问题描述】:

我正在编写一个应用程序来创建一个包含许多嵌入式 SVG 的 HTML 文档。

该应用具有以下特点:

  1. 它必须在服务器环境中无头运行

  2. 它使用现有代码来操作 DOM,以便在文档中创建 SVG 和其他项目

  3. 现有代码使用getBBox()方法来确定各种动态创建的元素的大小,从而计算SVG的布局。

  4. 作为附加信息,虽然我认为它不会影响问题:SVG 生成代码是用 Javascript 编写的,并使用 D3 库。我正在使用node-java 来促进这一点。但是,我目前遇到的问题很容易在纯 Java SSCE 中重现(见下文)。

我正在尝试使用Apache Batik 来提供 SVG DOM 实现。

我的问题是,在 SVG 元素嵌入更大的 XML 文档的情况下,我至今无法让 getBBox() 返回非空值。

这是一个说明问题的例子:

import org.w3c.dom.*;
import org.w3c.dom.svg.*;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;

class BatikDomEmbedded {

    public static void main(String [ ] args) {

        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); 
        SVGDocument doc = (SVGDocument) impl.createDocument(null, "html", null);

        Element html = doc.getDocumentElement();
        Element body = doc.createElement("body");
        html.appendChild(body);

        Element svg = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg"); 
        svg.setAttributeNS(null, "width", "500");
        svg.setAttributeNS(null, "height", "100");
        body.appendChild(svg);

        UserAgent userAgent = new UserAgentAdapter(); 
        DocumentLoader loader    = new DocumentLoader(userAgent); 
        BridgeContext ctx       = new BridgeContext(userAgent, loader); 
        ctx.setDynamicState(BridgeContext.DYNAMIC); 
        GVTBuilder builder   = new GVTBuilder(); 
        builder.build(ctx, svg); 

        Element rect = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect");
        rect.setAttributeNS(null, "x", "100"); 
        rect.setAttributeNS(null, "y", "100"); 
        rect.setAttributeNS(null, "width", "150"); 
        rect.setAttributeNS(null, "height", "200"); 
        svg.appendChild(rect); 

        SVGRect bbox = ((SVGLocatable)rect).getBBox(); 

        System.out.println("X: " + bbox.getX() + "\nY: " + bbox.getY() + 
            "\nHeight: " + bbox.getHeight() + "\nWidth: " + bbox.getWidth());     
    }       

}

运行此代码会在取消引用 bbox 时导致空指针异常。

如果我稍微更改代码以使文档成为独立的 SVG 文档,那么它可以正常工作。

这些场景之间的主要区别(除了 SVG 元素不是根文档元素)是在工作情况下,对 builder.build(ctx, ...); 的调用提供了一个 SVGDocument 作为第二个参数,但在非工作情况下如果它是一个 SVGElement('svg' 类型)。

有什么方法可以让getBBox() 在这种情况下工作,即 svg 元素嵌入到一个较大的文档中(实际上这个文档中可能有多个 SVG)?

【问题讨论】:

    标签: java dom batik


    【解决方案1】:
    val impl: DOMImplementation = SVGDOMImplementation.getDOMImplementation()
    val doc = impl.createDocument(SVGConstants.SVG_NAMESPACE_URI, "svg", null) as SVGDocument
    
    val userAgent: UserAgent = UserAgentAdapter()
    val loader = DocumentLoader(userAgent)
    val ctx = BridgeContext(userAgent, loader)
    ctx.setDynamicState(BridgeContext.DYNAMIC)
    val builder = GVTBuilder()
    builder.build(ctx, doc)
    
    val rect: Element = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect")
    rect.setAttributeNS(null, "x", "100")
    rect.setAttributeNS(null, "y", "100")
    rect.setAttributeNS(null, "width", "150")
    rect.setAttributeNS(null, "height", "200")
    doc.documentElement.appendChild(rect)
    
    val bbox = (rect as SVGLocatable).bBox
    
    println("X: " + bbox.x + "\nY: " + bbox.y +
            "\nHeight: " + bbox.height + "\nWidth: " + bbox.width)
    

    试试这个代码。

    首先,创建文档或元素时始终输入 svg namespace_url。

    其次,不要在 SvgDocument 中将qualifiedName 设置为“html”。如果要创建 html 文档,请使用 HtmlDocument。

    p.s 这段代码是 kotlin。

    【讨论】:

      猜你喜欢
      • 2015-12-19
      • 2017-07-15
      • 1970-01-01
      • 1970-01-01
      • 2021-12-16
      • 2015-11-02
      • 2019-08-08
      • 2013-02-20
      • 1970-01-01
      相关资源
      最近更新 更多