在 Batik 中将 SVG 转换为 GraphicNode 时使用自定义字体

问题描述 投票:0回答:1

我正在尝试使用 Java 中的 Apache Batik 和 OpenPDF 库将 SVG 嵌入到 PDF 中。

为此,按照教程,我需要创建一个 GraphicsNode,稍后将其转换为 ImgTemplate 以在 PDF 文档上使用。

我的代码是:

    private GraphicsNode convert(String svgCode) throws IOException {
        final SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
        final SVGDocument svgDocument = factory.createSVGDocument("", new ByteArrayInputStream(svgCode.getBytes(StandardCharsets.UTF_8)));

        final UserAgent userAgent = new UserAgentAdapter();
        final DocumentLoader loader = new DocumentLoader(userAgent);

        final BridgeContext context = new BridgeContext(userAgent, loader);
        context.setDynamicState(BridgeContext.DYNAMIC);

        final GVTBuilder builder = new GVTBuilder();
        return builder.build(context, svgDocument);
    }

由于 SVG 代码使用我的资源文件夹中的字体,我得到:

java.lang.NullPointerException: Cannot invoke "java.util.List.iterator()" because "this.srcs" is null

    at org.apache.batik.bridge.FontFace.getFontFamily(FontFace.java:98)
    at org.apache.batik.bridge.CSSFontFace.getFontFamily(CSSFontFace.java:176)
    at org.apache.batik.bridge.SVGFontUtilities.getFontFamily(SVGFontUtilities.java:144)

FontFace 有两个构造函数,在 debuggin 时使用:

    protected FontFace(String familyName) {
        super(familyName);
    }

这不是初始化

srcs
元素。因此我得到了 NPE。

也许我需要以某种方式注册字体。然后我在代码中添加了一些额外的行:

    private GraphicsNode convert(String svgCode) throws IOException {
        //Create org.w3c.dom.svg.SVGDocument
        final SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
        final SVGDocument svgDocument = factory.createSVGDocument("", new ByteArrayInputStream(svgCode.getBytes(StandardCharsets.UTF_8)));

        //Create a org.apache.batik.gvt.GraphicsNode from the org.w3c.dom.svg.SVGDocument
        final UserAgent userAgent = new UserAgentAdapter();
        final DocumentLoader loader = new DocumentLoader(userAgent);

        // Notice, that you should use org.apache.batik.bridge.svg12.SVG12BridgeContext.SVG12BridgeContext for the svg version 1.2
        final BridgeContext context = new SVG12BridgeContext(userAgent, loader);
        context.setDynamicState(BridgeContext.DYNAMIC);

        //Register fonts
        final GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
        final Set<Font> loadedFonts = com.custom.FontFactory.getLoadedFonts();
        loadedFonts.forEach(graphicsEnvironment::registerFont);

        final GVTBuilder builder = new GVTBuilder();
        return builder.build(context, svgDocument);
    }

我的

com.custom.FontFactory
返回已从资源加载的
Set<Font>

我不确定这是否是注册字体的正确方法。但似乎有一些效果,因为现在我得到了:

java.lang.NullPointerException: Cannot invoke "java.util.Collection.toArray()" because "c" is null

    at java.base/java.util.LinkedList.addAll(LinkedList.java:419)
    at java.base/java.util.LinkedList.addAll(LinkedList.java:398)
    at java.base/java.util.LinkedList.<init>(LinkedList.java:130)
    at org.apache.batik.bridge.FontFace.createFontFace(FontFace.java:78)

这是不同地方的不同错误。我也尝试过直接注册字体,如下:

graphicsEnvironment.registerFont(Font.createFont(Font.TRUETYPE_FONT,
                        new File("<pathToTheResource>"))));

但是和上次的错误没有什么区别

那么问题是..如何在 Batik 上使用自定义字体将 SVG 转换为 GraphicNode?

如果我转换没有任何嵌入字体的 SVG,它工作正常。那么我假设问题与使用的字体有关。

java font-face batik apache-batik
1个回答
0
投票

好的。看来这个问题与我想用

GraphicsEnvironment
注册的字体无关,而是与嵌入在 svg 上的字体有关。我已遵循此建议在 SVG 中使用字体。为此,我在
font-face
字段中创建了一个带有 Base64 编码字体的
src

好像Batik不喜欢

src
上的这个内容。但是,由于我使用
GraphicsEnvironment
嵌入字体,因此我不需要 SVG 上的嵌入字体。

TL;DR 在网页上使用 SVG 时,将字体嵌入到 SVG xml 中,但在使用 Batik 转换为 PNG、JPEG 或任何其他渲染时不要这样做。

© www.soinside.com 2019 - 2024. All rights reserved.