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

Spring Boot+Flying Saucer生成PDF:TTF字体相对路径嵌入问题

解决Flying Saucer PDF嵌入TTF字体的相对路径问题

我之前折腾Flying Saucer字体嵌入的时候也踩过不少坑,刚好能给你一些实用的解决思路,帮你搞定相对路径的问题:

一、HTML中@font-face相对路径的正确配置

首先要明确Flying Saucer解析相对路径的基准:

  • 如果你的HTML文件是本地文件系统里的文件(比如直接读取index.html),相对路径是相对于这个HTML文件所在的目录。
  • 如果HTML是从Classpath加载(比如Spring Boot的resources/templates目录),相对路径的基准是Classpath的根目录。

举个实际例子:
假设你的项目结构是这样的:

project-root/
├── index.html
└── fonts/
    ├── Asap-Regular.ttf
    └── Asap-Bold.ttf

那HTML里的@font-face应该这么写:

@font-face {
    font-family: 'Asap-Regular';
    src: url("fonts/Asap-Regular.ttf"); /* 相对于index.html所在目录的fonts子文件夹 */
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: Identity-H;
}

@font-face {
    font-family: 'Asap-Bold';
    src: url("fonts/Asap-Bold.ttf");
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: Identity-H;
}

如果HTML在src/main/resources/templates,字体在src/main/resources/fonts,那HTML里的路径要加根斜杠:

src: url("/fonts/Asap-Regular.ttf"); /* 基准是Classpath根,对应resources目录 */

二、Java代码中FontResolver的正确用法(你之前可能参数或路径不对)

你试过用renderer.getFontResolver().addFont()但没成功,大概率是路径处理或者参数有误,下面两种场景的正确写法:

场景1:字体在本地文件系统(开发环境)

如果字体在项目根目录的fonts文件夹下,相对路径是相对于Java程序的运行目录(比如你在项目根目录执行java -jar,那基准就是项目根):

ITextRenderer renderer = new ITextRenderer();
// 关键:第三个参数用BaseFont.IDENTITY_H,第四个参数指定嵌入(BaseFont.EMBEDDED)
renderer.getFontResolver().addFont("fonts/Asap-Bold.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 加载HTML文件(注意用URI来避免路径编码问题)
renderer.setDocument(new File("index.html").toURI().toString());
renderer.layout();
renderer.createPDF(new FileOutputStream("output.pdf"));

场景2:字体在Classpath(生产打包成Jar的情况)

Jar包里的资源不能直接用文件路径读取,必须用流或者Classpath资源URL,这是很多人踩坑的点:

ITextRenderer renderer = new ITextRenderer();

// 方式1:用流加载(最可靠,适配Jar环境)
try (InputStream fontStream = getClass().getResourceAsStream("/fonts/Asap-Bold.ttf")) {
    // 第五个参数true表示要嵌入字体
    renderer.getFontResolver().addFont(fontStream, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, null);
} catch (IOException e) {
    throw new RuntimeException("加载字体失败", e);
}

// 加载Classpath里的HTML
renderer.setDocument(getClass().getResource("/templates/index.html").toString());
renderer.layout();
renderer.createPDF(new FileOutputStream("output.pdf"));

三、常见坑点排查

  1. 路径基准搞混:一定要确认相对路径的基准是HTML所在目录还是Classpath根,别搞反了。
  2. 字体文件名大小写:Linux环境下文件名是大小写敏感的,比如asap-regular.ttf和Asap-Regular.ttf是两个文件。
  3. 字体文件权限:确保程序有读取字体文件的权限,尤其是部署到服务器上的时候。
  4. Font-family名称一致:HTML里的font-family要和代码中引用的(或者CSS里使用的)完全一致,比如别写成Asap Regular(有空格)而代码里是Asap-Regular。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:37:38