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"));
三、常见坑点排查
- 路径基准搞混:一定要确认相对路径的基准是HTML所在目录还是Classpath根,别搞反了。
- 字体文件名大小写:Linux环境下文件名是大小写敏感的,比如
asap-regular.ttf和Asap-Regular.ttf是两个文件。 - 字体文件权限:确保程序有读取字体文件的权限,尤其是部署到服务器上的时候。
- Font-family名称一致:HTML里的
font-family要和代码中引用的(或者CSS里使用的)完全一致,比如别写成Asap Regular(有空格)而代码里是Asap-Regular。
内容的提问来源于stack exchange,提问作者L_G
相关产品推荐
相关产品推荐

