PDF.js 在 Vue 中的使用

1,209 阅读1分钟

PDF.js 提供了pdfjs-dist这个包,用于通过 npm 安装使用。这里使用 canvas 渲染 PDF。

官方示例:Examples (mozilla.github.io) ,但是官方示例并没有明确给出在 Vite 中如何加载pdf.worker.js。查阅 Vite 文档 功能 | Vite 官方中文文档 (vitejs.dev),发现 Vite 支持以 url 形式导入某个 js 文件。

<script setup lang="ts">
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
// 显式加载资源为一个 URL
import workerUrl from "pdfjs-dist/build/pdf.worker.js?url";

const route = useRoute();

const canvasContainer = ref<HTMLElement | null>(null);

onMounted(async () => {
  // 配置 workerSrc 为 pdf.worker.js 的地址,这一步是必须的
  GlobalWorkerOptions.workerSrc = workerUrl;
  // 从 url 中读取 pdf 文件的 url,也可以使用其他方式
  const file = route.query.file;
  if (!file || typeof file !== "string") throw new Error("file is null");
  const pdf = await getDocument(file).promise;
  if (!canvasContainer.value) throw new Error("canvasContainer is null");
  // 设置倍数为 2,我发现这样较为清晰。也可以调整为其他值。
  const scale = 2;
  // 开始循环解析每一页
  for (let i = 1; i <= pdf.numPages; i++) {
    const canvas = document.createElement("canvas");
    const page = await pdf.getPage(i);
    const viewport = page.getViewport({ scale });
    const context = canvas.getContext("2d");
    if (!context) throw new Error("context is null");
    // 指定 canvas 的尺寸为 pdf 的尺寸
    canvas.height = viewport.height;
    canvas.width = viewport.width;
    // 开始渲染
    await page.render({
      canvasContext: context,
      viewport: viewport,
    }).promise;
    // 把 canvas 加入到 DOM 里
    canvasContainer.value.appendChild(canvas);
  }
});
</script>

<template>
  <div ref="canvasContainer" class="canvas-container"></div>
</template>

<style scoped>
.canvas-container {
  width: 100%;
}
.canvas-container :deep(canvas) {
  width: 100%;
  display: block;
}
</style>

在本例中,我直接使用 canvas 节点来绘制每一页的 PDF,然而当文件的页数过大时,会在 DOM 中生成大量的 canvas 节点。这可能会导致性能问题。可选的解决方案是,在每页渲染完成后,将 canvas 中的内容转换为图片。