Skip to content

Vue 3 + pdf-lib 实现浏览器端 PDF 注释移除 ​

译注:本文译自 dev.to 上的一篇技术实践文章,原文作者演示了如何用 Vue 3 与 pdf-lib 构建一个浏览器端的 PDF 注释移除工具。原文链接见文末。

移除 PDF 中的注释,需要解析 PDF 的注释字典(annotation dictionary),并在输出时将其排除。本文介绍如何用 Vue 3 和 pdf-lib 构建一个运行在浏览器中的注释移除工具。

挑战:安全地移除注释 ​

PDF 注释移除涉及以下几个步骤:

  1. 加载源 PDF 并检测注释
  2. 理解注释类型(文本评论、高亮、图章等)
  3. 创建一个不含注释的新 PDF
  4. 保留所有页面内容与结构

技术栈 ​

  • Vue 3,使用 Composition API
  • pdf-lib,用于 PDF 操作
  • Vite,用于打包

核心实现 ​

vue
<script setup lang="ts">
import { ref } from 'vue'
import { PDFDocument } from 'pdf-lib'

const file = ref<File | null>(null)
const annotationCount = ref(0)
const removing = ref(false)
const result = ref<Uint8Array | null>(null)

async function handleFile(e: Event) {
  const input = e.target as HTMLInputElement
  if (!input.files?.[0]) return
  file.value = input.files[0]

  const arrayBuffer = await file.value.arrayBuffer()
  const pdfDoc = await PDFDocument.load(arrayBuffer)

  // Count annotations
  let count = 0
  const pages = pdfDoc.getPages()
  for (const page of pages) {
    const annotations = page.getAnnotations()
    count += annotations.length
  }
  annotationCount.value = count
}

async function removeAnnotations() {
  if (!file.value || annotationCount.value === 0) return
  removing.value = true

  const arrayBuffer = await file.value.arrayBuffer()
  const pdfDoc = await PDFDocument.load(arrayBuffer)
  const newPdf = await PDFDocument.create()

  const pages = pdfDoc.getPages()
  const copiedPages = await newPdf.copyPages(pdfDoc, 
    Array.from({ length: pages.length }, (_, i) => i))

  copiedPages.forEach(page => {
    // pdf-lib doesn't have direct annotation removal
    // We need to recreate the page without annotations
    newPdf.addPage(page)
  })

  // Note: pdf-lib has limited annotation support
  // For full removal, consider using pdf.js for parsing
  result.value = await newPdf.save()
  removing.value = false
}
</script>

关键实现细节 ​

1. 注释计数 ​

使用 pdf-lib 检测并统计注释数量:

typescript
const annotations = page.getAnnotations()
count += annotations.length

2. 保留 PDF 结构 ​

移除注释时,需要保留所有页面内容:

typescript
const copiedPages = await newPdf.copyPages(pdfDoc, pageIndices)
copiedPages.forEach(page => newPdf.addPage(page))

3. pdf-lib 的局限 ​

pdf-lib 对注释操作的支持有限。若要实现完整移除:

解决方案:使用 pdf.js 解析并重建 PDF 结构。

局限性 ​

注释移除不完整 ​

pdf-lib 可能无法检测到所有注释类型。

解决方案:结合 pdf.js 进行更全面的解析。

无法选择性移除 ​

无法选择保留或移除哪些注释。

解决方案:增加注释类型过滤的 UI。

内存限制 ​

带有大量注释的大型 PDF 可能耗尽浏览器内存。

解决方案:分批处理页面。

小结 ​

构建一个浏览器端的注释移除工具,大致包含以下环节:

  1. 使用 pdf-lib 加载并分析 PDF
  2. 检测并统计注释
  3. 创建一个不含注释的新 PDF
  4. 提供下载功能

作者提供了一个在线示例:en.sotool.top/remove-annotations。

原文链接 ​

https://dev.to/sunshey/how-to-remove-annotations-from-pdf-in-the-browser-with-vue-3-and-pdf-lib-36p2