首先,需要明确一点,PDF.js 的版本迭代非常快。截至目前,pdfjs-dist
的稳定版本是 v4.x 系列。虽然你提到了 v5.0,但核心 API 获取批注的方式在最近的主要版本(v3.x, v4.x)中没有发生根本性的变化。因此,之前描述的方法对于当前和近期未来的版本(很可能也包括未来的 v5.0)仍然是有效的。
核心方法依然是使用 PDFPageProxy
对象的 getAnnotations()
方法。
以下是基于当前稳定版本 (v4.x) 并适用于未来版本的中文说明:
核心方法:使用 page.getAnnotations()
这是从 PDF 文档结构中读取批注数据的标准和推荐方式。
-
设置和加载文档:
- 确保你已经安装了
pdfjs-dist
包。 - 设置 Worker 源:这是运行 PDF 解析任务所必需的。
- 使用
pdfjsLib.getDocument()
加载 PDF 文件。
javascriptimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'; // 使用 ES 模块版本 // 或 const pdfjsLib = require('pdfjs-dist/build/pdf.js'); // 使用 CommonJS 版本 // 非常重要:设置 Worker 路径 // 可以指向 node_modules 或你部署 worker 文件的位置 // 例如,如果使用 Webpack 或类似工具,可以这样配置: // import workerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url'; // Vite/Webpack 5+ URL loader // pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc; // 或者直接提供 URL 字符串: pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.2.67/pdf.worker.mjs'; // 使用 CDN 的例子 (版本号需匹配) // 或者指向你本地部署的 worker 文件 // pdfjsLib.GlobalWorkerOptions.workerSrc = '/path/to/your/pdf.worker.mjs'; const pdfPath = '你的PDF文件路径或者URL';
- 确保你已经安装了
-
获取页面并调用
getAnnotations()
:- 获取
PDFDocumentProxy
对象(文档对象)。 - 遍历文档的每一页,获取
PDFPageProxy
对象(页面对象)。 - 对每个页面对象调用
page.getAnnotations()
方法。这是一个异步方法,返回一个 Promise,该 Promise 解析为一个包含该页面所有批注数据的对象数组。
javascriptasync function getAllAnnotations(pdfPath) { const loadingTask = pdfjsLib.getDocument(pdfPath); try { const pdfDocument = await loadingTask.promise; console.log(`PDF 文档加载成功,总页数: ${pdfDocument.numPages}`); const allAnnotationsData = []; // 存储所有批注数据 for (let i = 1; i <= pdfDocument.numPages; i++) { const page = await pdfDocument.getPage(i); console.log(`正在处理第 ${i} 页...`); // 获取当前页面的批注数据数组 const annotations = await page.getAnnotations(); if (annotations.length > 0) { console.log(`第 ${i} 页找到 ${annotations.length} 个批注。`); // 为每个批注添加页码信息,方便后续使用 const annotationsWithPageNum = annotations.map(anno => ({ ...anno, // 复制原始批注数据 pageNumber: i // 添加页码字段 })); allAnnotationsData.push(...annotationsWithPageNum); } else { console.log(`第 ${i} 页没有批注。`); } // 注意:在 v4.x 及以后版本,不再需要手动调用 page.cleanup(), // PDF.js 内部会更好地管理内存。 } console.log(`\n文档中总共获取到 ${allAnnotationsData.length} 个批注。`); return allAnnotationsData; } catch (error) { console.error('加载或处理 PDF 时出错:', error); throw error; // 或者返回空数组 [] } } // --- 如何使用 --- getAllAnnotations(pdfPath) .then(annotations => { console.log('\n--- 所有批注的详细数据 ---'); annotations.forEach((anno, index) => { console.log( `${index + 1}: 页码=${anno.pageNumber}, ` + `类型=${anno.subtype}, ` + `ID=${anno.id}, ` + // 批注 ID `矩形区域=[${anno.rect}], ` + `内容=${anno.contents || '无'}` // 显示文本内容(如果有) ); // 你可以根据 anno.subtype (类型) 来访问不同的特定属性 // 例如,对于 'Link' 类型,可能有 anno.url // 对于 'Highlight', 'Underline' 等,可能有 anno.quadPoints }); }) .catch(err => { console.error('获取批注失败:', err); });
- 获取
要点总结 (适用于 v4.x 及以后版本):
- API 稳定性 :
page.getAnnotations()
是获取批注的核心且稳定的 API,在 v4.x 中依然如此,预计在 v5.0 中也不会改变。 - 异步操作 : 记住
getDocument()
、getPage()
和getAnnotations()
都是异步的,需要使用async/await
或.then()
处理 Promise。 - 返回数据 :
getAnnotations()
返回的是原始的 JavaScript 对象数组 ,每个对象代表一个批注,其属性直接对应 PDF 规范中定义的批注字典字段(如subtype
,rect
,contents
,color
,id
,modificationDate
等)。它返回的不是 HTML 元素。 - Worker 配置 : 正确设置
GlobalWorkerOptions.workerSrc
是 PDF.js 运行的前提,尤其是在浏览器环境或 Node.js 中。确保 worker 文件的版本与你使用的pdfjs-dist
版本匹配。 - 批注类型 : 返回的批注数据结构会根据批注的
subtype
(类型,如 'Text', 'Link', 'Highlight', 'Square', 'Ink' 等) 而有所不同,包含各自特定的属性。你需要查阅 PDF 规范或 PDF.js 文档来了解不同类型批注的具体属性。 - 内存管理 : 较新版本的 PDF.js (v3.x 之后) 改进了内存管理,通常不再需要像旧版本那样显式调用
page.cleanup()
,尤其是在只获取批注数据时。
如果你在使用 PDF.js 预构建的查看器 (Viewer):
获取批注的方式与之前描述的类似,你需要先获取到查看器实例 (PDFViewerApplication
),然后通过 PDFViewerApplication.pdfDocument
拿到 PDFDocumentProxy
对象,接下来的步骤就和上面的核心方法一样了。
javascript
// 在查看器环境的控制台或脚本中运行
async function getAnnotationsFromViewer() {
if (typeof PDFViewerApplication === 'undefined' || !PDFViewerApplication.pdfDocument) {
console.error('PDFViewerApplication 或其 pdfDocument 尚未准备好。');
return;
}
const pdfDocument = PDFViewerApplication.pdfDocument;
// ... 接下来的逻辑和上面的 getAllAnnotations 函数内部类似 ...
// 遍历 pdfDocument.numPages, 调用 pdfDocument.getPage(i), 然后 page.getAnnotations()
// ...
}
总之,获取 PDF 批注列表的核心方法 page.getAnnotations()
在 PDF.js v4.x(以及可预见的未来版本)中保持稳定和有效。关键在于正确设置环境、处理异步操作并理解返回的数据结构。