Java 用于带有蜡染的嵌入式SVG元素的getBBox

Java 用于带有蜡染的嵌入式SVG元素的getBBox,java,dom,batik,Java,Dom,Batik,我正在编写一个应用程序,它将创建一个HTML文档,其中包含许多嵌入式SVG 该应用程序具有以下特征: 它必须在服务器环境中无头运行 它使用操作DOM的现有代码来创建SVG和文档中的其他项 现有代码使用getBBox()方法来确定各种动态创建元素的大小,从而计算SVG的布局 作为补充信息,尽管我认为这不会影响问题:SVG生成代码是用Javascript编写的,并使用D3库。我正在使用它来促进这一点。然而,我目前遇到的问题很容易在纯Java中重现(见下文) 我试图使用它来提供SVG DOM实现 我的

我正在编写一个应用程序,它将创建一个HTML文档,其中包含许多嵌入式SVG

该应用程序具有以下特征:

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

  • 它使用操作DOM的现有代码来创建SVG和文档中的其他项

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

  • 作为补充信息,尽管我认为这不会影响问题:SVG生成代码是用Javascript编写的,并使用D3库。我正在使用它来促进这一点。然而,我目前遇到的问题很容易在纯Java中重现(见下文)

  • 我试图使用它来提供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”)

    在这种情况下,如果svg元素嵌入到一个较大的文档中(事实上,该文档中可能有多个svg),是否有任何方法可以使
    getBBox()
    正常工作

    试试这个代码

    首先,在创建文档或元素时始终输入svg名称空间url

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

    p、 这代码是科特林

    试试这个代码

    首先,在创建文档或元素时始终输入svg名称空间url

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

    p、 这代码是科特林

    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)