前言
最近在项目中使用 docx4j-wisewe-convert 组件做 PPTX 文件转 PDF 功能时,遇到了一个非常典型的跨环境问题:Windows 本地测试环境转换完全正常,Linux 线上环境转换后的 PDF 只有图片 / 形状,所有文本全部丢失不显示。本文完整记录问题的排查过程、根因定位和最终解决方案,给遇到同样问题的同学避坑。
一、问题现象
1. 项目依赖
项目中使用了 wisewe 开源的 docx4j 转换工具,Maven 依赖如下:
xml
<dependency>
<groupId>cn.wisewe</groupId>
<artifactId>docx4j-wisewe-convert</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
2. 核心转换代码
java
// PPTX转PDF核心逻辑
SlideConverter.create()
.input(inputStream) // PPTX文件输入流
.output(outputStream) // PDF输出流
.convert(SlideConvertType.PDF);
3. 环境与现象对比
| 环境 | JDK 版本 | 转换现象 |
|---|---|---|
| Windows 本地测试环境 | JDK 1.8.0_202 | PPTX 转 PDF 完全正常,文本、图片、格式均无异常 |
| CentOS Linux 线上环境 | JDK 1.8.0_212 | 转换后的 PDF 能正常显示图片、形状,但所有文本内容全部丢失,页面空白 |
补充:代码执行无任何异常报错,日志无 Error 信息,就是输出的 PDF 没有文本。
二、排查过程与根因定位
1. 初步排查(排除非核心因素)
-
排除代码逻辑问题:同一份代码、同一个 PPTX 文件,Windows 正常,Linux 异常,说明代码本身没有问题。
-
排除 JDK 版本差异:尝试将线上 JDK 版本降级到和本地一致的 1.8.0_202,问题依旧存在,说明不是 JDK 小版本的 Bug 导致。
-
排除文件权限问题:检查输入输出流的文件权限,均为可读可写,无权限异常。
2. 核心根因定位
最终定位到问题的核心:Linux 服务器缺少字体库,导致转换时无法渲染文本。
这里给大家讲清楚底层原理:
-
docx4j-wisewe-convert底层依赖docx4j、PDFBox和 Java AWT 图形框架做文本渲染,PPTX 中的文本都绑定了对应的字体(比如宋体、微软雅黑、黑体等),转换 PDF 时,必须从系统字体库中读取对应的字体文件,才能把文本渲染到 PDF 中。 -
Windows 系统默认自带了大量的中文字体和西文字体,本地运行时能轻松找到 PPTX 文本对应的字体,正常渲染。
-
而线上使用的精简版 CentOS Linux 服务器,默认不仅没有安装任何中文字体,甚至连系统的字体目录
/usr/share/fonts都不存在,转换程序找不到任何可用字体,直接跳过了文本渲染步骤,最终导致 PDF 里只有图片,没有文字。
补充次要影响因素:Linux 服务器无图形界面,Java 程序未开启 Headless 模式,也会导致 AWT 图形渲染异常,加剧文本渲染失败的问题。
三、完整解决方案
前置说明
以下操作均在 CentOS 7/8/9 环境下执行,需要 root 权限,其他 Linux 发行版可参考对应包管理器命令。
步骤 1:安装字体管理工具
首先解决很多人会遇到的 fc-cache: command not found 问题,这是因为系统没有安装字体管理工具 fontconfig,先执行安装:
bash
yum install -y fontconfig
安装完成后,fc-cache(刷新字体缓存)、fc-list(查看系统字体)命令即可正常使用。
步骤 2:安装中文字体(二选一即可,推荐方案 A)
方案 A:yum 一键安装开源中文字体(快速应急,推荐)
如果不需要精准匹配 PPT 中的特殊字体,直接用 yum 安装开源中文字体包,一键完成安装:
bash
# 安装文泉驿微米黑(兼容性最好的开源中文字体)
yum install -y wqy-microhei-fonts
# 安装文泉驿正黑(可选,补充字体)
yum install -y wqy-zenhei-fonts
方案 B:手动上传 Windows 字体(精准匹配 PPT 字体,效果最好)
如果 PPT 中使用了微软雅黑、宋体等 Windows 专属字体,想要转换效果和本地完全一致,推荐手动上传字体:
-
从 Windows 系统的
C:\\Windows\\Fonts目录中,复制需要的字体文件(比如msyh\.ttc微软雅黑、simsun\.ttc宋体、simhei\.ttf黑体)。 -
在 Linux 服务器创建字体目录:
bashmkdir -p /usr/share/fonts/chinese -
将复制的字体文件上传到
/usr/share/fonts/chinese目录中。 -
设置字体文件权限,避免 Java 进程无法读取:
bashchmod 755 /usr/share/fonts/chinese chmod 644 /usr/share/fonts/chinese/*
步骤 3:刷新系统字体缓存
无论用哪种方案安装字体,都必须执行以下命令刷新字体缓存,让系统识别新安装的字体:
bash
fc-cache -fv
步骤 4:验证字体安装成功
执行以下命令,查看系统识别的中文字体:
bash
fc-list :lang=zh
如果能看到刚才安装的字体名称和路径,说明字体安装成功。
步骤 5:配置 Java 启动参数(适配无图形界面环境)
Linux 服务器无图形界面,需要给 Java 程序开启 Headless 模式,保证 AWT 图形渲染正常运行。
修改你的 Java 服务启动脚本,在启动命令中添加以下 JVM 参数:
bash
-Djava.awt.headless=true
示例:
bash
# 完整的启动命令示例
java -Djava.awt.headless=true -jar your-project.jar
步骤 6:重启 Java 应用(必做!)
非常关键的一步:JVM 只会在启动时加载系统的字体库,运行中新增的字体不会被实时识别。必须重启你的 Java 服务,才能让转换程序读取到新安装的字体。
四、验证效果
重启服务后,重新执行 PPTX 转 PDF 操作,线上 Linux 环境转换后的 PDF 可以正常显示所有文本内容,和 Windows 本地转换效果完全一致,问题彻底解决。
五、避坑总结
-
跨环境问题优先排查系统差异:同一份代码 Windows 正常、Linux 异常,90% 的情况都不是代码问题,而是系统环境、依赖库的差异导致。
-
Java 文档转换强依赖系统字体:无论是 PPTX、DOCX 转 PDF,只要涉及文本渲染,都依赖系统的字体库,Linux 精简系统默认无中文字体是最常见的坑。
-
安装字体后的两个必做操作 :刷新字体缓存
fc-cache -fv+ 重启 Java 应用,少一步都不会生效。 -
Headless 模式必须开启:无图形界面的 Linux 服务器,Java 程序必须开启 Headless 模式,否则会出现各种 AWT 图形渲染异常。
-
fontconfig 工具是前提:不要上来就传字体,先安装 fontconfig 工具,否则无法管理和识别字体。
补充说明
本文的解决方案不仅适用于 docx4j-wisewe-convert 组件,同样适用于 POI、docx4j、itext 等 Java 组件做 Word/Excel/PPT 转 PDF 时,Linux 环境文本丢失、乱码、方框等问题,核心都是解决系统字体缺失的问题。