純js實現html轉pdf


項目開發中遇到了一個變態需求,需要把一整個頁面導出為pdf格式,而且要保留頁面上的所有的表格、svg圖片和樣式。

簡而言之,就是希望像截圖一樣,把整個頁面截下來,然后保存成pdf。

咋不上天呢……

查了一下,能夠實現html轉pdf的方法還是挺多的,大概有以下幾種:

1、大部分瀏覽器就有這個功能。然而我們客戶要的可不是這個,人家要的是能夠在系統中主動觸發的導出為pdf功能,所以這種方案pass。

2、利用第三方工具。我找到了一種利用wkhtmltopdf這種工具來導出的方案,自己在我們的項目中試了一下,效果不好,而且對svg圖片的支持也不行。pass。

3、還有一種是利用iText類后台生成java文件。但因為需要導出的這個頁面是動態頁面,而且直接把頁面傳給后台會丟失大量樣式,所以還是pass。

最后沒什么好的辦法,只能退而求其次,想着要不先把html頁面轉成圖片,再把圖片導出為pdf。因為要支持用戶導出下載,而且要保留樣式,所以最好是純js前端實現。

html轉canvas的話,就用html2canvas這個js,這個網上介紹比較多了,這里就不廢話了。

比較麻煩的是svg圖片,直接用html2canvas無法把svg標簽的內容轉成canvas,最后查了一圈資料后,鎖定了canvg這個js。canvg是谷歌的一個插件,可以將svg標簽內容轉成canvas。具體到我們的項目,還有一個難點,就是如何把glyphicons這種字體圖標也轉成canvas,因為在不同瀏覽器下對這種字體圖標的支持是完全不一樣的。最后找到的方法是用char code來替換這些字體圖標,重新繪制成canvas。由canvas生成圖片不用廢話。由圖片生成pdf用jsPDF實現。 折騰了大半天,總算把整個流程打通了,接下來一步一步貼上代碼。

第一步:把對應dom節點里所有的svg元素替換成canvas

 1 svg2canvas: function(targetElem) {
2 var svgElem = targetElem.find('svg');
3 svgElem.each(function(index, node) {
4 var parentNode = node.parentNode;
5 //由於現在的IE不支持直接對svg標簽node取內容,所以需要在當前標簽外面套一層div,通過外層div的innerHTML屬性來獲取
6 var tempNode = document.createElement('div');
7 tempNode.appendChild(node);
8 var svg = tempNode.innerHTML;
9 var canvas = document.createElement('canvas');
10 //轉換
11 canvg(canvas, svg);
12 parentNode.appendChild(canvas);
13 });
14 }

第二步:把glyphicons字體轉成canvas。如果項目中沒有用到glyphicons字體圖標,可忽略這一步

 1 glyphicons2canvas: function(targetElem, fontClassName, fontFamilyName) {
2 var iconElems = targetElem.find('.' + fontClassName);
3 iconElems.each(function(index, inconNode) {
4 var fontSize = $(inconNode).css("font-size");
5 var iconColor = $(inconNode).css("color");
6 var styleContent = $(inconNode).attr('style');
7 //去掉"px"
8 fontSize = fontSize.replace("px", "");
9 var charCode = getCharCodeByGlyphiconsName(iconName);
10 var myCanvas = document.createElement('canvas');
11 //把canva寬高各增加2是為了顯示圖標完整
12 myCanvas.width = parseInt(fontSize) + 2;
13 myCanvas.height = parseInt(fontSize) + 2;
14 myCanvas.style = styleContent;
15 var ctx = myCanvas.getContext('2d');
16 //設置繪圖內容的顏色
17 ctx.fillStyle = iconColor;
18 //設置繪圖的字體大小以及font-family的名字
19 ctx.font = fontSize + 'px ' + fontFamilyName;
20 ctx.fillText(String.fromCharCode(charCode), 1, parseInt(fontSize) + 1);
21 $(inconNode).replaceWith(myCanvas);
22 });
23 }
24 //根據glyphicons/glyphicon圖標的類名獲取到對應的char code
25 getCharCodeByGlyphiconsName: function(iconName) {
26 switch (iconName) {
27 case("glyphicons-resize-full"):
28 return "0xE216";
29 case ("glyphicons-chevron-left"):
30 return "0xE225";
31 default:
32 return "";
33 }
34 }

第三步:html轉canvas轉圖片再轉pdf

 1 html2canvas($("#myExportArea"), {
2 onrendered: function(canvas) {
3 var imgData = canvas.toDataURL('image/jpeg');
4 var img = new Image();
5 img.src = imgData;
6 //根據圖片的尺寸設置pdf的規格,要在圖片加載成功時執行,之所以要*0.225是因為比例問題
7 img.onload = function() {
8 //此處需要注意,pdf橫置和豎置兩個屬性,需要根據寬高的比例來調整,不然會出現顯示不完全的問題
9 if (this.width > this.height) {
10 var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225]);
11 } else {
12 var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225]);
13 }
14 doc.addImage(imgData, 'jpeg', 0, 0, this.width * 0.225, this.height * 0.225);
15 //根據下載保存成不同的文件名
16 doc.save('report_pdf_' + new Date().getTime() + '.pdf');
17 }
18 },
19 background: "#fff",
20 //這里給生成的圖片默認背景,不然的話,如果你的html根節點沒設置背景的話,會用黑色填充。
21 allowTaint: true //避免一些不識別的圖片干擾,默認為false,遇到不識別的圖片干擾則會停止處理html2canvas
22 });

雖然最后勉強完成了客戶的要求,但是生成的pdf效果明顯不如正常截圖來的清晰……水平所限,暫時只能想到這種方法,如果大家有更好的辦法,歡迎指點。

一個簡單的demo:https://github.com/SuperNaturalGit/HtmlToPdf

使用方法:

使用Git克隆項目到本地:git clone https://github.com/SuperNaturalGit/HtmlToPdf.git

使用chrome瀏覽器打開index.html即可。其他瀏覽器的兼容性沒測試。

如果不用git,直接把幾個文件全部copy到本地,只要相對路徑沒問題,也可以運行的。

ps:評論里冷秋月同學對導出流程做了改良,可以解決閃爍以及背景的問題,大家可以參考。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



用JS實現HTML轉PDF java實現PDF轉HTML Java實現Html轉PDF html轉pdf的java實現 Java實現Html轉PDF Java實現Html轉PDF pdf2htmlEX實現pdf轉html pdf2htmlEX實現pdf轉html java實現轉html為pdf iText實現html轉pdf
 
粤ICP备14056181号  © 2014-2020 ITdaan.com