背景
昨天产品经理找我,说现在下载简历的功能,下载到的简历和ui的不一样,希望做成一样的。我的第一反应就是说那我们给后端写个静态页面,后端把相应的字段套进去吧。产品又说,每个渠道的简历的样式都不一样,不节能每个渠道都有对应的一个简历的静态页面,这样太复杂。希望通过前端下载,即前端直接保存简历预览页到本地。其实,一开始我是拒绝的,但是最后想想,写这么多静态页面也麻烦,索性就尝试尝试来解决这个问题吧。
初定技术方案
拿到这个需求之后,在网上查找了相关的资料。初步有两个方案。
- 通过
html2canvas
生成图片,然后再利用 jsPDF
将图片导入pdf并保存。
- 通过
html2canvas
生成图片,使用 FileSaver
将图片导入保存文件 。
对比了一下这两种技术方案,应该都能满足使用。
并且从浏览器兼容性的角度去看,方案一使用到ArrayBuffer这个类,方案二使用到Bolb类,都只能兼容到ie10。然后由于我们这个的需求为保存PDF文件,所以我就选了 jsPDF
这个库作为该方案的解决方案,感觉它专门针对pdf的,显得更专业点。
小试牛刀
确定了技术方案,那就按照定好的技术方案来执行,根据官方给的demo先写一段代码实现一下基础功能,看效果如何,代码如下:
import html2canvas from "html2canvas";
import * as jsPDF from "jspdf";
html2canvas(dom).then(canvas => {
var imgData = canvas.toDataURL('image/jpeg');
var doc = new jsPDF("p", "mm", "a4");
doc.addImage(imgData, 'JPEG', 0, 0,210,297);
doc.save(pdfName + ".pdf");
})
这段代码很简单,相信大家也都能看懂。试了一下,确实能生成对应名称的文件名。打开文件一看,感觉有点模糊。。。客户下载简历是需要投递给hr的,那可不能模糊啊。这个问题需要解决,一定要解决的!!!
解决pdf模糊的问题
上文中也提到了,代码很简单,模糊无非就两种情况嘛,一种canvas到的图片模糊,另外一种是保存pdf的时候模糊了。那我们就一步步试验排除一下吧。然后把图片的 DOMString
打印一下,放到浏览器看一下,发现图片有点模糊,那么问题定位到了,就想办法解决吧。
首先,我想到了 canvas.toDataURL
的api有一个默认图片质量的参数,如果不填,则是0.92。之前写过一篇压缩上传的图片就是通过这个参数压缩的。那就把它改成1吧。该api的详细文档,参见 文档 。再到浏览器里看看图片,发现有点效果,但是还是模糊。当然,这个也可能是我的肉眼的问题。还得继续解决啊。
然后在官方github上找到了一个关于清晰度的pr,连接如下: 我是修改清晰度pr , 增加了scale和dpi参数,可以设置画布的dpi,canvas默认的dpi是96dpi,scale默认为1。当两者同时存在时,以scale为主,会忽略dpi。
清晰度的问题解决了,那么是不是大功告成了呢?开始我也这样认为的,并且也测试着下载了几个简历,完美!但是,我发现当简历数据内容很多的时候,下载的pdf字体被压扁了。我简单了分析了一下,怀疑是图片太高,插入一页pdf,如果图片的高度大于pdf的高度,是不是会强行的把图片压缩成pdf的高度呢?那怎么办呢?我们可不可以给pdf做个分页呢?
分页解决字体压扁问题
既然想到了用分页,那么就搜索了一下jsPDF分页的内容。发现它有一个 addPage
的函数,那就简单了。我们可以计算出canvas的高度,已知a4纸的高度,如果大于,就需要分页,使用addPage函数。这里也是有两种解决方案,当然,这两个方案都不是我自己写的,哈哈哈。
方案一
该方案使用的关键技术就是canvas的 drawImage
api,把一个长图按照pdf的高度截取出好多个短图,然后插入对应的页面。这个原作者写的博客,使用到了递归。原博客 ,作者已经把代码帖进去了,我看了一下,然后使用了一下发现是可以用的。
方案二
方案二使用的关键技术是jsPDF的 addImage
的页面偏移的位置和jsPD超出内容不显示的特性。其实理解起来也很简单,第一页我插入canvas的偏移位置为0,第二页偏移位置就是一个a4纸的高度,第三页就是两个a4纸的高度,以此类推。原博客 ,作者已经把代码帖进去了,我看了一下,然后使用了一下发现是可以用的。
当时我还想,同时插入这么多canvas会不会使pdf文件的体积变大,后来看了看,测试下来,发现并不会,那个人推荐第二种方案,因为代码少,好理解。看方案一的代码,也看了一会儿才看明白,哈哈。
好了,写到这里,基本上使用javascript把html转成pdf下载就写完了,最后还是要感谢上文中提到的连接。
本人博客地址, 最近搞了一个非常简单的工时管理小程序,大佬们可以提提建议。