前端接入 pdfjs

您所在的位置:网站首页 pdfjs加载太慢 前端接入 pdfjs

前端接入 pdfjs

2023-07-02 19:45| 来源: 网络整理| 查看: 265

由于最终渲染页面属于自己定制的,所以这边通过直接引用 pdfjs-dist下的插件,只处理canvas 渲染部分,其他功能在此基础上自行定制,下面遇到的问题也是在使用插件进行 canvas 渲染时出现的问题

1、工程接入 pdfjs 时在安卓60版本下渲染失败,并报错

由于 pdfjs-dist 中语法偏高,如含有 ||= 等高级语法,所以在使用时,需要额外给pdfjs-dist进行 babel 再编译。

在webpack 中的rule下新增以下部分,需要注意使用"@babel/preset-env"时需要设置 modules 为 commonjs,否则默认 auto的情况编译出的代码是无法直接使用的

{ test: /.m?js$/, include: [ path.resolve("node_modules/pdfjs-dist/"), ], use: { loader: "babel-loader", options: { presets: [ [ require("@babel/preset-env"), { modules: "commonjs" } ] ], plugins: ["@babel/plugin-transform-runtime"] } } }, 2、node环境下部分机型使用 pdfjs 时无法渲染,如鸿蒙 p30

验证时发现使用时提示

structuredClone is not defined

发现 structuredClone 的兼容性更差,不知道为什么上面配置的 babel 降级怎么没有将这个语法给降了。

查看 github 官方 issue ,发现确实有这个问题,在使用时使用 pdfjs-dist/legacy/build下面对应的文件即可解决,官方文档中也有对应的说明。

然后我思考了一下,发现这个目录下是解决兼容问题,那么 问题1 是不是也能通过这个问题解决,然后验证了一下,发现真不能,有些语法仍需要做 babel 处理,如 Private class fields等高级语法仍在该版本插件下使用

3、node环境下使用 pdf.worker.js,无报错,也无渲染

由于在 node 环境下通过将 pdf.worker.js 设置为 pdfjs 的 GlobalWorkerOptions.workerSrc 无法生效,所以这里需要使用 pdf.worker.entry.js作为 workerSrc,对应 issue

此处注意使用的是 legacy下的还是 build下的需要与 pdfjs 引用的保持一致

4、体积问题

直接使用插件时体积较大,考虑到使用min版本时,pdf.work.entry 没有对应的min版本,查看源码如下:

(typeof window !== "undefined" ? window : {} ).pdfjsWorker = require("./pdf.worker.js");

那么我使用时是否直接按照上述方式调整,来降低 worker 的对应的体积呢,现象是能,整理数据发现,体积的增量几乎就在 worker 的体积上体现了

const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.min.js"); pdfjsLib.GlobalWorkerOptions.workerSrc = (typeof window !== "undefined" ? window : {} ).pdfjsWorker = require("pdfjs-dist/legacy/build/pdf.worker.min.js"); 原工程1119k接入build版本3538k+2419k接入 legacy 版本4035k+3916kworker min 版本worker 非 min 版本接入build min 版本2450k +1331k3657k +2538k接入 legacy min 版本2793k +1674k3735k +3616k

根据工程的兼容性和体积需求,目前考虑使用 接入 legacy 的 min 版本且 worker min 版本

5、跨域问题

当 pdfjs 加载远程pdf时,不免会出现 CORS 跨域的问题,3种解决方案,主要都是通过下载文件后再访问来解决

1、将 pdf 下载到本地,放到工程中进行本地引用,此方式不仅增加工程体积,还不灵活

2、将 pdf 下载到静态资源服务器上,在工程中访问静态资源服务器上的资源进行实现,此方式需要手动操作,比较低效

3、通过调用服务器接口由服务器进行资源下载,待下载完成后由服务器提供对应的资源的 ArrayBuffer 进行访问,此方式比较灵活

根据我们工程的现状, 选择了第三种方式

附录

其实好像大部分问题都能在官方说明里找到,只不过遇到的问题可能在文档里没有说那么细,但仔细查找下 issue 也是能找到对应的解决方案。

下面简单写个使用的例子吧

const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.min.js"); pdfjsLib.GlobalWorkerOptions.workerSrc = (typeof window !== "undefined" ? window : {} ).pdfjsWorker = require("pdfjs-dist/legacy/build/pdf.worker.min.js"); function init(data) { // data可以为url,也可以为服务端返回的 arrayBuffer 或服务端返回的 base64,前端转的 arrayBuffer try { const loadingTask = pdfjsLib.getDocument(data); this.pdf = await loadingTask.promise; this.pageNum = await this.pdf.numPages || 0; console.log('pageNum', this.pageNum) this.initCanvas(); this.renderPdf(1); } catch (err) { this.onError({ message: "pdf 文件加载失败", code: 1 }) } } function renderPdf(num = 1) { this.pdf.getPage(num).then((page) => { // 设置canvas相关的属性 const canvas = document.getElementById("pdfCanvas_" + num); const ctx = canvas.getContext("2d", { alpha: false }); const dpr = window.devicePixelRatio || 1; const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; const ratio = dpr / bsr; const viewport = page.getViewport({ scale: this.pdfScale * ratio }); // 设置缩放比率 const viewRatio = viewport.height / viewport.width; canvas.width = viewport.width * ratio; canvas.height = viewport.height * ratio; canvas.style.width = (this.container.clientWidth - 20) * this.pdfScale + "px"; canvas.style.height = (this.container.clientWidth - 20) * viewRatio * this.pdfScale + "px"; ctx.setTransform(ratio, 0, 0, ratio, 0, 0); const renderContext = { canvasContext: ctx, viewport: viewport }; // 数据渲染到canvas画布上 page.render(renderContext); if (this.pageNum > num) { setTimeout(() => { return this.renderPdf(num + 1); }); } }); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3