PDF.js 预览中文 PDF 出现乱码如何解决?

使用 PDF.js 预览 PDF 文件,部分 PDF 字体显示乱码。
PDF 文件信息:

  • 字体类型:CIDFont / Type0(嵌入式中文字体)
  • 生成工具:WPS Office / Adobe Acrobat 导出

环境信息:

  • PDF.js 版本:4.x
  • 浏览器:Chrome 最新版
    相关代码:

    const loadingTask = pdfjsLib.getDocument({
    url: 'example.pdf',
    cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/cmaps/',
    cMapPacked: true,
    standardFontDataUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/standard_fonts/',
    });

    请问如何正确配置让文字正常显示?是否需要服务端预处理 PDF?

已尝试的方案(均未生效):

  1. 配置 cMapUrlstandardFontDataUrl
  2. CSS @font-face 设置 fallback 字体
  3. PDF.js worker 版本已启用
  4. 浏览器控制台无字体加载失败日志,无报错
    期望效果:
  5. 遇到不支持的字体时,自动 fallback 到默认字体(宋体/微软雅黑)
  6. 或加载自定义 TTF 作为替代字体
    环境:
  7. PDF.js 4.x + Chrome 最新版 + Worker 模式
阅读 627
1 个回答

方法(推荐)

  1. 用 Ghostscript
    Mac / Linux 安装
brew install ghostscript
# 或
apt install ghostscript

Windows
下载: https://www.ghostscript.com

Windows命令使用

gs -o fixed.pdf 
   -sDEVICE=pdfwrite 
   -dEmbedAllFonts=true 
   -dSubsetFonts=false 
   -dPDFSETTINGS=/prepress 
   input.pdf

作用:
嵌入完整字体(非子集)
增加 ToUnicode 映射

Node.js 调用写法

const { execFile } = require('child_process');

function fixPdf(input, output) {
  return new Promise((resolve, reject) => {

    const gsCmd = process.platform === 'win32'
      ? 'gswin64c'
      : 'gs';

    const args = [
      '-o', output,
      '-sDEVICE=pdfwrite',

      '-dEmbedAllFonts=true',
      '-dSubsetFonts=false',
      '-dPDFSETTINGS=/prepress',

      '-dNOPAUSE',
      '-dBATCH',
      '-dQUIET',

      input
    ];

    execFile(gsCmd, args, (err, stdout, stderr) => {
      if (err) {
        console.error(stderr);
        reject(err);
      } else {
        resolve();
      }
    });
  });
}