使用Javascript从HTML生成PDF格式

我有以下的HTML代码:

<!DOCTYPE html> <html> <body> <p>don't print this to pdf</p> <div id="pdf"> <p><font size="3" color="red">print this to pdf</font></p> </div> </body> </html> 

我想要做的就是打印到PDF格式的任何东西,在ID为“pdf”的div中find。 这必须使用JavaScript来完成。 然后应该自动下载“pdf”文件,文件名为“foobar.pdf”

我一直在使用jspdf来做到这一点,但它唯一的function是只接受string值的“文本”。 我想提交HTML到jspdf,而不是文本。

jsPDF能够使用插件。 为了使其能够打印HTML,你必须包括一些插件,因此必须做到以下几点:

  1. 转到https://github.com/MrRio/jsPDF并下载最新版本。;
  2. 在您的项目中包含以下脚本:
    • jspdf.js
    • jspdf.plugin.from_html.js
    • jspdf.plugin.split_text_to_size.js
    • jspdf.plugin.standard_fonts_metrics.js

如果你想忽略某些元素,你必须用一个ID标记它们,然后你可以在jsPDF的一个特殊的元素处理器中忽略它。 所以你的HTML应该看起来像这样:

 <!DOCTYPE html> <html> <body> <p id="ignorePDF">don't print this to pdf</p> <div> <p><font size="3" color="red">print this to pdf</font></p> </div> </body> </html> 

然后,您使用以下JavaScript代码在PopUp中打开创build的PDF:

 var doc = new jsPDF(); var elementHandler = { '#ignorePDF': function (element, renderer) { return true; } }; var source = window.document.getElementsByTagName("body")[0]; doc.fromHTML( source, 15, 15, { 'width': 180,'elementHandlers': elementHandler }); doc.output("dataurlnewwindow"); 

对我来说,这创造了一个不错的整洁的PDF只包括行“打印到PDF”。

请注意,特殊元素处理程序只处理当前版本中的ID,这也在GitHub Issue中进行了说明 。 它指出:

因为匹配是针对节点树中的每个元素完成的,我的愿望是尽可能快地完成。 在这种情况下,它意味着“仅匹配元素ID”元素ID仍然以jQuery样式“#id”完成,但并不意味着所有的jQueryselect器都被支持。

因此用像'.ignorePDF'这样的类select器replace'#ignorePDF'对我来说并不适用。 相反,你将不得不为每个你想要忽略的元素添加相同的处理器:

 var elementHandler = { '#ignoreElement': function (element, renderer) { return true; }, '#anotherIdToBeIgnored': function (element, renderer) { return true; } }; 

从这些例子中也可以看出,有可能select“a”或“li”这样的标签。 尽pipe如此,对于大多数用户来说,这可能有一点点不可限制:

我们支持特殊的元素处理程序。 注册他们与ID或节点名称的jQuery风格的IDselect器。 (“#iAmID”,“div”,“span”等)。目前还不支持任何其他types的select器(类,复合类)。

一个非常重要的补充是,你失去了所有的风格信息(CSS)。 幸运的是,jsPDF能够很好地格式化h1,h2,h3等,这对我来说已经足够了。 另外它只会在文本节点内打印文本,这意味着它不会打印textareas等的值。 例:

 <body> <ul> <!-- This is printed as the element contains a textnode --> <li>Print me!</li> </ul> <div> <!-- This is not printed because jsPDF doesn't deal with the value attribute --> <input type="textarea" value="Please print me, too!"> </div> </body> 

这是简单的解决scheme。 这适用于我。你可以使用JavaScript打印的概念,并简单地保存为PDF格式。

 <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script type="text/javascript"> $("#btnPrint").live("click", function () { var divContents = $("#dvContainer").html(); var printWindow = window.open('', '', 'height=400,width=800'); printWindow.document.write('<html><head><title>DIV Contents</title>'); printWindow.document.write('</head><body >'); printWindow.document.write(divContents); printWindow.document.write('</body></html>'); printWindow.document.close(); printWindow.print(); }); </script> </head> <body> <form id="form1"> <div id="dvContainer"> This content needs to be printed. </div> <input type="button" value="Print Div Contents" id="btnPrint" /> </form> </body> </html> 

您可以使用autoPrint()并将输出设置为'dataurlnewwindow',如下所示:

 function printPDF() { var printDoc = new jsPDF(); printDoc.fromHTML($('#pdf').get(0), 10, 10, {'width': 180}); printDoc.autoPrint(); printDoc.output("dataurlnewwindow"); // this opens a new popup, after this the PDF opens the print window view but there are browser inconsistencies with how this is handled } 

如果你想导出一个表格,你可以看看Shield UI Grid Widget提供的这个导出样例 。

这是通过扩展像这样的configuration来完成的:

 ... exportOptions: { proxy: "/filesaver/save", pdf: { fileName: "shieldui-export", author: "John Smith", dataSource: { data: gridData }, readDataSource: true, header: { cells: [ { field: "id", title: "ID", width: 50 }, { field: "name", title: "Person Name", width: 100 }, { field: "company", title: "Company Name", width: 100 }, { field: "email", title: "Email Address" } ] } } } ... 

如前所述,你应该使用jsPDF和html2canvas 。 我还发现了一个函数,它将你的pdf自动分割成多个页面( 源代码 )

 function makePDF() { var quotes = document.getElementById('container-fluid'); html2canvas(quotes, { onrendered: function(canvas) { //! MAKE YOUR PDF var pdf = new jsPDF('p', 'pt', 'letter'); for (var i = 0; i <= quotes.clientHeight/980; i++) { //! This is all just html2canvas stuff var srcImg = canvas; var sX = 0; var sY = 980*i; // start 980 pixels down for every new page var sWidth = 900; var sHeight = 980; var dX = 0; var dY = 0; var dWidth = 900; var dHeight = 980; window.onePageCanvas = document.createElement("canvas"); onePageCanvas.setAttribute('width', 900); onePageCanvas.setAttribute('height', 980); var ctx = onePageCanvas.getContext('2d'); // details on this usage of this function: // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight); // document.body.appendChild(canvas); var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0); var width = onePageCanvas.width; var height = onePageCanvas.clientHeight; //! If we're on anything other than the first page, // add another page if (i > 0) { pdf.addPage(612, 791); //8.5" x 11" in pts (in*72) } //! now we declare that we're working on that page pdf.setPage(i+1); //! now we add content to that page! pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width*.62), (height*.62)); } //! after the for loop is finished running, we save the pdf. pdf.save('test.pdf'); } }); } 

要将div捕获为PDF,您可以使用https://grabz.it解决scheme。; 它有一个简单而灵活的JavaScript API,可以让您捕捉单个HTML元素(如div或跨度)的内容

为了实现它,你需要先获得一个应用程序密钥和秘密,并下载 (免费)的SDK。

现在是一个例子。

假设你有HTML:

 <div id="features"> <h4>Acme Camera</h4> <label>Price</label>$399<br /> <label>Rating</label>4.5 out of 5 </div> <p>Cras ut velit sed purus porttitor aliquam. Nulla tristique magna ac libero tempor, ac vestibulum felisvulput ate. Nam ut velit eget risus porttitor tristique at ac diam. Sed nisi risus, rutrum a metus suscipit, euismod tristique nulla. Etiam venenatis rutrum risus at blandit. In hac habitasse platea dictumst. Suspendisse potenti. Phasellus eget vehicula felis.</p> 

要捕捉functionID下的内容,您需要:

 //add the sdk <script type="text/javascript" src="grabzit.min.js"></script> <script type="text/javascript"> //login with your key and secret. GrabzIt("KEY", "SECRET").ConvertURL("http://www.example.com/my-page.html", {"target": "#features", "format": "pdf"}).Create(); </script> 

请注意target: #feature#feature是你的CSSselect器,就像前面的例子。 现在,当页面加载时,图像截图现在将在脚本标签的相同位置创build,其中将包含functiondiv的所有内容,而不包含其他内容。

您可以对div-screenshot机制进行其他configuration和定制,请在这里查看

我能够让jsPDF从一个divdynamic创build表格。

 $(document).ready(function() { $("#pdfDiv").click(function() { var pdf = new jsPDF('p','pt','letter'); var specialElementHandlers = { '#rentalListCan': function (element, renderer) { return true; } }; pdf.addHTML($('#rentalListCan').first(), function() { pdf.save("caravan.pdf"); }); }); }); 

与Chrome和Firefox一起使用效果非常好…格式化全部在IE中被炸毁。

我还包括这些:

 <script src="js/jspdf.js"></script> <script src="js/jspdf.plugin.from_html.js"></script> <script src="js/jspdf.plugin.addhtml.js"></script> <script src="//mrrio.github.io/jsPDF/dist/jspdf.debug.js"></script> <script src="http://html2canvas.hertzen.com/build/html2canvas.js"></script> <script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script> <script type="text/javascript" src="./libs/Blob.js/Blob.js"></script> <script type="text/javascript" src="./libs/deflate.js"></script> <script type="text/javascript" src="./libs/adler32cs.js/adler32cs.js"></script> <script type="text/javascript" src="js/jspdf.plugin.addimage.js"></script> <script type="text/javascript" src="js/jspdf.plugin.sillysvgrenderer.js"></script> <script type="text/javascript" src="js/jspdf.plugin.split_text_to_size.js"></script> <script type="text/javascript" src="js/jspdf.plugin.standard_fonts_metrics.js"></script>