Quarkus中Qute模板使用Open Sans字体生成PDF失效问题排查
解决Quarkus+Qute+ITextRenderer生成PDF时Open Sans字体加载失败问题
核心问题分析
你遇到的问题根源在于Flying Saucer(即ITextRenderer)对Web字体的支持限制:
- 不支持通过
<link>加载远程Google Fonts的CSS,无法解析并下载远程字体文件 - 本地字体路径未正确指向资源目录,且未手动注册字体到渲染器
正确解决方案:本地字体嵌入+手动注册
1. 准备字体文件
将Open Sans各字重的字体文件(比如OpenSans-Regular.ttf、OpenSans-Medium.ttf等)放在Quarkus项目的src/main/resources/fonts/目录下,确保打包后能被classpath访问。
2. 修改HTML模板的@font-face定义
替换原有字体引入代码,使用classpath路径并明确字重:
<style> @page { size: A4 landscape; margin: 0; } /* 注册各字重的Open Sans字体 */ @font-face { font-family: 'Open Sans'; src: url('classpath:/fonts/OpenSans-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Open Sans'; src: url('classpath:/fonts/OpenSans-Medium.ttf') format('truetype'); font-weight: 500; font-style: normal; } /* 按需添加其他字重:300(Light)、600(SemiBold)等 */ body { margin: 0 20px; font-family: "Open Sans", sans-serif; color: #031434; } /* 其余样式保持不变 */ </style>
3. 在Java渲染代码中手动注册字体
Flying Saucer需要显式注册字体才能正确识别,修改createClaimDetailReport方法:
public ByteArrayInputStream createClaimDetailReport(ClaimDetails claim) { ClaimsPdfData claimsPdfData = new ClaimsPdfData(); List<ClaimDetails> claims = new ArrayList<>(); claims.add(claim); addClaimFormattedDateFromClaimDate(claims); claimsPdfData.setClaims(claims); try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { String xdata = htmlToXhtml(insertClaimsValuesHtml(claimsPdfData, false)); ITextRenderer renderer = new ITextRenderer(); // 注册本地字体到渲染器,确保字体嵌入PDF renderer.getFontResolver().addFont("/fonts/OpenSans-Regular.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); renderer.getFontResolver().addFont("/fonts/OpenSans-Medium.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); // 对应模板中用到的其他字重,同步注册 renderer.setDocumentFromString(xdata); renderer.layout(); renderer.createPDF(byteArrayOutputStream); renderer.finishPDF(); return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); } catch (IOException | DocumentException e) { LOG.error("Error creation pdf ", e); throw new RuntimeException(e); } }
关键注意事项
- 确保字体文件名与代码中的路径完全匹配,区分大小写
- 每个字重对应单独的字体文件和@font-face定义,避免字重失效
- 使用
BaseFont.EMBEDDED参数将字体嵌入PDF,防止在无字体的环境下回退到默认字体 - 移除模板中所有远程Google Fonts的
<link>标签,避免渲染冲突
内容的提问来源于stack exchange,提问作者Francesco
相关产品推荐
相关产品推荐

