第三类方案:
PDF 文件转化成图片进行展示
的兼容性最好,能同时在 PC 端和移动端预览,但由于是图片格式,所以选中 pdf 文件上的文件,更加无法继续宁操作。
因为我的个人博客尚未实现适配移动端,所以选择了第二类方案。
1.使用 HTML 标签
该类方法实现简单,但兼容性很差,慎重选择。
1.1 iframe 标签
HTML 内联框架元素 iframe 表示嵌套的 browsing context。它能够将另一个 HTML 页面嵌入到当前页面中。
iframe 标签的属性含义请参照 MDN
iframe 标签的兼容性请参照 Can I Use
iframe 标签实现方案代码如下所示:
<iframe src="./test.pdf" height="900px;" width="800px"></iframe>
1.2 embed 标签
HTML embed 元素将外部内容嵌入文档中的指定位置。此内容由外部应用程序或其他交互式内容源(如浏览器插件)提供。
embed 标签的属性含义请参照 MDN
embed 标签的兼容性请参照 Can I Use
embed 标签实现方案代码如下所示:
<embed src="./test.pdf" type="application/pdf" width="100%" height="100%" />
1.3 object 标签
HTML object 元素(或者称作 HTML 嵌入对象元素)表示引入一个外部资源,这个资源可能是一张图片,一个嵌入的浏览上下文,亦或是一个插件所使用的资源。
object 标签的属性含义请参照 MDN
object 标签的兼容性请参照 Can I Use
object 标签实现方案代码如下所示:
<object
data="./test.pdf"
type="application/pdf"
width="100%"
height="100%"
></object>
2.使用第三方插件
能实现实时预览 pdf 的插件还有许多种,但使用最多的是 PDF.js 与 PDFObject,所以本文只涉及这两个插件。
2.1 PDF.js
2.1.1 PDF.js 简介
PDF.js 是一款开源的 pdf 文档读取解析插件,可以实现在 html 下直接浏览 pdf 文档。
pdf.js 是基于Promise 对象而实现的,不了解的读者可以先去看看MDN 上的解释。
pdf.js 渲染 pdf 时底层还使用了Web Worker(这会导致我们无法直接在本地运行官网下载的 demo,得在服务器上运行,详情见注意点处),不了解的读者可以去看一下阮一峰老师关于 Web Worker 的文章。
PDF.js 主要分为 3 层:
显示层采用核心层,并公开更容易使用的 API 来呈现 pdf 和从文档中获取其他信息。
层级 | 对应文件 | 作用 |
---|
Core Layer(核心层) | pdf.worker.js | 核心层用于解析和解释二进制 PDF 文档,这一层是所有后续层的基础。一般我不会直接操作核心层,而是去操作由核心层封装的展示层,操作核心层的高级用法可去参照官网 |
Display Layer(展示层) | pdf.js | 显示层是对核心层进行了一个封装,从而得到更容易使用的 API,用来展示 pdf 或从文档中获取其他信息。 |
Viewer Layer(查看器层) | viewer.html+viewer.css+viewer.js | 查看器构建在显示层上,是 PDF 查看器的 UI。 |
更多的细节请参照官网
2.1.2 使用 PDF.js 具体步骤
该方法是以图片形式来展示 PDF 文档,所以不能选中文本或复制文本。
具体步骤如下:
首先 npm i pdfjs-dist 下载 pdf.js 的 Prebuilt 包
设置 PDFJS.GlobalWorkerOptions.workerSrc 的地址
通过 PDFJS.getDocument(pdf 文件的 url) 处理 pdf 数据,返回一个 PDFDocumentLoadingTask
通过 pdfDoc.getPage(i) 单独获取第 i 页的数据
创建一个 canvas 元素,并设置元素的画布属性
通过 page.render 方法,将数据渲染到画布上、
具体代码如下:
import * as PDFJS from "./build/pdf.js";
import pdfjsWorker from "./build/pdf.worker.js";
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const pdfUrl = "./test.pdf";
console.log(pdfUrl);
PDFJS.getDocument(pdfUrl).promise.then((pdfDoc) => {
const totalPages = pdfDoc.numPages;
const canvasContainer = document.getElementById("#canvasContainer");
for (let i = 1; i <= totalPages; i++) {
pdfDoc.getPage(i).then((page) => {
let scaledViewport = page.getViewport({ scale: 1.5 });
let canvas = document.createElement("canvas");
canvas.setAttribute("id", "the-canvas" + i);
canvas.height = scaledViewport.height;
canvas.width = scaledViewport.width;
let context = canvas.getContext("2d");
let renderContext = {
canvasContext: context,
viewport: scaledViewport,
page.render(renderContext).promise.then(() => {});
canvasContainer.appendChildren(canvas);
直接使用官方封装好的 viewer.html 来展示自己的 PDF 文档,该方法比较简单,不用去操作 API;而且功能比较齐全,还可复制 pdf 中的文本。
具体步骤如下: 1.去官网下载打包好的 Prebuilt 版本压缩包 2.将需要打开的 PDF 文档放到与 viewer.html 文档的同一目录下 3.新建一个 html 文件,使用 window.open 方法 或 iframe 标签 来打开 viewer.html,并使用 file 字段来传入 pdf 名字信息
该方法的更多详细信息可参照博文
具体代码如下:
<iframe
src="./web/viewer.html?file=test.pdf"
frameborder="0"
style="height: 800px; width: 100%"
></iframe>
<script type="text/javascript">
window.open("./web/viewer.html?file=test.pdf");
</script>
2.1.3 使用 PDF.js 的注意事项
这里的内容非常重要,可以避免踩坑。我就是在这浪费了足足两天的时间,最终才找到解决办法。
注意事项一:pdf.js 需要启动服务器才能运行,无法直接打开本地的文档
原因:因为 pdf.js 渲染 pdf 文档时使用了 Web Worker 技术,该 Web Worker 无法读取本地文件。可参见阮一峰老师关于 Web Worker 的文章
报错信息:Message: Missing PDF "file:///D:/%E6%A1%8C%E9%9D%A2/pdfjs/web/test.pdf"
解决办法:可通过 live-server 这个插件在本地启动服务器然后打开相应的 html 文件。
具体步骤:
npm i live-server 安装包
live-server 启动服务器 更多配置信息可参见此博客
打开相应的 html 文件
注意事项二:我们的电脑上不能安装 IDM(Internet Download Manager)这类软件或插件。
报错信息 : Unexpected server response (204) while retrieving PDF
原因:因为 IDM 会拦截可下载的资源,会导致页面无法预览。
解决办法:直接卸载或关闭相应的插件、软件;也可以对软件进行相应的设置。更多信息可参照博文
另外使用 pdf.js 打开发票等文件时可能会出现字体显示不全的 bug,可参照该博客解决 pdf.js 无法完全显示 pdf 文件内容的问题。
2.2 PDFObject
相对 pdf.js 来说,PDFObject 的使用非常简单。但在手机 webview 使用兼容性不太好。
PDFObject 2.0 不向后兼容 1.0 版本,针对现代浏览器设计,支持 Chrome, Firefox, Safari (OS X and iOS), IE 9-11, and MS Edge。
更多信息可参照官网地址,和该篇博客PDF 预览之 PDFObject.js 总结
使用步骤:
创建嵌入 PDF 的容器
告诉 PDFObject,插入的 PDF 文件路径,以及插入到哪个容器
可以选择使用 CSS 来指定视觉样式,包括维度、边框、边距等
<div id="pdf"></div>
<script src="library/pdfobject.js"></script>
<script>
PDFObject.embed("uploads/pdfs/dongxuemin.pdf", "#pdf");
</script>
<style>
.pdfobject-container {
height: 500px;
.pdfobject {
border: 1px solid #ccc;
</style>
另外还有许多第三方库可实现 pdf 预览,如:vue-pdf、jquery.media.js等等。
3.PDF 文件转化成图片进行展示
把 PDF 转换为图片也有很多控件处理,例如 Aspose.Pdf、Spire.Pdf、 pdfiumviewer 等等,不同的第三方类库使用的方法有所差异,不过思路都很类似。
由于转成图片将无法复制或选中 PDF 文档的文本,所以我没使用该方法,就没进行进一步研究。大家可去参照其他博客。
参考博课:
前端预览 PDF 文件(使用 PDFJS)
实现在线预览 PDF 的几种解决方案
PDFObject.js、jquerymedia.js、pdf.js 的对比
PDF 预览之 PDFObject.js 总结
这是我目前所了解的知识面中最好的解答,当然也有可能存在一定的误区。
所以如果对本文存在疑惑,可以在评论区留言,我会及时回复的,欢迎大家指出文中的错误观点。
最后码字不易,觉得有帮助的朋友点赞、收藏、关注走一波。