使用Javascript从div中的HTML生成pdf

时间:2013-08-12 16:18:32

标签: javascript jspdf

我有以下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为&#34; pdf&#34;的内容。这必须使用JavaScript完成。 &#34; pdf&#34;然后应该使用&#34; foobar.pdf&#34;

的文件名自动下载文档

我一直在使用jspdf执行此操作,但它唯一的功能是&#34; text&#34;它只接受字符串值。我想将HTML提交给jspdf,而不是文本。

15 个答案:

答案 0 :(得分:178)

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
  3. 如果要忽略某些元素,则必须使用ID标记它们,然后可以在jsPDF的特殊元素处理程序中忽略该ID。因此,您的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中打开创建的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”完成,但并不意味着所有jQuery选择器都受支持。

    因此用“.ignorePDF”等类选择器替换'#ignorePDF'对我来说不起作用。相反,您必须为每个要忽略的元素添加相同的处理程序,如:

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

    examples开始,还可以选择“a”或“li”等标签。对于大多数用例来说,这可能有点无限制:

      

    我们支持特殊元素处理程序。用jQuery样式注册它们   ID或节点名称的ID选择器。 (“#iAmID”,“div”,“span”等)   不支持任何其他类型的选择器(class,of   化合物)此时。

    要添加的一件非常重要的事情是您丢失了所有的样式信息(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>
    

答案 1 :(得分:36)

这是一个简单的解决方案。这适用于我。您可以使用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>

答案 2 :(得分:13)

您可以使用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
}

答案 3 :(得分:8)

如上所述,您应该使用jsPDFhtml2canvas。我还在jsPDF的问题中找到了一个函数,它将你的pdf自动分成多个页面(sources

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');
    }
  });
}

答案 4 :(得分:4)

如果你需要下载特定页面的pdf,只需添加这样的按钮

<h4 onclick="window.print();"> Print </h4>

使用window.print()打印所有页面而不仅仅是div

答案 5 :(得分:2)

如果要导出表格,可以查看Shield UI网格小部件提供的this export sample

通过扩展这样的配置来完成:

...
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" }
            ]
        }
    }
}
...

答案 6 :(得分:1)

我能够让jsPDF从div打印动态创建的表。

$(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>

答案 7 :(得分:1)

使用pdfMake.jsthis Gist

(我找到了要点here以及指向软件包html-to-pdfmake的链接,但最终我暂时不使用它。)

npm install pdfmake并将要点保存在htmlToPdf.js之后,我这样使用它:

const pdfMakeX = require('pdfmake/build/pdfmake.js');
const pdfFontsX = require('pdfmake-unicode/dist/pdfmake-unicode.js');
pdfMakeX.vfs = pdfFontsX.pdfMake.vfs;
import * as pdfMake from 'pdfmake/build/pdfmake';
import htmlToPdf from './htmlToPdf.js';

var docDef = htmlToPdf(`<b>Sample</b>`);
pdfMake.createPdf({content:docDef}).download('sample.pdf');

备注:

  • 我的用例是从降价文档(使用markdown-it)创建相关的html,然后生成pdf,然后上传其二进制内容(可以通过pdfMake的{​​{ 1}}函数),全部来自浏览器。相对于我尝试过的其他解决方案,这种html生成的pdf更好。
  • 我不满意从getBuffer()中得到的结果,因为该解决方案很容易与HTML中的特殊字符混淆,这些特殊字符显然被解释为一种标记,并且完全弄乱了结果PDF。
  • 使用基于画布的解决方案(例如不建议使用的jsPDF.fromHTML()函数,不要与接受的答案相混淆)对我来说不是一种选择,因为我希望生成的PDF中的文本可粘贴。基于画布的解决方案会生成基于位图的PDF。
  • 直接降价到md-to-pdf之类的pdf转换器仅是服务器端的,对我而言不起作用。
  • 使用浏览器的打印功能对我不起作用,因为我不想显示生成的PDF,而是上载其二进制内容。

答案 8 :(得分:0)

要将div捕获为PDF,您可以使用https://grabz.it解决方案。它有一个简单灵活的JavaScript API,可以捕获单个HTML元素的内容,例如div或span

要实现它,您需要先获得app key and secretdownload(免费)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>

要捕获功能ID下的内容,您需要:

//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是CSS选择器,就像前面的示例一样。现在,当加载页面时,现在将在与脚本标记相同的位置创建图像屏幕截图,脚本标记将包含要素div的所有内容,而不包含任何其他内容。

您可以对div-screenshot机制进行其他配置和自定义,请查看here

答案 9 :(得分:0)

  • 没有依赖性,纯粹的JS

这为我服务多年了:

export default function printDiv({divId, title}) {
  let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150');

  mywindow.document.write(`<html><head><title>${title}</title>`);
  mywindow.document.write('</head><body >');
  mywindow.document.write(document.getElementById(divId).innerHTML);
  mywindow.document.write('</body></html>');

  mywindow.document.close(); // necessary for IE >= 10
  mywindow.focus(); // necessary for IE >= 10*/

  mywindow.print();
  mywindow.close();

  return true;
}

答案 10 :(得分:0)

我使用jspdf和html2canvase进行CSS渲染,并导出特定div的内容,因为这是我的代码

$(document).ready(function () {
    let btn=$('#c-oreder-preview');
    btn.text('download');
    btn.on('click',()=> {

        $('#c-invoice').modal('show');
        setTimeout(function () {
            html2canvas(document.querySelector("#c-print")).then(canvas => {
                //$("#previewBeforeDownload").html(canvas);
                var imgData = canvas.toDataURL("image/jpeg",1);
                var pdf = new jsPDF("p", "mm", "a4");
                var pageWidth = pdf.internal.pageSize.getWidth();
                var pageHeight = pdf.internal.pageSize.getHeight();
                var imageWidth = canvas.width;
                var imageHeight = canvas.height;

                var ratio = imageWidth/imageHeight >= pageWidth/pageHeight ? pageWidth/imageWidth : pageHeight/imageHeight;
                //pdf = new jsPDF(this.state.orientation, undefined, format);
                pdf.addImage(imgData, 'JPEG', 0, 0, imageWidth * ratio, imageHeight * ratio);
                pdf.save("invoice.pdf");
                //$("#previewBeforeDownload").hide();
                $('#c-invoice').modal('hide');
            });
        },500);

        });

});

答案 11 :(得分:0)

一种方法是使用window.print()函数。不需要任何库

专业人士

1。无需外部库。

2。我们也只能打印身体的选定部位。

3。没有CSS冲突和js问题。

4。核心html / js功能

---只需添加以下代码

CSS

@media print {
        body * {
            visibility: hidden; // part to hide at the time of print
            -webkit-print-color-adjust: exact !important; // not necessary use         
               if colors not visible
        }

        #printBtn {
            visibility: hidden !important; // To hide 
        }

        #page-wrapper * {
            visibility: visible; // Print only required part
            text-align: left;
            -webkit-print-color-adjust: exact !important;
        }
    }

JS代码-在btn点击上调用bewlow函数

$scope.printWindow = function () {
  window.print()
}

注意:在每个CSS对象中使用!important

示例-

.legend  {
  background: #9DD2E2 !important;
}

答案 12 :(得分:0)

这个例子很好用。

<button onclick="genPDF()">Generate PDF</button>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script>
    function genPDF() {
        var doc = new jsPDF();
        doc.text(20, 20, 'Hello world!');
        doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
        doc.addPage();
        doc.text(20, 20, 'Do you like that?');
    
        doc.save('Test.pdf');
    }
</script>

答案 13 :(得分:-1)

任何人都试试这个

    (function () {  
        var  
         form = $('.form'),  
         cache_width = form.width(),  
         a4 = [595.28, 841.89]; // for a4 size paper width and height  

        $('#create_pdf').on('click', function () {  
            $('body').scrollTop(0);  
            createPDF();  
        });  
        //create pdf  
        function createPDF() {  
            getCanvas().then(function (canvas) {  
                var  
                 img = canvas.toDataURL("image/png"),  
                 doc = new jsPDF({  
                     unit: 'px',  
                     format: 'a4'  
                 });  
                doc.addImage(img, 'JPEG', 20, 20);  
                doc.save('Bhavdip-html-to-pdf.pdf');  
                form.width(cache_width);  
            });  
        }  

        // create canvas object  
        function getCanvas() {  
            form.width((a4[0] * 1.33333) - 80).css('max-width', 'none');  
            return html2canvas(form, {  
                imageTimeout: 2000,  
                removeContainer: true  
            });  
        }  

    }());  

答案 14 :(得分:-2)

jsPDF已更新。这是正确的代码

  func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        guard let selectedImage = info[.originalImage] as? UIImage else {
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        }

        imageview.image = selectedImage

        dismiss(animated: true, completion: nil)
    }