简体   繁体   English

如何使用 jsPDF 和 HTML2Canvas 从网站获取多页 pdf?

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

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.我有一个使用 HTML2Canvas 截取页面内div的屏幕截图,然后使用 jsPDF 将其转换为 pdf 的脚本。

The problem is the pdf that is generated is only one page, and the screenshot requires more than one page in some instances.问题是生成的 pdf 只有一页,而截图在某些情况下需要不止一页。 For example the screenshot is larger than 8.5x11.例如,屏幕截图大于 8.5x11。 The width is fine, but I need it to create more than one page to fit the entire screenshot.宽度很好,但我需要它来创建多个页面以适合整个屏幕截图。

Here is my script:这是我的脚本:

var pdf = new jsPDF('portrait', 'pt', 'letter');
$('.export').click(function() {
      pdf.addHTML($('.profile-expand')[0], function () {
           pdf.save('bfc-schedule.pdf');
      });
 });

Any ideas how I could modify that to allow for multiple pages?有什么想法可以修改它以允许多个页面吗?

pdf.addHtml does not work if there are svg images on the web page.如果网页上有 svg 图像,则 pdf.addHtml 不起作用。 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.如果您可以从 jsPDF 中找到官方编号,请使用它们。

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

you can use page split option of addhtml like this:您可以像这样使用 addhtml 的页面拆分选项:

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.注意:这会破坏多个页面上的 html,但这些页面会被拉伸。 Stretching is a issue in addhtml till now and i am still not able to find on internet how to solve this issue.到目前为止,拉伸是 addhtml 中的一个问题,我仍然无法在互联网上找到如何解决这个问题。

I was able to get it done using async functionality.我能够使用async功能完成它。

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

This is my aproach, also with jspdf and html2canvas which did a very good job for me:这是我的方法,还有 jspdf 和 html2canvas 对我来说做得很好:

I am using a wrapper node which holds the content to be converted to pdf:我正在使用一个包含要转换为 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:这是 JS 集成(我只检查了这个版本)并调用:

<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.在这里你可以看到 pdf 的生成。 I encapsulated the generation part in an extra js object (you need to include this file also):我将生成部分封装在一个额外的 js 对象中(您还需要包含此文件):

//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:我的.printview案例的 css 示例:

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.对您提供的链接的@Code Spy 的贡献,这是此 aporach 的基础。

Found out the solution to this,putting a rectangle as border for each pdf page and also starting the second page and other pages from a litte down by making difference in pageHeight,hope this will resolve for few...找到了解决方案,将一个矩形作为每个 pdf 页面的边框,并通过改变 pageHeight 从一点点开始第二页和其他页面,希望这将解决少数...

html2canvas(myCanvas).then(function (canvas) {

      var imgWidth = 210;
      var pageHeight = 290;
      var imgHeight = canvas.height * imgWidth / canvas.width;
      var heightLeft = imgHeight;


      var doc = new jsPDF('p', 'mm');
      var position = 0;
      var pageData = canvas.toDataURL('image/jpeg', 1.0);
      var imgData = encodeURIComponent(pageData);
      doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
      doc.setLineWidth(5);
      doc.setDrawColor(255, 255, 255);
      doc.rect(0, 0, 210, 295);
      heightLeft -= pageHeight;

      while (heightLeft >= 0) {
        position = heightLeft - imgHeight;
        doc.addPage();
        doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
        doc.setLineWidth(5);
        doc.setDrawColor(255, 255, 255);
        doc.rect(0, 0, 210, 295);
        heightLeft -= pageHeight;
      }
      doc.save('file.pdf');

    });
  };

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM