vue实现HTML转PDF (已解决清晰、页边距、图片跨域导出等问题)
作者:互联网
最近有需求做简历打印的功能,就又花时间研究了一下html转图片导出,里面牵扯到多页pdf导出时的分页和页边距问题,清晰度问题以及图片跨域问题等。我们一个一个来解决。
一、先说HTML转PDF的实现方法
1. 我们要先添加两个模块
第一个.将页面html转换成图片
npm install --save html2canvas
第二个.将图片生成pdf
npm install jspdf --save
2. 在utils文件夹下面创建一个htmlToPdf.js文件,写入如下代码:
// 页面导出为pdf格式
import html2Canvas from 'html2canvas'
import jsPDF from 'jspdf'
const htmlToPdf = {
getPdf(title,url) {
html2Canvas(document.querySelector('#pdfDom'), {
allowTaint: false,
taintTest: false,
logging: false,
useCORS: true,
dpi: window.devicePixelRatio*4, //将分辨率提高到特定的DPI 提高四倍
scale:4 //按比例增加分辨率
}).then(canvas=>{
var pdf = new jsPDF('p', 'mm', 'a4'); //A4纸,纵向
var ctx = canvas.getContext('2d'),
a4w = 190, a4h = 277, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
imgHeight = Math.floor(a4h * canvas.width / a4w), //按A4显示比例换算一页图像的像素高度
renderedHeight = 0;
while(renderedHeight < canvas.height) {
var page = document.createElement("canvas");
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight);//可能内容不足一页
//用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); //添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if(renderedHeight < canvas.height) {
pdf.addPage();//如果后面还有内容,添加一个空页
}
// delete page;
}
//保存文件
pdf.save(title + '.pdf')
})
}
};
export default htmlToPdf;
3. 在我们需要的页面使用我们定义的函数文件。
import html2canvas from "html2canvas";
4. 在执行下载的方法中调用html2canvas中的getPdf方法即可。
html
<div id="pdfDom">
// ... 需要打印的内容
</div>
<div class="preview-content-operateBtn">
<button class="previewBtn" @click="onClickDownLoad">下载PDF简历</button>
</div>
js
onClickDownLoad() {
htmlToPdf.getPdf('下载名称');
},
至此,我们的HTML转PDF的功能也就实现了。
但是在实现的过程中,我们会发现以下问题:
1. 因为实现的方法是先利用canvas转成图片,然后转pdf,所以会存在导出模糊的情况。
2. 导出的pdf页边距的问题。
3. 当要打印的区域存在跨域图片时,方法会报错。
问题已经找出来,接下来当然就是一个一个解决问题喽,哈哈。
问题1. 转pdf,所以会存在导出模糊的情况
解决的原理就是通过放大canvas转图片时的大小
dpi: window.devicePixelRatio*4, //将分辨率提高到特定的DPI 提高四倍
scale:4 //按比例增加分辨率
问题2. 导出的pdf页边距的问题
在图片转pdf的时候,提前把pdf的页边距留出来,再去计算图片的放置尺寸。
var pdf = new jsPDF('p', 'mm', 'a4'); //A4纸,纵向
var ctx = canvas.getContext('2d'),
a4w = 190, a4h = 277, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
imgHeight = Math.floor(a4h * canvas.width / a4w), //按A4显示比例换算一页图像的像素高度
renderedHeight = 0;
while(renderedHeight < canvas.height) {
var page = document.createElement("canvas");
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight);//可能内容不足一页
//用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); //添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if(renderedHeight < canvas.height) {
pdf.addPage();//如果后面还有内容,添加一个空页
}
// delete page;
}
问题3. 图片跨域
在解决图片跨域的过程中,我试过了网上的方法,说是还需要在跨域的服务器上配置一些参数,比较麻烦,还是前端自己解决吧。
然后尝试把图片转base64,之后,图片跨域问题完美解决,很是开心。还是要记得先为跨域的图片做下代理(图片地址:http://118.190.75.53/portal_pic/item/3de47b6bf40747d495728cf6441e4a62.jpg)
proxy: {
'/portal_pic': {
target: "http://118.190.75.53/"
},
},
this.getBase64Image(this.baseInfo.basic.interviewHead);
// 第一个参数是图片的URL地址,第二个是转换成base64地址后要赋值给的img标签
getBase64Image(url = "") {
if (!url) return;
let link = url;
link = link.split("118.190.75.53");
if (link.length > 1) link = link[1];
var that = this;
var image = new Image();
console.log(url, "url");
image.src = link + "?v=" + Math.random(); // 处理缓存
image.crossOrigin = "*"; // 支持跨域图片
image.onload = function() {
var base64 = that.drawBase64Image(image);
that.baseInfo.basic.interviewHead = base64;
console.log(that.baseInfo, that.baseInfo.basic);
};
},
drawBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataURL = canvas.toDataURL("image/png");
return dataURL;
},
好了,遇到的问题已经解决,功能实现,可以愉快的下载pdf文件了,哈哈!
(在此顺便记录一下实现转pdf的另一种简单的方式,window.print(),这种方法是通过调用网页上面的打印方法,缺点就是有些地方可能会打印不准确。)
标签:canvas,vue,跨域,renderedHeight,height,width,HTML,pdf,page 来源: https://blog.csdn.net/MICHAEL_PRINCE/article/details/118667848