当前位置: 首页 > 工具软件 > jsPDF > 使用案例 >

jspdf+html2canvas生成pdf

宣高朗
2023-12-01

pc项目中有下载pdf的需求,内容是动态变化的,要求分页,加水印效果,各方面综合考虑以后要求前端实现

技术要点:jspdf+html2canvas

**原理:**利用html2canvas将html转成canvas,再利用canvas.toDataURL生成网路图片,然后用jspdf.addImage将图片画到pdf中

**难点:**图片的高度>一页pdf高度时,利用图片的偏移量来实现分页效果,详见代码

下面分别描述一下水印、分页等是如何实现的

水印效果
  1. 本地png格式的图片在线转成base64格式
  2. doc.addImage(‘图片地址’,‘图片格式’,x,y,‘图片宽度’,‘图片高度’)
分页效果
  1. html2canvas将html转成canvas(放大两倍,保证以后追加图片的清晰度)
  2. canvas.toDataURL(‘image/png’, 1.0)
  3. doc.addImage(‘图片地址’,‘图片格式’,x,y,‘图片宽度’,‘图片高度’)
  4. 每个页面添加图片的时候,其实用的是一张图,不同的是图片距离pdf顶部的距离,也就是图片的偏移来实现
pdf左右间距和上下间距的实现(图片高度>pdf每页高度)
  1. 左右间距直接在html中设置margin:0 100px;
  2. 上下间距,通过在每页pdf中添加白底的矩形遮盖多余内容的显示
文字链接
  1. 算好最后一页中剩余高度可容纳文字链接的个数、一整页pdf可容纳文字链接的个数,每一个文字链接距离顶部的位置
  2. 循环追加文字链接doc.textWithLink(‘超链接文本’,x,y,{url:‘超链接地址’})
问题
  1. 添加jpeg格式的图片是黑底的;解决办法:所有图片格式转成png
  2. 利用图片偏移实现分页,有时候会出现文字被裁切的问题;目前没有好的解决办法,是通过手动微调文字间距和偏移量实现的
  3. 文字链接乱码;解决办法:doc.setFont(‘simhei’),jspdf只支持英文字体,需要手动设置中文字体
  4. canvas默认白底,会覆盖水印;解决办法:html2canvas(‘html’,{scale:2,backgroundColor:‘rgba(255,255,255,0)’})
完整代码
function downPdf(html){
	//初始化jspdf实例
	const doc=new jsPDF()//a4 [552.28,841.89]
	doc.setFont('simhei')//设置中文字体,避免乱码
	//每页pdf宽高
	let pageWidth = doc.internal.pageSize.width
	let pageHeight = doc.internal.pageSize.height
	//html容器的宽高
	let contentWidth = html.clientWidth
	let contentHeight = html.clientHeight
	//图片的宽高
	let imgWidth=pageWidth
	let imgHeight=imgWidth*contentHeight/contentWidth
	//html-canvas-img
	let canvas=await html2canvas(html,{scale:2,backgroundColor:null})//设置null,背景是透明的,会跟水印有叠加的效果
	let pageData=canvas.toDataURL('image/png', 1.0)//1.0保证图片的清晰度
	let position=10
	if(imgHeight<pageHeight){
	    doc.addImage(pageData, 'PNG', 0, 10, imgWidth, imgHeight)
	}else{
	    let height=imgHeight//剩余图片高度
	    while(height>0){
	    	//设置每页的上下间距
	        doc.setFillColor(255,255,255);
	        doc.rect(0,0,pageWidth,10,'F')//头部白条
	        doc.rect(0,pageHeight-10,pageWidth,10,'F')//尾部白条
	        //画图
	        doc.addImage(pageData, 'PNG', 0, position, imgWidth, imgHeight)
	        height=height-(pageHeight-20)
	        position=position-(pageHeight-20)
	        if(height>0){//剩余图片高度大于每页pdf高度时,添加新页面(并添加水印)
	            doc.addPage()
	            this.addWaterMark(doc)
	        }else{
	            //每页26条链接
	            doc.setTextColor('#E02020')
	            let pos=10+(height+(pageHeight-20))+1//第一个文字链接距离顶部的距离(10头部白条高度,1距离图片下边缘的距离)
	            //计算剩余高度可容纳文字链接的个数
	            let sheng=pageHeight-pos
	            let num=Math.floor(sheng/14)
	            //开始画超链接	            
	            let newPos=15//新页面中第一个文字链接的位置           
	            let currentPge=1
	            //循环文字类链接列表
	            txts.forEach((item,index) => {
	                if(index<num){
	                    doc.textWithLink((index+1)+'、'+item.name,15,pos,{url:item.url})
	                    pos+=10
	                }else if(index%26===num){
	                    currentPge++
	                    doc.addPage()
	                    this.addWaterMark(doc)
	                    doc.textWithLink('txt',15,newPos,{url:''})
	                    newPos=25
	                }
	                else{
	                    doc.textWithLink('txt',15,newPos,{url:''})
	                    newPos+=10
	                }
	            })            
	            //保存下载
	            doc.save('test.pdf')
	        }
	    }
	}
}
 类似资料: