canvas实现pdf的展示与生成pdf
前言
这里主要使用到了两个库,pdf的展示是开源库pdf.js,和canvas结合使用;生成pdf的开源库是jsPDF。
pdf展示的demo: http://121.4.85.237/
pdf.js
这个开源库很牛的,详细内容看官网就行了,我这里就简单的贴一些例子和pdf.js的两种使用方式。
官网:https://github.com/mozilla/pdf.js
这个pdf.js还是有一个官网demo的可以玩一下。
https://mozilla.github.io/pdf.js/web/viewer.html
我这里主要说一下两种使用方式,第一种是以npm的形式引入项目中,去进行生产;第二种是以构建包的形式扔到服务器上进行使用。
引入项目使用
引入的是pdf-dist npm包,此方式的缺点是官方demo中的工具栏
等一些东西是没有的,想要的话需要自己去实现。
安装:npm i pdfjs-dist
直接上只展示一页(此处是第一页)demo的核心代码
<canvas id="theCanvas" style="border: 1px solid black; direction: ltr;"></canvas>
const pdfjsLib = require("pdfjs-dist");
import ss from "pdfjs-dist/build/pdf.worker.entry";
const pdfPath = "helloworld.pdf"; // 此pdf要放在静态文件夹中
pdfjsLib.GlobalWorkerOptions.workerSrc = ss; // 这里使用好别扭,固定写法
mounted() {
const loadingTask = pdfjsLib.getDocument(pdfPath);
loadingTask.promise.then(function(pdfDocument) {
return pdfDocument.getPage(1).then(function(pdfPage) {
const viewport = pdfPage.getViewport({ scale: 1.5 }); // 我自己设的1.5倍
const canvas = document.getElementById("theCanvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
const ctx = canvas.getContext("2d");
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport,
});
return renderTask.promise;
})
}).catch(function(reason) {
console.log('error', reason)
})
}
还可以实现展示多页,不过我试了下,单页展示时的页面响应式还不错,多页时有点闪眼,我这里就把resize事件去掉了。
<canvas
v-for="item in totalPage"
:key="item"
:id="'theCanvas' + item"
class="canvas-box"
></canvas>
const that = this;
this.loadingTask = pdfjsLib.getDocument(pdfPath);
this.winW = document.documentElement.clientWidth;
this.loadingTask.promise
.then(function (pdfDocument) {
let nums = pdfDocument.numPages;
for (let i = 1; i <= numPages; i++) {
pdfDocument
.getPage(i)
.then(function (pdfPage) {
let viewport = pdfPage.getViewport({ scale: 1.5 });
let scale = (that.winW / viewport.width).toFixed(2);
let scaledViewport = pdfPage.getViewport({ scale });
const canvas = document.getElementById("theCanvas" + i);
canvas.width = scaledViewport.width;
canvas.height = scaledViewport.height;
const ctx = canvas.getContext("2d");
const renderTask = pdfPage.render({
canvasContext: ctx,
viewport: scaledViewport,
});
return renderTask.promise;
})
.catch((err) => {
console.log("errr", err);
});
}
})
.catch(function (reason) {
console.log("error", reason);
});
},
构建包
首先是拉代码进行构建包,不想自己构建就在官网下载构建包。
// 自己构建
git clone https://github.com/mozilla/pdf.js.git
cd pdf.js
npm install -g gulp-cli
npm install
gulp generic-legacy
// 或者官网直接下载构建包
https://mozilla.github.io/pdf.js/getting_started/#download
自己操作的构建包在build文件夹中,可将构建包抽出,运行web文件夹下的viewer.html,使用open with live server,会默认查看compressed.tracemonkey-pldi-09.pdf 。
默认查看的pdf是在viewer.js中做了配置:defaultUrl 属性。想查看其它pdf文档,需要将pdf放入web文件夹中,和compressed.tracemonkey-pldi-09.pdf同层级,并在浏览器中拼接file,类似于http://127.0.0.1:5500/web/viewer.html?file=helloworld.pdf
对于其它服务器的pdf文档,我没有试验,应该也是支持的,感觉也是在file后拼接url路径,可去看网上大佬文章进行学习。这里推荐几篇文章,讲了下后端返回流文件的处理
https://juejin.cn/post/6844903843088564238
https://juejin.cn/post/6988051826058723364
构建包的使用
我将构建包扔在我的服务器80端口上,写个简单的index.html,html里使用了iframe嵌套了一个,点击切换按钮展示另一个pdf,很好用。
简单代码如下:
<iframe
width="100%"
height="100%"
src="http://121.4.85.237/legacy/web/viewer.html"
></iframe>
>
let btn = document.getElementById("button");
btn.onclick = function () {
window.open(
"http://121.4.85.237/legacy/web/viewer.html?file=helloworld.pdf"
);
};
jsPDF
此开源库是将html元素导出为pdf文档,或者不根据元素自己new一个pdf文档出来,使用简单。
官方文档: http://raw.githack.com/MrRio/jsPDF/master/docs/index.html
安装: npm install jspdf --save
一些基础使用
import { jsPDF } from "jspdf";
const doc = new jsPDF(); // Default export is a4 paper
doc.text("Hello world!", 10, 10);
doc.addFont("MyFont.ttf", "MyFont", "normal");
doc.setFont("MyFont");
doc.setFontSize(40)
doc.save("a4.pdf");
导出为一页或多页pdf文档可参考这篇博客:
https://www.jianshu.com/p/651c40d565e4
此库的缺点很多,如有一点模糊感,分页时会造成文字或表格截断等。看网上的处理方式有自己拿捏css布局的,也有遍历节点做判断处理的。
我的建议是在简单场景下或者不需要分页时可以使用此库生成pdf,复杂场景下直接让后端去生成pdf,后端有更好的处理方式。
更多推荐
所有评论(0)