根本原因是PDF字体不支持中文字符集且未嵌入中文字体;需显式加载如NotoSansCJKsc-Regular.otf等开源字体,用PdfEncodings.IDENTITY_H编码注册并嵌入,才能正确显示中文。

Java 生成 PDF 时中文显示为方块或乱码,根本原因是 PDF 字体不支持中文字符集,且未正确嵌入中文字体。iText、Apache PDFBox、Flying Saucer(XHTML to PDF)等主流工具默认都不带中文字体,必须显式指定并注册支持 GBK/UTF-8 的 TrueType 字体(如 simsun.ttc、NotoSansCJKsc-Regular.otf、SourceHanSansSC-Regular.otf 等)。
确认并嵌入支持中文的字体文件
PDF 标准字体(Helvetica、Times-Roman 等)不含中文字符。你必须提供一个含中文的 TTF/OTF 文件,并在代码中加载、注册、使用:
- 推荐使用开源免费字体:如 Source Han Sans SC(思源黑体简体)、Noto Sans CJK SC 或 Windows 自带的 simsun.ttc(注意版权,生产环境建议用开源字体)
- 确保字体文件路径可访问(建议放在
resources/fonts/下,用getClass().getResourceAsStream()加载) - 字体需显式设置为“嵌入”(
setEmbeddable(true)或对应 API),否则生成的 PDF 在无该字体的设备上仍会乱码
iText 7 中正确使用中文字体
iText 7 使用 PdfFontFactory.createFont() 加载字体,并通过 setFont() 应用于 Paragraph 或 Cell:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
PdfFont font = PdfFontFactory.createFont(
getClass().getResourceAsStream("/fonts/NotoSansCJKsc-Regular.otf"),
PdfEncodings.IDENTITY_H // 关键:必须用 IDENTITY_H 支持 Unicode 多字节中文
);
Paragraph p = new Paragraph("你好,世界!").setFont(font).setFontSize(12);
document.add(p);
- PdfEncodings.IDENTITY_H 是核心——它启用双字节编码映射,让 PDF 解析器按 Unicode 正确渲染中文
- PdfEncodings.WINANSI 或
STANDARD,它们只支持 ASCII 和西欧字符 - PdfFontFactory.setDefaultFont(font)(iText 7.2+)
PDFBox 中设置中文字体
PDFBox 通过 PDType0Font.load() 加载字体,并绑定到 PDPageContentStream:
立即学习“Java免费学习笔记(深入)”;
PDType0Font font = PDType0Font.load(doc,
getClass().getResourceAsStream("/fonts/SourceHanSansSC-Regular.otf"));
contentStream.setFont(font, 12);
contentStream.beginText();
contentStream.newLineAtOffset(50, 700);
contentStream.showText("测试中文显示");
contentStream.endText();
- 必须使用
PDType0Font(支持 CID 字符集),不能用PDType1Font(仅支持单字节) - 字体文件需是 OpenType/CID-compliant 的中文字体;部分旧版 simsun.ttc 可能不兼容,建议优先选 Noto 或思源系列
- 调用
showText()前务必先setFont(),且字体对象需在整个文档生命周期内保持有效
Flying Saucer(XHTML → PDF)配置中文字体
Flying Saucer 基于 CSS 渲染,需在 HTML 中用 @font-face 声明字体,并确保 ITextRenderer 正确识别:
<style>
@font-face {
font-family: "NotoSansSC";
src: url("file:///path/to/NotoSansCJKsc-Regular.otf");
}
body { font-family: "NotoSansSC", sans-serif; }
</style>
- 实际运行时建议将字体转为 Base64 内联,或通过自定义
FontResolver注册字体流(避免文件路径问题) - 调用
ITextRenderer前,执行:renderer.getFontResolver().addFont(...),传入字体输入流和 family name - 确保 HTML 文档声明
<meta charset="UTF-8">,且 Java 读取 HTML 时也用 UTF-8 编码解析


















