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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27045704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:39:03  来源:igfitidea点击:

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

javascriptjqueryhtml2canvasjspdf

提问by Tom Nolan

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

我有一个脚本,它使用 HTML2Canvas 对div页面内的a 进行屏幕截图,然后使用 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. For example the screenshot is larger than 8.5x11. The width is fine, but I need it to create more than one page to fit the entire screenshot.

问题是生成的pdf只有一页,截图在某些情况下需要不止一页。例如屏幕截图大于 8.5x11。宽度很好,但我需要它来创建多个页面以适合整个屏幕截图。

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?

有什么想法可以修改它以允许多个页面吗?

回答by Trilok Nagvenkar

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.

如果网页上有 svg 图像,pdf.addHtml 将不起作用。我根据已经在画布中的图片复制了这里的解决方案。

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

回答by Ajay Gunpal

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. Stretching is a issue in addhtml till now and i am still not able to find on internet how to solve this issue.

注意:这会破坏多个页面上的 html,但这些页面会被拉伸。到目前为止,拉伸是 addhtml 中的一个问题,我仍然无法在互联网上找到如何解决这个问题。

回答by avoliva

I was able to get it done using asyncfunctionality.

我能够使用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();
        });
      });
    }
})();

回答by helle

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. I encapsulated the generation part in an extra js object (you need to include this file also):

在这里你可以看到 pdf 生成。我将生成部分封装在一个额外的 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 .printviewcase:

我的.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 的基础。

回答by Jessé Filho

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