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(可以搜索图片转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(),这种方法是通过调用网页上面的打印方法,缺点就是有些地方可能会打印不准确。)

  • 19
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 49
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inticaler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值