Java生成PDF时该如何正确支持中文生僻字详解

 更新时间:2026年03月02日 10:03:10   作者:yeye19891224  
这篇文章主要介绍了Java生成PDF时该如何正确支持中文生僻字的相关资料,包括字体选择、字体加载、HTML/CSS使用等方面,并提供了一个标准方案来解决生僻字问题,文中给出了详细的代码示例,需要的朋友可以参考下

——从字体原理到工程落地的完整实践指南

一、问题背景:为什么“生僻字”在 PDF 中总是出问题?

在 Java 项目中使用 iText / OpenPDF / Flying Saucer 生成 PDF,是非常常见的需求,典型场景包括:

  • 合同 / 协议生成
  • 电子档案
  • 报表导出
  • 存证类文件

但一旦涉及中文生僻字(如姓名、地名、少数民族用字、古籍用字),就很容易出现以下问题:

  • PDF 中显示为
  • 直接空白
  • 只有数字、符号、序号,中文正文消失
  • 本机正常,换一台机器就乱码

这些问题并不是 iText 的 bug,而是对 PDF 字体机制 + 中文字符集 理解不足导致的。

二、核心结论先行(非常重要)

Java 生成 PDF 要支持中文生僻字,本质上只取决于三件事:

  1. 字体是否真正包含该字符(Glyph 是否存在)
  2. PDF 是否使用了该字体(CSS / font-family)
  3. 字体是否随 PDF 一起嵌入(EMBEDDED)

只要其中任意一个不满足,生僻字一定失败

三、为什么宋体(SimSun)无法支持生僻字?

1. SimSun 的历史定位

SimSun.ttc(宋体)是一个非常早期的中文字库,主要覆盖:

  • GB2312 / GBK
  • 常用汉字

但它不包含

  • CJK 扩展区 A / B / C / D / E / F
  • 大量现代姓名用字(如:𠮷、𡿺)
  • 古籍、少数民族汉字

2. 结论

宋体不是“坏字体”,而是“时代局限字体”
它从设计之初就没打算覆盖 Unicode 全中文字符集。

因此:

  • Word 里能显示 ≠ PDF 一定能显示
  • 系统里有 ≠ 所有人机器都有

四、真正支持生僻字的字体:Noto / 思源系列

1. 推荐字体

在 Java PDF 场景中,强烈推荐使用静态版本的 Noto 字体

NotoSansCJKsc-Regular.otf

特点:

  • 覆盖几乎全部 Unicode 中文字符
  • 支持 CJK 扩展区
  • 免费可商用(SIL OFL)
  • iText / Flying Saucer 完全支持

五、常见字体后缀解析(避免踩坑)

后缀

含义

是否可用于 Java PDF

.ttf

TrueType Font

.otf

OpenType Font

✅(推荐)

.ttc

字体集合

⚠️(易出问题)

.vf.ttf

可变字体

❌(不支持)

.woff / woff2

Web 字体

特别警告:Variable Font(VF)

NotoSansCJKsc-VF.ttf

iText / Flying Saucer 完全不支持,使用后常见现象是:

  • 只有数字、符号
  • 中文正文全部消失
  • 不报错,非常迷惑

六、Java 端正确的字体加载方式

1. 必须使用IDENTITY_H

BaseFont.IDENTITY_H

作用:

告诉 PDF 使用 Unicode 编码,而不是单字节编码。

2. 强烈建议使用EMBEDDED

BaseFont.EMBEDDED

为什么?

  • NOT_EMBEDDED 只是“引用字体名”
  • 是否能显示,完全依赖打开 PDF 的环境
  • 换机器 / Linux / Docker 必定翻车

你现在能显示,只是环境“碰巧”有该字体

3. 标准代码示例

ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(
    "NotoSansCJKsc-Regular.otf",
    BaseFont.IDENTITY_H,
    BaseFont.EMBEDDED
);

七、最容易被忽略的一点:HTML / CSS 才是真正的“使用字体”

1. 一个常见误区

“我在 Java 里 addFont 了,为什么中文还不显示?”

原因是:

addFont 只是“注册”,不是“使用”

2. 必须在模板中显式指定font-family

<style>
body {
    font-family: "Noto Sans CJK SC";
    font-size: 12pt;
}
</style>

关键点:

  • 使用 字体内部 family 名称
  • 不是文件名
  • 建议写在 body,让所有元素继承

如果不写这一步,Flying Saucer 会退回到内置 Latin 字体,中文直接丢失。

八、为什么换成 Noto 后,版式可能发生变化?

这是一个正常且不可避免的现象

原因:

  • 不同字体的字宽不同
  • 行高(ascent / descent)不同
  • 笔画粗细不同

因此可能导致:

  • 换行点变化
  • 表格溢出
  • 分页变化

九、工程级应对方案(必须知道)

1. 固定行高

body {
    line-height: 1.4;
}

2. 表格列宽避免“卡死”

优先:

width: 25%;

避免:

width: 80px;

3. 字号微调

经验值:

原宋体字号

Noto 建议

12pt

11pt

10.5pt

10pt

十、生僻字验证(上线前必做)

在模板中加入测试文本:

龘 麤 鱻 𠮷 𡿺

全部可见,才算真正支持生僻字。

十一、最终推荐的“标准方案”

生产级、稳定、可迁移的最佳实践

  • 字体:NotoSansCJKsc-Regular.otf
  • 编码:IDENTITY_H
  • 嵌入:EMBEDDED
  • CSS:body 全局 font-family
  • 行高:显式设置
  • 表格:避免极限宽度

十二、一句话总结

Java 生成 PDF 的生僻字问题,从来不是“渲染问题”,

而是“字体工程问题”。

理解了 字体覆盖范围 + PDF 字体嵌入机制 + CSS 使用方式

这个问题可以一次性、永久性解决。

到此这篇关于Java生成PDF时该如何正确支持中文生僻字的文章就介绍到这了,更多相关Java生成PDF支持中文生僻字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • idea在用Mybatis时xml文件sql不提示解决办法(提示后背景颜色去除)

    idea在用Mybatis时xml文件sql不提示解决办法(提示后背景颜色去除)

    mybatis的xml文件配置的时候,有时候会没有提示,这让我们很头疼,下面这篇文章主要给大家介绍了关于idea在用Mybatis时xml文件sql不提示的解决办法,提示后背景颜色去除的相关资料,需要的朋友可以参考下
    2023-03-03
  • SpringBoot 项目如何在tomcat容器中运行的实现方法

    SpringBoot 项目如何在tomcat容器中运行的实现方法

    这篇文章主要介绍了SpringBoot 项目如何在tomcat容器中运行的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Java concurrency集合之CopyOnWriteArraySet_动力节点Java学院整理

    Java concurrency集合之CopyOnWriteArraySet_动力节点Java学院整理

    CopyOnWriteArraySet基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent(若没有则增加)方法
    2017-06-06
  • 详细解读Java的串口编程

    详细解读Java的串口编程

    这篇文章主要介绍了详细解读Java的串口编程,而文中讲解的示例主要针对于JavaComm和RxTx这两个库,需要的朋友可以参考下
    2015-08-08
  • 利用keytools为tomcat 7配置ssl双向认证的方法

    利用keytools为tomcat 7配置ssl双向认证的方法

    双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证,下面这篇文章主要介绍了利用keytools为tomcat 7配置ssl双向认证的方法,需要的朋友可以借鉴,下面来一起看看吧。
    2017-02-02
  • Java中的FutureTask用法和原理解析

    Java中的FutureTask用法和原理解析

    本文深入剖析了Java并发编程中的FutureTask,包括其与Callable和Future的关系、使用方法以及内部实现原理,FutureTask是Future的基础实现,用于处理异步计算结果,提供了任务执行结果获取和任务取消等方法
    2024-10-10
  • springboot配置nacos的实现示例

    springboot配置nacos的实现示例

    本文将介绍如何在Spring Boot中配置Nacos,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • Fluent Mybatis实际开发中的优势对比

    Fluent Mybatis实际开发中的优势对比

    本文给大家介绍如何通过IQuery和IUpdate定义强大的动态SQL语句,给大家分享Fluent Mybatis实际开发中的优势讲解,感兴趣的朋友一起看看吧
    2021-08-08
  • java 面向对象面试集锦

    java 面向对象面试集锦

    这篇文章主要介绍了java 面向对象面试集锦的相关资料,这里整理了面向对象的基础知识,帮助大家学习理解此部分的知识,需要的朋友可以参考下
    2016-11-11
  • Spring Boot 配置文件从基础语法到验证码实战

    Spring Boot 配置文件从基础语法到验证码实战

    本文详细解析了SpringBoot配置文件的作用及其主流格式,包括Properties和YAML(YML)的语法差异、优先级及适用场景,并通过@Value与@ConfigurationProperties注解的代码实战,演示了如何将配置项优雅地集成到实际业务中,感兴趣的朋友跟随小编一起看看吧
    2025-12-12

最新评论