You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FOP 2.8 SVG渲染空指针问题及最优语法咨询

问题:FOP 2.8中两种SVG字体引用写法哪种更合适?

环境与配置

使用FOP 2.8 + XSLT 2,相关XSLT样式表定义如下:

<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fn="http://www.w3.org/TR/xpath-functions"
                xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xalan="http://xml.apache.org/xalan"
                xmlns:fox="http://xml.apache.org/fop/extensions"
                xmlns:pre="xalan://org.apache.xalan.Version"
                xmlns:svg="http://www.w3.org/2000/svg">

执行命令与报错

执行以下FOP命令时出现错误:

fop -c /path/to/config/config.xml -xml /path/to/test.xml -xsl /path/to/test.xslt -pdf /path/to/tst.pdf -param img /path/to/param

错误信息:

[ERROR] FOUserAgent - SVG graphic could not be rendered. Reason: java.lang.NullPointerException: Cannot load from object array because "this.boundingBoxes" is null <java.lang.NullPointerException: Cannot load from object array because "this.boundingBoxes" is null>java.lang.NullPointerException: Cannot load from object array because "this.boundingBoxes" is null
        at org.apache.fop.fonts.MultiByteFont.getBoundingBox(MultiByteFont.java:212)
        at org.apache.fop.fonts.LazyFont.getBoundingBox(LazyFont.java:305)
        at org.apache.fop.svg.font.FOPGVTGlyphVector.buildBoundingBoxes(FOPGVTGlyphVector.java:435)
        at org.apache.fop.svg.font.FOPGVTGlyphVector.getBoundingBoxes(FOPGVTGlyphVector.java:427)
        at org.apache.fop.svg.font.FOPGVTGlyphVector.getGlyphMetrics(FOPGVTGlyphVector.java:297)
        at org.apache.batik.bridge.GlyphLayout.doExplicitGlyphLayout(GlyphLayout.java:1107)
        at org.apache.batik.bridge.GlyphLayout.adjustTextSpacing(GlyphLayout.java:1465)
        at org.apache.batik.bridge.GlyphLayout.getAdvance2D(GlyphLayout.java:386)

初始SVG代码(报错版本)

XSLT中导致报错的SVG片段:

<svg:svg xmlns:svg="http://www.w3.org/2000/svg" xml:base="http://example.org/today/"  width="1100" height="1150">
                        <svg:defs>
                            <svg:font-face font-family="Test">
                                <svg:font-face-src>
                                    <svg:font-face-uri href="TestReg.ttf"/>
                                </svg:font-face-src>
                            </svg:font-face>
                        </svg:defs>
                        <svg:text font-family="Test" font-size="150pt" x="38.5" y="654.5" transform="rotate(-76.5,40,407)" textLength="125mm" lengthAdjust="spacingAndGlyphs"  style="fill:rgb(0,0,0);fill-opacity:0.3">
                            DRAFT
                        </svg:text>
                    </svg:svg>

修复后的两种可行写法

排查后发现是FOP配置文件问题,修复后以下两种写法均可正常运行:

写法一:显式使用svg:defs定义字体

<fo:instream-foreign-object>
  <svg:svg xmlns:svg="http://www.w3.org/2000/svg" xml:base="http://example.org/today/"  width="1100" height="1150">
     <svg:defs>
      <svg:font-face font-family="TestReg">
       <svg:font-face-src>
         <svg:font-face-uri href="TstReg.ttf"/>
       </svg:font-face-src>
      </svg:font-face>
     </svg:defs>
     <svg:text font-family="TestReg" font-size="150pt" x="68.5" 
        y="354.5" transform="rotate(-46.5,50,350)" textLength="125mm" 
        lengthAdjust="spacingAndGlyphs"  style="fill:rgb(0,0,0);fill-opacity:0.3">
            TEST
       </svg:text>
  </svg:svg>
</fo:instream-foreign-object>

写法二:依赖FOP配置文件加载字体,不使用svg:defs

<fo:instream-foreign-object>
  <svg:svg xmlns:svg="http://www.w3.org/2000/svg" xml:base="http://example.org/today/"  width="1100" height="1150">
     <svg:text font-family="TestReg" font-size="150pt" x="68.5" 
          y="354.5" transform="rotate(-46.5,50,350)" textLength="125mm" 
          lengthAdjust="spacingAndGlyphs"  style="fill:rgb(0,0,0);fill-opacity:0.3">
          TEST
      </svg:text>
     </svg:svg>
 </fo:instream-foreign-object>

推荐方案与原因

优先选择写法二(依赖FOP配置加载字体),理由如下:

  • 集中管理,减少冗余:字体配置统一放在FOP的config.xml中,所有SVG/FO内容可共用该字体,不用在每个SVG里重复定义font-face,降低维护成本。
  • 规避字体加载风险:之前出现的NullPointerException是因为字体初始化不完整,通过FOP配置加载时,FOP会提前完成字体的全量初始化(包括boundingBoxes这类核心数据),从根源避免这类底层渲染错误。
  • 简化SVG代码:SVG只需负责文本的样式与布局,无需额外维护字体定义逻辑,代码更简洁清晰。

如果是单个SVG需要使用特殊字体且不想全局配置的场景,写法一也可以使用,但要注意:

  • 确保字体文件路径正确(结合xml:base或使用绝对路径)
  • 多环境测试字体加载稳定性,避免出现类似初始化问题

内容的提问来源于stack exchange,提问作者Rito Sarkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 11:03:02