简体   繁体   English

使用蜡染嵌入 SVG 元素的 getBBox

[英]getBBox for embedded SVG element with batik

I am writing an application which is to create a HTML document which contains a number of embedded SVGs.我正在编写一个应用程序,用于创建一个包含许多嵌入式 SVG 的 HTML 文档。

The application has the following characteristics:该应用程序具有以下特点:

  1. It must run headless in a server environment它必须在服务器环境中无头运行

  2. It uses existing code which manipulates the DOM in order to create the SVGs and other items in the document它使用现有的代码来操作 DOM,以便在文档中创建 SVG 和其他项目

  3. The existing code uses the getBBox() method in order to determine sizes of various dynamically created elements, so as to calculate the layout of the SVGs.现有代码使用getBBox()方法来确定各种动态创建的元素的大小,从而计算getBBox()的布局。

  4. As additional information, although I do not think it affects the question: the SVG generation code is written in Javascript and uses the D3 library.作为附加信息,虽然我认为它不会影响问题:SVG 生成代码是用 Javascript 编写的并使用 D3 库。 I am using node-java to facilitate this.我正在使用node-java来促进这一点。 However, the problem I am currently experiencing is easily reproduced in a pure Java SSCE (see below).但是,我目前遇到的问题很容易在纯 Java SSCE 中重现(见下文)。

I am trying to use Apache Batik to provide the SVG DOM implementation.我正在尝试使用Apache Batik来提供 SVG DOM 实现。

My problem is that I have so far been unable to get the getBBox() to return a non-null value in the case where an SVG element is embedded in a larger XML document.我的问题是,在 SVG 元素嵌入到较大的 XML 文档中的情况下,到目前为止,我一直无法让getBBox()返回非空值。

Here is an example that illustrates the problem:这是一个说明问题的示例:

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());     
    }       

}

Running this code results in a null pointer exception when dereferencing bbox.取消引用 bbox 时,运行此代码会导致空指针异常。

If I alter the code slightly to make the document a standalone SVG document then it works OK.如果我稍微更改代码以使文档成为独立的 SVG 文档,则它可以正常工作。

The chief difference between these scenarios (other than that the SVG element is not the root document element) is that in the working case, the call to builder.build(ctx, ...);这些场景之间的主要区别(除了 SVG 元素不是根文档元素)是在工作案例中,对builder.build(ctx, ...);的调用builder.build(ctx, ...); supplies an SVGDocument as the second argument, but in the non-working case it is an SVGElement (of type 'svg').提供一个 SVGDocument 作为第二个参数,但在非工作情况下它是一个 SVGElement(类型为“svg”)。

Is there any way to get getBBox() working in this case where the svg element is embedded in a larger document (and in fact there may be multiple SVGs in this document)?在 svg 元素嵌入到更大的文档中的情况下(实际上该文档中可能有多个 SVG getBBox()有没有办法让getBBox()工作?

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)

try this code.试试这个代码。

first, always input svg namespace_url when create document or element.首先,在创建文档或元素时始终输入 svg namespace_url。

second, don't set qualifiedName to "html" in SvgDocument.其次,不要在 SvgDocument 中将qualifiedName 设置为“html”。 if you want to create html document, use HtmlDocument.如果要创建 html 文档,请使用 HtmlDocument。

ps this code is kotlin. ps 此代码是 kotlin。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM