PDF 作为一种广泛使用的文件格式,已经成为了人们日常生活和工作中不可或缺的一部分。PDF 文件的解析和显示一直是前端开发者们需要面对的挑战。为了解决这个问题,诞生了多种PDF处理工具和库,其中 PDFObject.js 和 PDF.js 就是两款备受欢迎的解决方案,分别用于在不同的场景解决不同的问题。
背景
PDF.js 和 PDFObject 是两种不同的技术,用于在网页上嵌入和显示 PDF 文件。
PDF.js 是一个由 Mozilla 开发的 JavaScript 库,它允许你在浏览器中直接解析和渲染 PDF 文件,而不需要依赖于任何插件。
PDFObject 则是一个轻量级的 JavaScript 插件,它提供了一种简单的方式来在网页上嵌入 PDF 文件,使用浏览器内置的 PDF 查看器扩展插件来显示 PDF 文件。
PDFObject.js
PDFObject 是一款个人开源的,百行代码实现的一个轻量级 JS 库,使用上非常方便,可自定义范围小,简单作为一个 PDF 阅读器已是足够。简单一点的使用场景,通过以下内容即可实现一个 PDF 文件的预览。
<div id="my-PDF"></div>
<script src="https://unpkg.com/PDFObject"></script>
<script>PDFObject.embed("/path/to/file.PDF", "#my-PDF");</script>
使用
它并不对 PDF 文件做任何的解析,主要利用了浏览器的内置插件,如谷歌浏览器上的 PDFium(FoxIt PDF Reader的一个分支),结合 <embed>,显示 PDF 文件的内容。随着时间的推移,由于大多数浏览器已经弃用并取消了对浏览器插件的支持,为了避免受到 <embed> 的不稳定支持的影响,在2024年2月,PDFObject 删除了 <embed> 的使用并替换成了更加稳定支持的 <iframe>。
<embed>方式
<iframe>方式
兼容
虽然大多数浏览器已经取消了对浏览器插件的支持,但 PDF 的预览依旧依赖着浏览器的内置插件。除个别如 edge 等仍旧支持第三方扩展插件的浏览器还可以使用 ActiveX 等三方插件作为 PDF 的阅读器之外,PDFObject 的兼容性主要取决于 window.navigator.PDFViewerEnabled (即内置PDF阅读插件)的支持。
PDFObject 预览器在浏览器下的功能展现如下:
可配置
除了部分参数可控制上图中的某些模块或者功能的展示之外,无法对PDF 资源进行特殊的定制。
各大浏览器内置的插件支持的参数有些差异,下面包含 Adobe Reader 和 PDFium 都支持的参数:
| nameddest=标题名 | 指定 PDF 文档中的命名目标。 | |
|---|---|---|
| page=页数 | 跳转到指定页。文档的第一页的pagenum值为1 | |
| zoom=scale zoom=scale,left,top | 使用浮点或整数值设置缩放和滚动。例如,比例值100表示缩放值为100%。“向左滚动”和“向上滚动”值位于坐标系中,其中0,0表示可见页面的左上角。 | |
| pagemode=bookmarkspagemode=thumbspagemode=none (default) | 显示书签或缩略图 | |
| scrollbar=1 | 0 | 打开或关闭滚动条 |
| toolbar=1 | 0 | 打开或关闭工具栏 |
| statusbar=1 | 0 | 打开或关闭状态栏 |
| navpanes=1 | 0 | 打开或关闭导航窗格和选项卡 |
更加详细的参数配置可查看 Adobe Reader ( PDFObject.com/PDF/PDF\\_o… ) 和 PDFium( kb.foxit.com/hc/en-us/ar… )官方具体介绍。
已知上述参数,若想要关闭预览器中的工具栏和选项卡,可通过以下方式实现(等同于在原生浏览器地址栏直接输入: example.com/path/to/fil… )
<script>
PDFObject.embed(
"http://example.com/path/to/file.PDF",
"#my-PDF",
{ toolbar: 0, navpanes: 0}
);
</script>
PDFObject 的实现很简单,只要浏览器内置有相关的插件或者支持第三方 ActiveX 等 PDF 阅读器插件,结合<embed> 或 <iframe> 即可实现。
通过以上的介绍,可以知道 PDFObject 方式的 PDF 阅读器不支持很复杂的交互行为,但它也有自己的优势:因为它依赖于浏览器的内置插件,而内置插件通常是为了优化性能和资源消耗而设计的。
PDF预览的内置插件(如Adobe Reader 和 PDFium)利用操作系统提供的PDF渲染引擎和硬件加速功能,可能会涉及到一些服务器端处理,使用更高效的方法来渲染PDF,提供更好的性能,减少资源消耗,从而为用户提供了更流畅的阅读体验。
PDF.js
PDF.js是一款由 Mozilla 团队开发的,基于 JavaScript 的开源 PDF 阅读器库,它提供了在浏览器中展示和解码处理 PDF 文档的方式,适用于需要在Web应用程序中嵌入功能较为丰富的 PDF 阅读器或需要解码 PDF 文档的场景。
PDF.js 中包含了阅读器和解码core,而其阅读器也是通过它的解码器,将 PDF 文件资源进行解码、序列化,转换成对应的HTML5 元素内容(如canvas、text等元素)实现的,因此具有丰富而强大的自定义功能。
阅读器
当纯粹的只是使用 PDF.js 的阅读器时,可通过将 PDF.js 的阅读器拷贝到项目中或者部署到服务上进行使用,下方 viewer.html 则为阅读器的入口文件:
showPDF (selector, options) {
// iframe 访问
const { width, height, fileUrl } = options;
this.PDFFrame = document.createElement('iframe');
this.PDFFrame.width = width;
this.PDFFrame.height = height;
this.PDFFrame.src = `./web/viewer.html?file=${encodeURIComponent(fileUrl)}`;
document.getElementById(selector).append(this.PDFFrame);
// 或者可以直接进行跳转访问
window.location.href = `./web/viewer.html?file=${encodeURIComponent(fileUrl)}`;
}
解码器
PDF.js 除了提供已经设计好的阅读器之外,还提供了 PDF 文件解码功能,以供开发者能够深度定制自己的 PDF 阅读器。
编码器主要通过网络请求获取到文件流stream,通过解码stream获取到PDF文件信息和页面信息,包括文件标题,页面数量,每一页的内容如图片、文字等内容的信息。在绘制页面内容时,将解码内容的arrayBuffer通过编码成图片或文字及其相关信息,绘制到canvas中。
除了将内容绘制到 canvas 中之外,还可以将编解码后的文字内容,序列化成dom元素 textLayer 中,覆盖在 canvas 之上。为了避免文字的重叠,一般textLayer 的文字字体颜色都是透明的,主要用于选择文字等交互上使用。
除了与dom相关的绘制工作,解码逻辑全部使用了worker来实现,来提高解码的效率。
部分渲染功能只在 node 环境下支持,在浏览器下是不支持的,如渲染模块的硬件加速部分。
如何选择
从兼容性看
- PDF.js 拥有更加广泛的适用性,它支持最新版本的 Chrome、Firefox、Safari、Edge 等主流浏览器,同时也对旧版浏览器进行了适当的优化。这使得 PDF.js 在各种网络环境中都能保持稳定的性能,为用户提供良好的阅读体验。
- PDFObject.js 的兼容性取决于浏览器内置的 PDF 查看器。目前大部分移动设备的浏览器都有内置的PDF查看器,但较低版本的浏览器也支持使用第三方PDF查看器插件。
从性能上看
- PDF.js 是一个客户端解决方案,它将PDF文件的解析和渲染工作放在用户的浏览器中完成,依赖用户的设备性能。在移动设备上,这可能会导致较慢的加载时间和较高的 CPU 使用率,尤其是在处理大型或复杂的 PDF 文件时。
- PDFObject.js 里用的是内置的 PDF 查看器或者是系统的插件,能够直接利用操作系统的硬件加速功能,依赖客户端的硬件,这可能会提供更好的性能和更快的加载时间。
从功能和交互性需求上看
- PDF.js 提供了一个完整的PDF查看器,且可以自定义和扩展。
- PDFObject.js 只提供了基本的PDF查看功能。
| 兼容性 | 性能 | 资源加载 | 功能扩展 | 成本 | |
|---|---|---|---|---|---|
| PDF.js | 不支持IE ✅ | 依赖设备性能大文件不友好 | 不支持跨域资源 支持文件流 | 支持高度自定义和扩展 ✅ | 扩展和优化成本高 |
| PDFObject.js | 取决于PDF插件的兼容 | 依赖设备硬件性能更好✅ | 内嵌时不支持跨域资源 不支持文件流 | 基本的 PDF 查看功能,不支持扩展 | 不支持扩展和优化 |
总结
在不同的场景下,对 PDF 阅读器的需求也不一样。选择哪种方案取决于项目需求、用户体验、性能要求和开发资源。当需要复杂功能和自定义,如金融场景下比较常见的阅读进度监听、预览状态变更、协议签订等场景,PDF.js可能是更好的选择。当只需要基本的 PDF 查看功能,且希望快速实现,PDFObject.js 可能更适合。