You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PDF.js填充PDF表单:修改后无法保存文档的问题

程序化填充PDF表单的问题

尝试pdf-lib遇到的问题

  • 表单包含名称重复的复选框字段,结构示例:
{...
"employment.employment": [
  {
    id: '243R',
    value: 'Off',
    defaultValue: null,
    exportValues: 'YES',
    editable: true,
    name: 'employment',
    rect: [ 264.12, 529.496, 274.23, 539.604 ],
    hidden: false,
    actions: null,
    page: -1,
    strokeColor: null,
    fillColor: null,
    rotation: 0,
    type: 'checkbox'
  },
  {
    id: '244R',
    value: 'Off',
    defaultValue: null,
    exportValues: 'NO',
    editable: true,
    name: 'employment',
    rect: [ 307.971, 529.138, 318.081, 539.246 ],
    hidden: false,
    actions: null,
    page: -1,
    strokeColor: null,
    fillColor: null,
    rotation: 0,
    type: 'checkbox'
  }
]
}
  • pdf-lib无法正确解析这类字段,仅能设置243R的值,244R仿佛不存在,推测是字段名称重复导致;且该库已停止维护。

尝试pdf.js遇到的问题

  • 能加载文档、获取字段并设置值,但调用saveDocument或getData仅返回未修改的原始文档,代码示例:
const run = async () => {
  const loading = pdfjs.getDocument('form-cms1500.pdf')
  const pdf = await loading.promise
  const fields = await pdf.getFieldObjects()

  console.log(fields['employment.employment'] )
  fields['employment.employment'][0].value = 'On'
  console.log(fields['employment.employment'] )
  await fs.writeFileSync('test.pdf', await pdf.saveDocument()) // 抛出警告:saveDocument called while `annotationStorage` is empty, please use the getData-method instead.
}
  • 核心疑问:如何用pdf.js保存修改后的PDF文档?

解决方法

问题根源

直接修改getFieldObjects()返回的对象不会触发pdf.js内部状态更新,因为这些字段对象只是只读快照,未绑定到文档的可编辑实例;同时annotationStorage为空,说明修改未被记录到文档的注释存储中。

正确的填充与保存步骤

  1. 启用注释存储:加载文档时配置enableAnnotationStorage: true,跟踪修改记录
  2. 使用官方字段API修改:通过pdf.getField()获取字段实例,调用setValue()方法修改值,而非直接修改对象属性
  3. 用getData()保存:按照警告提示,使用getData()获取修改后的文档数据再写入文件

修改后的代码示例:

const fs = require('fs').promises;
const pdfjsLib = require('pdfjs-dist');

const run = async () => {
  // 加载文档时启用注释存储
  const loadingTask = pdfjsLib.getDocument({
    url: 'form-cms1500.pdf',
    enableAnnotationStorage: true
  });
  const pdf = await loadingTask.promise;

  // 获取字段实例,处理同名字段组
  const employmentField = await pdf.getField('employment.employment');
  // 传入对应选项的exportValues值,选中目标复选框
  employmentField.setValue('YES'); // 对应id=243R的复选框,exportValues为YES

  // 获取修改后的文档数据并写入文件
  const modifiedPdfData = await pdf.getData();
  await fs.writeFile('test.pdf', modifiedPdfData);
};

run().catch(err => console.error(err));

重复名称字段说明

pdf.js的getField()会自动处理同名字段组(如示例中的复选框组),调用setValue()时传入对应选项的exportValues值(如'YES'或'NO'),即可正确选中对应的复选框,无需手动操作单个字段实例。


内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:31:09