How do I get a multi-page pdf from a website using jsPDF and HTML2Canvas?

前端 未结 5 1936
生来不讨喜
生来不讨喜 2021-02-19 05:03

I have a script that uses HTML2Canvas to take a screenshot of a div within the page, and then converts it to a pdf using jsPDF.

The problem is the pdf that

相关标签:
5条回答
  • 2021-02-19 05:36

    you can use page split option of addhtml like this:

    var options = {
        background: '#fff',
        pagesplit: true
    };
    
    var doc = new jsPDF(orientation, 'mm', pagelayout);
    doc.addHTML(source, 0, 0, options, function () {
            doc.save(filename + ".pdf");
            HideLoader();`enter code here`
    });
    

    Note: This will break the html on multiple pages but these pages will get stretched. Stretching is a issue in addhtml till now and i am still not able to find on internet how to solve this issue.

    0 讨论(0)
  • 2021-02-19 05:40

    This is my aproach, also with jspdf and html2canvas which did a very good job for me:

    I am using a wrapper node which holds the content to be converted to pdf:

    <div id="main-content">
        <!-- the content goes here -->
    </div>
    <!-- and a button somewhere in the dom -->
     <a href="javascript:genPDF()">
         <i class="far fa-file-pdf"></i> &nbsp; Download PDF
     </a>
    

    This is the JS integration ( I only checked this versions ) and call:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js"></script>
    <script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
    <script type="text/javascript">
    
        const documentSlug = "some Slug";
        const documentTitle ="Some Title";
    
        function genPDF(){
            let html2pdf = new pdfView();
            html2pdf.generate();
        }
    </script>
    

    And here you can see the pdf generation. I encapsulated the generation part in an extra js object (you need to include this file also):

    //assuming jquery is in use
    
    let pdfView = function(){
        //assuming documentSlug is a constant set earlier 
        this.documentSlug = documentSlug;
        //assuming documentTitle is a constant set earlier
        this.documentTitle = documentTitle;
    
        //in this html node the part which shall be converted to pdf
        this.nodeId = "main-content";
    };
    
    pdfView.prototype.generate = function(){
        let self = this;
        this.prepareDocumentToPrint();
    
        //variables
        let HTML_Width = $("#"+self.nodeId).width();
        let HTML_Height = $("#"+self.nodeId).height();
        let top_left_margin = 15;
        let PDF_Width = HTML_Width+(top_left_margin*2);
        let PDF_Height = (PDF_Width*1.5)+(top_left_margin*2);
    
        this.pdfWidth = PDF_Width;
        this.pdfHeight = PDF_Height;
    
        let canvas_image_width = HTML_Width;
        let canvas_image_height = HTML_Height;
    
        let totalPDFPages = Math.ceil(HTML_Height/PDF_Height)-1;
    
        html2canvas($("#"+self.nodeId)[0],{allowTaint:true, scale: 2}).then(function(canvas) {
            canvas.getContext('2d');
    
            //console.log(canvas.height+"  "+canvas.width);
    
            let imgData = canvas.toDataURL("image/jpeg", 1.0);
            let pdf = new jsPDF('p', 'mm',  [PDF_Width, PDF_Height]);
            pdf.addImage(imgData, 'JPG', top_left_margin, top_left_margin,canvas_image_width,canvas_image_height);
    
            pdf = self.addPdfHeader(pdf);
            pdf = self.addPdfFooter(pdf, 1);
    
            for (let i = 1; i <= totalPDFPages; i++) {
                pdf.addPage(PDF_Width, PDF_Height);
    
                pdf.addImage(imgData, 'JPG', top_left_margin, -(PDF_Height*i)+(top_left_margin*4) + top_left_margin,canvas_image_width,canvas_image_height);
    
                pdf = self.addPdfHeader(pdf);
                pdf = self.addPdfFooter(pdf, (i+1));
            }
    
            pdf.save(self.documentSlug+".pdf");
    
            self.resetDocumentAfterPrint();
    
        });
    };
    
    //this one sets a fixed viewport, to be able to 
    //get the same pdf also on a mobile device. I also
    //have a css file, which holds the rules for the 
    //document if the body has the .printview class added
    pdfView.prototype.prepareDocumentToPrint = function(){
        let viewport = document.querySelector("meta[name=viewport]");
        viewport.setAttribute('content', 'width=1280, initial-scale=0.1');
        $('body').addClass("printview");
        window.scrollTo(0,0);
    };
    
    pdfView.prototype.addPdfHeader = function(pdf){
    
        pdf.setFillColor(255,255,255);
        pdf.rect(0, 0, this.pdfWidth, 40, "F");
    
        pdf.setFontSize(40);
        pdf.text("Document: "+this.documentTitle+" - Example Lmtd. Inc. (Whatsoever)", 50, 22);
    
        return pdf;
    };
    
    pdfView.prototype.addPdfFooter = function(pdf, pageNumber){
    
        pdf.setFillColor(255,255,255);
        pdf.rect(0, pdf.internal.pageSize.height - 40, this.pdfWidth, this.pdfHeight, "F");
    
        pdf.setFontSize(40);
        pdf.text("Seite "+pageNumber, 50, pdf.internal.pageSize.height - 20);
        return pdf;
    };
    
    //and this one resets the doc back to normal
    pdfView.prototype.resetDocumentAfterPrint = function(){
        $('body').removeClass("printview");
        let viewport = document.querySelector("meta[name=viewport]");
        viewport.setAttribute('content', 'device-width, initial-scale=1, shrink-to-fit=no');
    };
    

    my css example for the .printview case:

    body.printview #header,
    body.printview footer
    {
        display: none !important;
    }
    
    body.printview{
        margin-top: 0px !important;
    }
    
    body.printview #main-content{
        margin-top: 0px !important;
    }
    
    body.printview h1{
        margin-top: 40px !important;
    }
    

    enjoy

    Contributions to @Code Spy for the Link you provided, which was the basis for this aporach.

    0 讨论(0)
  • 2021-02-19 05:48

    pdf.addHtml does not work if there are svg images on the web page. I copy the solution here, based on the picture being in a canvas already.

    Here are the numbers (paper width and height) that I found to work. It still creates a little overlap part between the pages, but good enough for me. if you can find an official number from jsPDF, use them.

    var imgData = canvas.toDataURL('image/png');
    var imgWidth = 210; 
    var pageHeight = 295;  
    var imgHeight = canvas.height * imgWidth / canvas.width;
    var heightLeft = imgHeight;
    var doc = new jsPDF('p', 'mm');
    var position = 0;
    
    doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
    heightLeft -= pageHeight;
    
    while (heightLeft >= 0) {
      position = heightLeft - imgHeight;
      doc.addPage();
      doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
      heightLeft -= pageHeight;
    }
    doc.save( 'file.pdf');`
    
    0 讨论(0)
  • 2021-02-19 05:55

    I was able to get it done using async functionality.

    (async function loop() {
        var pages = [...]
        for (var i = 0; i < pages.length; i++) {
          await new Promise(function(resolve) {
            html2canvas(pages[i], {scale: 1}).then(function(canvas) {
    
              var img=canvas.toDataURL("image/png");
              doc.addImage(img,'JPEG', 10, 10);
              if ((i+1) == pages.length) {
                doc.save('menu.pdf');
              } else {
                doc.addPage();
              }
              resolve();
            });
          });
        }
    })();
    
    0 讨论(0)
  • 2021-02-19 05:55

    You can try it:

    $('#cmd2').click(function () {
    
        var len = 4; //$x(".//body/div/div").length
        var pdf = new jsPDF('p', 'mm','a4');
        var position = 0;
        Hide
        for (let i = 1;i  <= len; i++){
            html2canvas(document.querySelector('#pg'+i),
                {dpi: 300, // Set to 300 DPI
                scale: 1 // Adjusts your resolution
                }).then(canvas => {
                pdf.addImage(canvas.toDataURL("images/png", 1), 'PNG', 0,position, 210, 295);
    
                if (i == len){
                    pdf.save('sample-file.pdf');
                }else{
                    pdf.addPage();
                }
            });
        }
    });
    
    0 讨论(0)
提交回复
热议问题