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

如何使用Mozilla PdfJs Viewer导出和导入PDF注释为JSON格式

如何使用Mozilla PdfJs Viewer导出和导入PDF注释为JSON格式

我之前也碰到过和你一模一样的需求,用PDF.js Viewer做注释后导出成JSON,再导入回去渲染,一开始也遇到了注释存进storage但UI不显示的问题,后来摸索出了正确的做法,分享给你:

一、正确导出注释为JSON

你用pdfDocument.annotationStorage.serializable()获取注释Map的思路是对的,但直接把Map转JSON会有问题,因为JSON不支持Map类型,所以要先转成数组再序列化:

// 获取可序列化的注释Map
const annotationsMap = pdfDocument.annotationStorage.serializable();
// 转成数组后再序列化为JSON字符串,方便存储
const annotationsJson = JSON.stringify(Array.from(annotationsMap));
// 这里可以把JSON存到localStorage、后端数据库或者文件里
localStorage.setItem('pdfAnnotations', annotationsJson);

二、正确导入注释并触发UI渲染

你之前的代码只把注释存入了annotationStorage,但Viewer的页面已经缓存了初始的注释状态,所以不会自动刷新。必须在存入后手动触发注释的重新绘制,具体步骤如下:

方式1:文档加载完成后导入

如果是自己初始化PDF文档,可以在文档加载完成后导入注释,然后刷新页面的注释图层:

pdfjsLib.getDocument({
  data: pdfData,
  cMapUrl: CMAP_URL,
  cMapPacked: CMAP_PACKED,
  enableXfa: true,
}).promise.then((pdfDocument) => {
  // 从存储中读取保存的注释JSON
  const savedAnnotationsJson = localStorage.getItem('pdfAnnotations');
  if (!savedAnnotationsJson) return;

  // 解析JSON转回Map格式
  const annotationsArray = JSON.parse(savedAnnotationsJson);
  const annotationsMap = new Map(annotationsArray);

  // 将注释存入annotationStorage
  for (const [key, value] of annotationsMap) {
    pdfDocument.annotationStorage.setValue(key, value);
  }

  // 关键:获取Viewer实例并触发注释重新渲染
  const viewer = window.PDFViewerApplication.pdfViewer;
  // 遍历所有页面,清空旧缓存并重新绘制注释
  viewer.getPages().forEach((page) => {
    page.annotations = null; // 清除页面的注释缓存
    page.drawAnnotations(); // 重新绘制该页面的注释
  });
});

方式2:利用Viewer的事件监听(更适配官方Viewer)

如果你用的是官方的PDF.js Viewer页面,可以通过监听documentLoaded事件来导入注释,这样时机更稳妥:

// 等待Viewer加载完成
document.addEventListener('webviewerloaded', () => {
  // 监听文档加载完成事件
  PDFViewerApplication.eventBus.on('documentLoaded', () => {
    const pdfDocument = PDFViewerApplication.pdfDocument;
    const savedAnnotationsJson = localStorage.getItem('pdfAnnotations');
    
    if (savedAnnotationsJson) {
      const annotationsArray = JSON.parse(savedAnnotationsJson);
      const annotationsMap = new Map(annotationsArray);
      
      // 存入注释
      for (const [key, value] of annotationsMap) {
        pdfDocument.annotationStorage.setValue(key, value);
      }
      
      // 直接调用Viewer的refresh方法更新整个视图
      PDFViewerApplication.pdfViewer.refresh();
    }
  });
});

为什么你的代码没生效?

你之前只把注释存入了annotationStorage,但Viewer的每个页面都已经缓存了初始化时的注释数据,不会自动监听annotationStorage的变化,所以必须手动触发页面的注释重新绘制或者Viewer的整体刷新,这样导入的注释才会显示在UI上。

注意事项

  • 确保导出的注释JSON完整保留了原有的key和value结构,key是注释的唯一ID,value是注释的序列化对象,不能随意修改。
  • 如果是跨PDF文档导入注释,要确保注释对应的页面索引和目标PDF一致,否则注释会显示错误或者不显示。
  • 注释的序列化和反序列化必须用serializable()和Map的方式,不要自己手动拼接注释对象,避免格式错误。

备注:内容来源于stack exchange,提问作者Santhosh Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:59:32