前端时间调研了一下js转pdf的一些方案,做个整理。
一开始考虑前端转还是后端转,后来想想前端可能做出来和看到的会更像一点,所以先考虑前端的方案。
首先通过google和ata等搜到jsPDF这个库,不过一开始看到例子都不是把html转成pdf。
后来看了它的一些文档,里面有个fromHTML方法,不过它不支持utf8,其github上有个issue,就我看到了有这几个workaround:
1和2看上去比较复杂,而且也没找到明确的从HTML转pdf的方法,所以直接尝试方案三,不过有兴趣也可以研究一下。查看了addHTML的文档和代码后,写了下面这个js:
var pdf = new jsPDF('p','pt','a4');
var element = $("body");
element = document.getElementsByClassName("span12")[0];//element.find('.span12');
console.log(element);
pdf.addHTML(element,{
format: 'png',
pagesplit: true,
rstz: true
},function() {
var string = pdf.output('datauristring');
pdf.save("abc.pdf");
$('.preview-pane').attr('src', string);
});
看上去它的原理就是先把当前页面通过html2canvas或者rasterizeHTML库转成图片,然后调用jsPDF的addimage来生成pdf。上述代码中rstz就是控制用html2canvas还是rasterizeHTML。 不过它主要问题是不会自动分页,要自动分页的话要加上pagesplit这个选项,但是会失真。
下面贴一些效果图:
### html2canvas + No pagesplit
### html2canvas + pagesplit
### rasterizeHTML + No pagesplit
### rasterizeHTML + pagesplit
可以看到html2canvas在分页时候会失真,rasterizeHTML表现良好。
不过在做我们这个demo的时候,我发现rasterizeHTML对那些复杂一点的css支持不是太友好,而且装起来也比较复杂,所以最后还是用了html2canvas。然后尝试绕过分页的bug, 最后通过多次调用addHTML来避免问题。代码如下:
var pdf = new jsPDF('p', 'pt', 'a4');
var header = document.getElementsByTagName('header')[0];
var options = { format: 'png' };
var ready = false;
var sections = [
document.getElementById('main-result'),
document.getElementById('deep-result'),
document.getElementById('other-result')
];
var cy = 120;
function makePDF(eles) {
pdf.addHTML(header, 0, 0, options,
function () {
addPage(eles);
});
}
function addPage(eles) {
if (!eles || eles.length <= 0) {
ready = true;
return;
}
var ele = eles[0];
pdf.addHTML(ele, 0, cy, options,
function () {
cy = 0;
if (eles.length > 1) {
pdf.addPage();
}
addPage(eles.slice(1));
});
}
makePDF(sections);
$('#onDownload').click(function () {
if (ready) {
pdf.save('def.pdf');
}
});
理论上我感觉通过查看它本身addhtml的源码是能解决分页问题的,不过由于时间和能力关系我还没法解决。如果有能解决的欢迎告诉我。
另外网上有个类似的方案也可以参考一下.
对于后端生成pdf, 理论上也是可行的,比如这里 和 这里 不过看上去都很复杂,不如前端生成的简单。
还有就是通过phantomjs, 因为时间关系也没好好研究。