Aspose.Words 转 PDF 中文乱码问题完整解决方案

文章讲述了在CentOS服务器上使用Aspose.Word转换Word文件至PDF时遇到的中文乱码问题,原因在于Linux缺少对应字库。提供了详细的解决方案,包括安装字库、更新字体缓存和设置字体权限等步骤。

Aspose.Words 转 PDF 中文乱码问题完整解决方案

本文详细介绍在使用 Aspose.Words 将 Word 文档转换为 PDF 时出现中文乱码的原因分析和解决方案,涵盖 Windows/Linux/Docker 全平台场景。


一、问题描述

1.1 现象

// 使用 Aspose.Words 转换 Word 到 PDF
Document doc = new Document("input.docx");
doc.save("output.pdf", SaveFormat.PDF);

Windows 环境: 转换正常,中文完美显示 ✅

Linux/CentOS 环境: 转换后 PDF 中的中文字符显示为乱码(方块、问号或空白) ❌

Docker 环境: 同样出现中文乱码 ❌

1.2 乱码表现形式

表现截图示例原因
所有中文显示为 □□□ 方块文字被替代为系统缺失字体的占位符完全缺失中文字体
中文显示为 ???? 问号文本编码异常字体回退失败
中文完全不显示(空白)被渲染引擎跳过字体路径无效
部分中文正常,部分乱码字体中有部分字符缺失字体集不完整

二、问题原因

2.1 根本原因

Linux 服务器缺少对应的中文字库。

环境是否预装中文字体说明
Windows✅ 是系统自带 宋体、微软雅黑、黑体等
macOS✅ 是系统自带 苹方、华文细黑等
Linux(最小安装)❌ 否默认不包含中文字体
Docker(Alpine)❌ 否基础镜像仅包含极少字体
Docker(CentOS/Ubuntu)⚠️ 部分需要安装 fontconfig + 中文字体包

2.2 Aspose.Words 字体解析机制

Word 文档(DOCX)
    ↓
Aspose.Words 读取内容 + 字体引用
    ↓
查找系统字体(按优先级搜索)
    │
    ├─→ Windows: C:\Windows\Fonts\           ✅ 找到中文字体
    ├─→ Linux:   /usr/share/fonts/           ❌ 可能没有中文字体
    ├─→ Docker:  依赖镜像的字体包             ❌ 通常没有中文字体
    │
    ↓ 字体未找到
Aspose.Words 使用默认回退字体
    ↓
回退字体(通常为西方字体)不含中文
    ↓
PDF 输出中文乱码

2.3 Aspose.Words 字体的回退顺序

// Aspose.Words 查找字体的顺序:
// 1. 文档中指定的字体名称(如果系统中有)
// 2. FontSettings.DefaultFontName(如果设置了)
// 3. 系统默认的 sans-serif 字体
// 4. 最接近的可用字体

// 在 Linux 上,回退链最终指向无中文字体的西方字体
// 导致中文全部变为方块

三、解决方案一:环境级——安装字体

3.1 从 Windows 复制字体到 Linux

步骤 1:准备字体文件

在 Windows 机器上,打开文件夹:

C:\Windows\Fonts

将需要的字体文件(.ttf / .ttc)复制出来。必选的中文字体:

字体文件字体名称说明
simsun.ttc宋体(SimSun)最常见的衬线中文
msyh.ttf / msyhbd.ttf微软雅黑 / 微软雅黑加粗最常用的无衬线中文
simhei.ttf黑体(SimHei)标题用粗体
simfang.ttf仿宋(FangSong)公文用
simkai.ttf楷体(KaiTi)手写风格
SIMLI.TTF隶书(LiSu)
STXIHEI.TTF华文细黑
msmincho.ttc明朝体日文支持

简便做法:直接复制整个 Fonts 文件夹

# Windows 中压缩 C:\Windows\Fonts 文件夹
# 上传到 Linux 服务器

步骤 2:上传到 Linux

# 创建字体目录
mkdir -p /usr/share/fonts/chinese

# 上传字体文件(通过 scp 或 ftp)
scp -r /local/path/fonts/*.ttf root@server:/usr/share/fonts/chinese/
scp -r /local/path/fonts/*.ttc root@server:/usr/share/fonts/chinese/

# 或者使用 rz 命令
# rz  # 选择字体文件上传

步骤 3:安装字体工具

# CentOS / RHEL
yum install -y mkfontscale fontconfig

# Ubuntu / Debian
apt-get update
apt-get install -y fontconfig ttf-dejavu

# Alpine(Docker)
apk add --no-cache fontconfig ttf-dejavu

步骤 4:生成字体缓存

# 进入字体目录
cd /usr/share/fonts/chinese

# 生成字体索引(CentOS 执行以下两条)
mkfontscale
mkfontdir

# 清空字体缓存
fc-cache -fv

步骤 5:使字体生效

# 重启应用,或执行:
source /etc/profile

# 如果服务已运行,需要重启 Java 进程
# 验证字体是否安装成功
fc-list :lang=zh

# 输出应类似:
# 宋体,SimSun:style=Regular
# 微软雅黑,Microsoft YaHei:style=Normal
# 黑体,SimHei:style=Regular

3.2 使用 yum/apt 安装中文字体包

# CentOS / RHEL 使用 epel 源
yum install -y epel-release
yum install -y cjkuni-uming-fonts   # 宋体替代
yum install -y cjkuni-ukai-fonts    # 楷体替代
yum install -y google-noto-cjk-fonts  # Google Noto 中文字体

# Ubuntu / Debian
apt-get install -y fonts-wqy-microhei   # 文泉驿微米黑
apt-get install -y fonts-wqy-zenhei     # 文泉驿正黑
apt-get install -y fonts-noto-cjk       # Google Noto CJK

3.3 查看 Linux 当前字体

# 查看所有字体
fc-list

# 查看所有中文字体
fc-list :lang=zh

# 查看字体文件路径
fc-list :lang=zh | head -5
# 输出示例:
# /usr/share/fonts/chinese/msyh.ttf: Microsoft YaHei:style=Normal
# /usr/share/fonts/chinese/simsun.ttc: SimSun:style=Regular

3.4 设置字体权限

# 如果字体安装后仍不生效,检查文件权限
chmod -R 755 /usr/share/fonts/chinese/

# 或者更严格的权限
chmod 644 /usr/share/fonts/chinese/*
chmod 755 /usr/share/fonts/chinese/

# 重新生成缓存
fc-cache -fv

四、解决方案二:代码级——Aspose 字体配置

4.1 设置默认字体

import com.aspose.words.*;

/**
 * Aspose.Words 字体配置工具类
 */
public class AsposeFontUtil {

    /**
     * 设置默认字体为宋体(简单但有效)
     */
    public static void setDefaultFont() {
        FontSettings fontSettings = new FontSettings();
        // 设置默认回退字体为宋体(必须确保系统已安装该字体)
        fontSettings.getSubstitutionSettings()
                    .getDefaultFontSubstitution()
                    .setDefaultFontName("SimSun");
        // 应用到当前线程
        Document doc = new Document("input.docx");
        doc.setFontSettings(fontSettings);
        doc.save("output.pdf", SaveFormat.PDF);
    }
}

4.2 指定字体来源目录

/**
 * 指定自定义字体目录(推荐方案)
 * 
 * 优点:
 * - 不污染系统字体
 * - 可精确控制使用的字体
 * - 应用可自包含运行
 */
public static void setCustomFontFolder() {
    FontSettings fontSettings = new FontSettings();

    // 添加自定义字体文件夹(可以是项目内部的 resources/fonts)
    fontSettings.setFontsFolder("/app/fonts", false);

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

/**
 * 指定多个字体目录
 */
public static void setMultipleFontFolders() {
    FontSettings fontSettings = new FontSettings();

    // 添加多个字体来源目录
    fontSettings.setFontsFolders(
        new String[]{
            "/usr/share/fonts/chinese",
            "/app/resources/fonts",
            "/app/libs/fonts"
        },
        true  // 同时扫描子目录
    );

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

4.3 配置字体回退规则

/**
 * 配置字体回退规则(精细控制)
 * 
 * 当文档中使用的字体不存在时,按规则逐级回退
 */
public static void configureFontFallback() {
    FontSettings fontSettings = new FontSettings();
    FontFallbackSettings fallbackSettings = fontSettings.getFallbackSettings();

    // 清空默认规则
    fallbackSettings.getFallbackFonts().clear();

    // 添加回退规则:
    // 当文档使用字体范围 0x4E00-0x9FFF(CJK统一汉字)时,
    // 依次尝试 SimSun → Microsoft YaHei → Noto Sans CJK SC
    fallbackSettings.getFallbackFonts().add(
        0x4E00,   // Unicode 范围起始(中文)
        0x9FFF,   // Unicode 范围结束
        "SimSun", // 首选
        "Microsoft YaHei", // 备用1
        "Noto Sans CJK SC" // 备用2
    );

    // 其他常见 Unicode 范围:
    // 0x4E00-0x9FFF  →  CJK统一汉字
    // 0x3000-0x303F  →  CJK符号和标点
    // 0x3040-0x309F  →  日文平假名
    // 0x30A0-0x30FF  →  日文片假名
    // 0xAC00-0xD7AF  →  韩文音节
    // 0x0400-0x04FF  →  西里尔字母(俄语)
    // 0x0600-0x06FF  →  阿拉伯语

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

/**
 * 从配置文件加载回退规则
 */
public static void loadFallbackFromXml() {
    FontSettings fontSettings = new FontSettings();
    FontFallbackSettings fallbackSettings = fontSettings.getFallbackSettings();

    // 从 XML 规则文件加载
    fallbackSettings.load("fallback-rules.xml");

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

4.4 回退规则 XML 配置

<!-- fallback-rules.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<FontFallbackSettings>
    <!-- 中文回退规则 -->
    <FallbackRule>
        <Range Start="0x4E00" End="0x9FFF"/>
        <FallbackFont Name="SimSun"/>
        <FallbackFont Name="Microsoft YaHei"/>
        <FallbackFont Name="Noto Sans CJK SC"/>
        <FallbackFont Name="WenQuanYi Micro Hei"/>
    </FallbackRule>

    <!-- 中文标点符号 -->
    <FallbackRule>
        <Range Start="0x3000" End="0x303F"/>
        <FallbackFont Name="SimSun"/>
        <FallbackFont Name="Microsoft YaHei"/>
    </FallbackRule>

    <!-- 日文平假名/片假名 -->
    <FallbackRule>
        <Range Start="0x3040" End="0x30FF"/>
        <FallbackFont Name="MS Mincho"/>
        <FallbackFont Name="SimSun"/>
    </FallbackRule>

    <!-- 其他所有字符的通用回退 -->
    <FallbackRule>
        <Range Start="0x0000" End="0xFFFF"/>
        <FallbackFont Name="SimSun"/>
        <FallbackFont Name="Arial"/>
    </FallbackRule>
</FontFallbackSettings>

4.5 完整工具类

import com.aspose.words.*;
import java.io.File;

/**
 * Aspose.Words 字体配置工具类
 */
public class AsposeWordHelper {

    private static volatile boolean fontConfigured = false;

    /**
     * 初始化字体配置(全局一次)
     * 
     * @param fontDir 自定义字体目录,若为 null 则尝试自动检测
     */
    public static void initFontSettings(String fontDir) {
        if (fontConfigured) return;

        FontSettings fontSettings = getDefaultFontSettings(fontDir);

        // 将 FontSettings 设置为全局默认(对所有 Document 生效)
        FontSettings.setDefaultFontSettings(fontSettings);

        fontConfigured = true;
    }

    /**
     * 获取默认字体配置
     */
    private static FontSettings getDefaultFontSettings(String fontDir) {
        FontSettings fontSettings = new FontSettings();

        // 1. 设置默认回退字体
        fontSettings.getSubstitutionSettings()
                    .getDefaultFontSubstitution()
                    .setDefaultFontName("SimSun");

        // 2. 添加字体来源目录
        String fontsPath = detectFontPath(fontDir);
        if (fontsPath != null) {
            fontSettings.setFontsFolder(fontsPath, true);
        }

        // 3. 配置回退规则(额外保护)
        FontFallbackSettings fallback = fontSettings.getFallbackSettings();
        fallback.getFallbackFonts().add(
            0x4E00, 0x9FFF,
            "SimSun",
            "Microsoft YaHei",
            "Noto Sans CJK SC",
            "WenQuanYi Micro Hei"
        );

        return fontSettings;
    }

    /**
     * 自动检测字体目录
     */
    private static String detectFontPath(String customDir) {
        // 1. 优先使用自定义目录
        if (customDir != null && new File(customDir).exists()) {
            return customDir;
        }

        // 2. 常见系统字体目录
        String[] commonPaths = {
            "/usr/share/fonts",
            "/usr/share/fonts/chinese",
            "/usr/local/share/fonts",
            System.getProperty("user.dir") + "/fonts",
            System.getProperty("user.dir") + "/src/main/resources/fonts"
        };

        for (String path : commonPaths) {
            if (new File(path).exists()) {
                return path;
            }
        }

        return null;
    }

    /**
     * Word 转 PDF
     */
    public static void wordToPdf(String inputPath, String outputPath)
            throws Exception {
        // 确保字体配置已初始化
        initFontSettings(null);

        Document doc = new Document(inputPath);
        doc.save(outputPath, SaveFormat.PDF);
    }

    /**
     * Word 转 PDF(自定义字体目录)
     */
    public static void wordToPdf(String inputPath, String outputPath,
                                  String fontDir) throws Exception {
        initFontSettings(fontDir);

        Document doc = new Document(inputPath);
        doc.save(outputPath, SaveFormat.PDF);
    }

    /**
     * 调试:输出当前字体信息
     */
    public static void printFontInfo() {
        FontSettings fontSettings = FontSettings.getDefaultFontSettings();
        System.out.println("=== Aspose Font Info ===");
        System.out.println("Default Font: " +
            fontSettings.getSubstitutionSettings()
                        .getDefaultFontSubstitution()
                        .getDefaultFontName());

        String[] folders = fontSettings.getFontsFolders();
        if (folders != null) {
            for (String folder : folders) {
                System.out.println("Font Folder: " + folder);
            }
        }

        // 列出所有可用字体
        String[] fontNames = fontSettings.getFontsSources();
        if (fontNames != null) {
            System.out.println("Available font sources: " + fontNames.length);
        }
    }
}

五、解决方案三:Docker 环境

5.1 Dockerfile 方式

# 基于 CentOS 的 Dockerfile
FROM centos:7

# 安装中文字体
RUN yum install -y epel-release \
    && yum install -y \
        fontconfig \
        mkfontscale \
        cjkuni-uming-fonts \
        cjkuni-ukai-fonts \
        google-noto-cjk-fonts \
    && yum clean all \
    && fc-cache -fv

# 或者从 Windows 复制字体(推荐)
COPY fonts/ /usr/share/fonts/chinese/
RUN mkfontscale /usr/share/fonts/chinese/ \
    && mkfontdir /usr/share/fonts/chinese/ \
    && fc-cache -fv

# 部署应用
COPY app.jar /app/
CMD ["java", "-jar", "/app/app.jar"]
# 基于 Alpine 的 Dockerfile(更小体积)
FROM openjdk:8-jre-alpine

# 安装 fontconfig 和字体
RUN apk add --no-cache fontconfig ttf-dejavu

# 复制中文字体
COPY fonts/ /usr/share/fonts/truetype/chinese/
RUN fc-cache -fv

COPY app.jar /app/
CMD ["java", "-jar", "/app/app.jar"]
# 基于 Ubuntu 的 Dockerfile
FROM ubuntu:20.04

RUN apt-get update \
    && apt-get install -y \
        fontconfig \
        fonts-wqy-microhei \
        fonts-wqy-zenhei \
        fonts-noto-cjk \
    && apt-get clean \
    && fc-cache -fv

COPY app.jar /app/
CMD ["java", "-jar", "/app/app.jar"]

5.2 Docker Compose 方式

version: '3.8'
services:
  app:
    image: my-java-app:latest
    volumes:
      # 挂载字体目录(不用把字体打包进镜像)
      - ./fonts:/usr/share/fonts/custom:ro
    environment:
      - JAVA_OPTS=-Dfile.encoding=UTF-8

5.3 验证 Docker 字体

# 进入容器验证
docker exec -it <container_id> /bin/bash

# 查看中文字体
fc-list :lang=zh

# 如果看不到字体,可能是 fontconfig 未安装
# 也可以直接检查文件
ls -la /usr/share/fonts/

5.4 推荐:项目中打包字体

<!-- Maven 将字体打包到 JAR 中 -->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>fonts/**/*.ttf</include>
                <include>fonts/**/*.ttc</include>
            </includes>
        </resource>
    </resources>
</build>
项目结构中的字体位置:
src/main/resources/fonts/
├── SimSun.ttf
├── msyh.ttf
└── msyhbd.ttf
// 从 classpath 中导出字体到临时目录
public void extractFontsFromClasspath() throws Exception {
    String tempFontDir = System.getProperty("java.io.tmpdir")
            + "/aspose-fonts/";
    new File(tempFontDir).mkdirs();

    // 从 JAR 中复制字体
    copyFromClasspath("/fonts/SimSun.ttf",
            tempFontDir + "SimSun.ttf");
    copyFromClasspath("/fonts/msyh.ttf",
            tempFontDir + "msyh.ttf");

    // 设置字体路径
    FontSettings fontSettings = new FontSettings();
    fontSettings.setFontsFolder(tempFontDir, false);
    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

private void copyFromClasspath(String resource, String dest)
        throws IOException {
    try (InputStream in = getClass().getResourceAsStream(resource);
         OutputStream out = new FileOutputStream(dest)) {
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }
    }
}

六、解决方案四:使用字体文件直接注册

6.1 PhysicalFont 注册

/**
 * 直接通过文件路径注册字体(不依赖系统字体目录)
 */
public static void registerFontByFile() {
    FontSettings fontSettings = new FontSettings();

    // 直接从指定文件加载字体
    FontSourceBase fontSource = new FileFontSource(
        "/opt/fonts/SimSun.ttf",   // 字体文件路径
        0,                          // 优先级(越小越优先)
        "Custom SimSun"             // 标识名称(可选)
    );

    fontSettings.setFontsSources(new FontSourceBase[]{fontSource});

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

/**
 * 注册多个字体文件
 */
public static void registerMultipleFonts() {
    FontSettings fontSettings = new FontSettings();

    // 创建多个字体源
    FontSourceBase[] sources = new FontSourceBase[]{
        new FileFontSource("/opt/fonts/SimSun.ttf", 0),
        new FileFontSource("/opt/fonts/msyh.ttf", 1),
        new FileFontSource("/opt/fonts/simsun.ttc", 2),
    };

    fontSettings.setFontsSources(sources);

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

6.2 MemoryFontSource(用于加密字体)

/**
 * 从内存中加载字体(适用于加密或保护字体文件)
 */
public static void registerFontFromMemory() throws IOException {
    // 读取加密的字体文件
    byte[] fontData = decryptFontFile("encrypted-simsun.bin");

    FontSourceBase memoryFont = new MemoryFontSource(fontData, 0);
    FontSettings fontSettings = new FontSettings();
    fontSettings.setFontsSources(new FontSourceBase[]{memoryFont});

    Document doc = new Document("input.docx");
    doc.setFontSettings(fontSettings);
    doc.save("output.pdf", SaveFormat.PDF);
}

private static byte[] decryptFontFile(String path) throws IOException {
    // 解密逻辑(示例)
    byte[] encrypted = Files.readAllBytes(Paths.get(path));
    byte[] decrypted = new byte[encrypted.length];
    for (int i = 0; i < encrypted.length; i++) {
        decrypted[i] = (byte) (encrypted[i] ^ 0x7F); // 简单 XOR 解密
    }
    return decrypted;
}

七、调试与诊断

7.1 调试工具

/**
 * 字体诊断工具——输出当前系统所有可用字体
 */
public void diagnoseFonts() {
    // 方法 1:通过 Aspose API
    FontSettings fontSettings = FontSettings.getDefaultFontSettings();
    System.out.println("=== Aspose Font Settings ===");
    System.out.println("Default Font Name: " +
        fontSettings.getSubstitutionSettings()
                    .getDefaultFontSubstitution()
                    .getDefaultFontName());

    // 方法 2:列出所有字体源
    FontSourceBase[] sources = fontSettings.getFontsSources();
    for (FontSourceBase source : sources) {
        System.out.println("Font Source Type: " + source.getType());
        System.out.println("Priority: " + source.getPriority());

        // 列出该源下的所有字体
        PhysicalFontInfo[] fonts = source.getAvailableFonts();
        for (PhysicalFontInfo font : fonts) {
            System.out.printf("  Font: %s (%s)%n",
                font.getFullFontName(), font.getFilePath());
        }
    }
}

7.2 Linux 字体调试命令

# 查看系统所有字体
fc-list | sort

# 查看中文字体
fc-list :lang=zh | sort

# 查看特定字体是否存在
fc-match SimSun
# 输出:SimSun.ttc: "宋体" "Regular"

# 查看字体文件详情
fc-list -v | grep -i "cjk\|chinese\|simsun\|yahei"

# 查看 fontconfig 配置
fc-conflist

# 测试字体渲染(需要安装 imagemagick)
convert -font SimSun -pointsize 24 \
        label:'中文测试' test.png

7.3 Java 调试

# 查看 JVM 能识别的字体
java -cp aspose-words.jar:
      com.aspose.words.FontSettings

# 开启 Aspose 调试日志
# 在 log4j.properties 中添加:
log4j.logger.com.aspose.words.FontSettings=DEBUG

7.4 常见调试输出解读

# 正常情况——能找到字体
[DEBUG] Font 'SimSun' found in system fonts collection
[DEBUG] Using font 'SimSun' for CJK characters

# 异常情况——找不到字体
[WARN] Font 'SimSun' is not available
[WARN] Fallback to default font 'Arial'
[ERROR] No suitable font found for Unicode range 0x4E00-0x9FFF

八、常见问题排查

8.1 问题对照表

问题现象原因解决方案
所有中文变方块□□□无中文字体安装字体 + fc-cache
部分中文变方块某些字正常某些方块字体不全换用完整字体(如 Noto CJK)
中文显示为空白文字不可见字体渲染失败检查字体文件权限
加粗中文乱码粗体显示异常未安装粗体版本复制 msyhbd.ttf 等粗体文件
斜体中文乱码斜体显示异常无斜体字体设置 getSubstitutionSettings()
Docker 乱码容器内乱码基础镜像无字体Dockerfile 安装字体
仅在特定 Doc 乱码一个文档乱码另一个正常文档嵌入了字体子集检查文档嵌入字体
PDF 体积过大PDF 文件异常大嵌入了大量字体设置字体子集化

8.2 字体文件完整性检查

# 检查 ttf 文件是否损坏
file simsun.ttc
# 输出:TrueType font collection data

# 检查 ttc 中包含的字体列表
python -c "
from fontTools.ttLib import TTFont
font = TTFont('simsun.ttc')
font.keys()
"

8.3 快速环境修复脚本

#!/bin/bash
# fix-chinese-fonts.sh
# 一键修复 CentOS 中文乱码

echo "=== 开始修复中文乱码 ==="

# 1. 创建字体目录
mkdir -p /usr/share/fonts/chinese

# 2. 如果没有字体文件,尝试从网络下载
if [ ! -f "/usr/share/fonts/chinese/SimSun.ttf" ]; then
    echo "下载 Noto CJK 字体..."
    yum install -y google-noto-cjk-fonts
fi

# 3. 安装 fontconfig
yum install -y mkfontscale fontconfig

# 4. 生成字体缓存
cd /usr/share/fonts/chinese
mkfontscale 2>/dev/null || true
mkfontdir 2>/dev/null || true
fc-cache -fv

# 5. 验证
echo "=== 已安装的中文字体 ==="
fc-list :lang=zh 2>/dev/null | head -10

echo "=== 修复完成 ==="
echo "如果仍存在问题:"
echo "1. 将 Windows 的 C:\\Windows\\Fonts 复制到 /usr/share/fonts/chinese/"
echo "2. 重新运行本脚本"
echo "3. 重启应用"

8.4 快速排查清单

  • fc-list :lang=zh 能否看到中文字体
  • 字体文件权限是否为 644 / 755
  • 字体目录是否在 Aspose 的搜索路径中
  • 是否在 FontSettings 中设置了 DefaultFontName
  • Docker 中是否安装了 fontconfig
  • Docker 中是否执行了 fc-cache -fv
  • 项目中是否打包了备用字体
  • 文档中是否使用了稀有字体(如特殊艺术字)

九、总结

9.1 解决方案优先级

方案一:环境装字体         ✅ 一劳永逸,推荐
  ├─ 复制 Windows 字体     ✅ 最完整
  └─ yum/apt 安装包         ✅ 方便但字体可能不全

方案二:Aspose 代码配置     ✅ 双重保险,强烈推荐
  ├─ setDefaultFontName()   ✅ 设置回退字体
  ├─ setFontsFolder()       ✅ 自定义字体目录
  ├─ FontFallbackSettings   ✅ 精细回退规则
  └─ FileFontSource         ✅ 直接注册字体文件

方案三:Docker 配置          ✅ 容器化部署
  ├─ Dockerfile 安装         ✅ 不可变镜像
  └─ Volume 挂载             ✅ 灵活替换

方案四:打包在项目中         ✅ 自包含,无环境依赖
  ├─ resources/fonts/        ✅ JAR 内嵌字体
  └─ 运行时解压              ✅ 独立运行

9.2 最佳实践

/**
 * 生产环境推荐配置
 */
@PostConstruct
public void initAsposeFonts() {
    FontSettings fontSettings = new FontSettings();

    // 1. 默认回退字体
    fontSettings.getSubstitutionSettings()
                .getDefaultFontSubstitution()
                .setDefaultFontName("SimSun");

    // 2. 目录优先级:项目字体 > 系统字体
    String projectFonts = System.getProperty("user.dir") + "/fonts";
    if (new File(projectFonts).exists()) {
        // 项目字体目录(最高优先级)
        fontSettings.setFontsFolder(projectFonts, false);
    } else {
        // 回退到系统字体目录
        fontSettings.setFontsFolder("/usr/share/fonts", true);
    }

    // 3. CJK 回退规则
    FontFallbackSettings fallback = fontSettings.getFallbackSettings();
    fallback.getFallbackFonts().add(
        0x4E00, 0x9FFF,
        "SimSun",
        "Microsoft YaHei",
        "WenQuanYi Micro Hei",
        "Noto Sans CJK SC"
    );

    FontSettings.setDefaultFontSettings(fontSettings);
    log.info("Aspose font settings initialized");
}

9.3 各平台一站式对照

步骤WindowsLinux (CentOS)Linux (Ubuntu)Docker (Alpine)Docker (CentOS)
安装字体工具无需yum install mkfontscale fontconfigapt install fontconfigapk add fontconfig同 CentOS
安装中文字体系统自带yum install google-noto-cjk-fontsapt install fonts-noto-cjk复制字体文件同 CentOS 并复制字体
字体目录C:\Windows\Fonts/usr/share/fonts/usr/share/fonts/usr/share/fonts/usr/share/fonts
缓存命令无需fc-cache -fvfc-cache -fvfc-cache -fvfc-cache -fv
Aspose 设置非必需(可选)必需必需必需必需

9.4 核心要点

  1. 环境是基础:确保 Linux/Docker 安装了中文字体(fc-list :lang=zh 验证)
  2. 代码是保障:始终在 Aspose 中设置 DefaultFontName 和自定义字体目录
  3. 字体完整:粗体(Bold)、斜体(Italic)版本都需要安装
  4. 权限正确:字体文件需要可读权限(chmod 644
  5. 缓存更新:安装字体后执行 fc-cache -fv
  6. 自包含:关键项目将字体打包在 JAR 中,避免环境依赖
  7. 验证:转换后打开 PDF 检查所有中文是否正常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值