如何使用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
相关产品推荐
相关产品推荐

