使用 html2Canvas 的多页 pdf

问题描述 投票:0回答:3

我正在使用react-typescript,并且在这个参考的帮助下我已经成功地从html页面创建了一个PDF文件 从 React Components 生成 PDF 文件

但是如果我们想创建一个包含多个页面的 PDF 那么该怎么办呢? a4 尺寸的页面各边都有适当的边距,并且在每个新页面中都应应用该边距。

这是我的代码。

private printDocument() {
        const input = document.getElementById("pdf");

        html2canvas(input)
            .then((canvas) => {
                const pdf = new jsPDF("p", "px", "a4");
                pdf.addHTML(input, 0, 0, {
                    pagesplit: true,
                    background: "#ffffff",
                }, () => {
                    pdf.save("download.pdf");
                });
            });
    }

请帮我它是银色的。 先谢谢你了

jspdf html2canvas html2pdf
3个回答
2
投票

我尝试使用jsPDF来解决这个问题,但没有成功。我不清楚 jsPDF 管理分页内容分割的方式。 所以我决定使用 pdfMake,另一个令人惊叹的 js 库。 我在这个问题中得到了这些信息:使用 JavaScript 生成 PDF 文件

在您提到的问题中(从 React Components 生成 PDF 文件),最佳答案提出了一种处理分页的好方法。您为每个页面创建一个 div。但就我而言,我的内容可以动态增加您的垂直尺寸,因此我无法修复 div 的垂直尺寸。 所以,我确实喜欢这样:

printDocument() {
  const divs = document.getElementsByClassName('example');
  const newList = [].slice.call(inputs);
  var contentArray = []
  var docDefinition = {
            pageSize: {width: 800, height: 1173},
            content: [
                {
                    text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Confectum ponit legam, perferendis nomine miserum, animi. Moveat nesciunt triari naturam.'
                }
            ]
            
        }
        
  Promise.map(newList, async (element, index) => {
            let canvas = await html2canvas(element);
            const imgData = await canvas.toDataURL('image/png');
            // console.log("imgData URL => ", imgData)
            // margin horizontal -40 = removing white spaces
            return contentArray[`${index}`] = [{ image: imgData, width: canvas.width, height: canvas.height, margin: [-40, 0] }, {
                text: ` ${index} - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Confectum ponit legam, perferendis nomine miserum, animi.`
}];
           
        }).then(
            () => ( docDefinition.content.push(contentArray))
        ).then(
            () => {
                console.log("... starting download ...")
                pdfMake.createPdf(docDefinition).download('examplePdf.pdf')
            } 
        )
}

// In your react's component constructor ... 

constructor(props) {
        super(props);
        this.printDocument = this.printDocument.bind(this)
}

// the imports below ...
import Promise from 'bluebird';
import html2canvas from 'html2canvas';
import pdfMake from 'pdfmake/build/pdfmake.js';
import pdfFonts from "pdfmake/build/vfs_fonts.js";
pdfMake.vfs = pdfFonts.pdfMake.vfs;

// i'm using these middlewares
import promise from 'redux-promise'
import multi from 'redux-multi'
import thunk from 'redux-thunk'
<div>
  The approach here is: a div it's not a page. Because if the image generated by the canvas element it's bigger than the page vertical size, we'll need to control the pagination by ourselves. So, we broke our content in small elements to the pdf generator handle the pagination to us. This way we garantee that the pagination will occurs without cuts. 
  <div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
  
  // any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
  
  </div>
  <div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
  
  // any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
  
  </div>
  <div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
  
  // any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
  
  </div>
  
</div>

<div>
 <button onClick={this.printDocument}> print using PDFMake  </button>
</div>

将 bluebird 的

Promise.map
与异步/等待资源结合使用,我们可以确保等到画布上的所有图像生成结束。此过程可能需要一段时间,具体取决于图像的大小。

http://bluebirdjs.com/docs/api/promise.map.html

看一下 pdfMake 的 github: https://github.com/bpampuch/pdfmake

他的游乐场有很好的例子和方法: http://pdfmake.org/playground.html

我仍然会尝试升级这种方式来解决分页问题,但这是我解决问题的最快方法,我希望对某人有用。


1
投票

你尝试吗?

const printDocument= () => {
const input = document.getElementById('divToPrint');
const input2 = document.getElementById('divToPrint2');
const pdf = new jsPDF();

html2canvas(input)
  .then((canvas) => {
    const imgData = canvas.toDataURL('image/png');
    pdf.addImage(imgData, 'JPEG', 0, 0);
    pdf.addPage();
    html2canvas(input2)
      .then((canvas2) => {
        const imgData2 = canvas2.toDataURL('image/png');
        pdf.addImage(imgData2, 'JPEG', 0, 0);
        pdf.save("download.pdf");
      })
    ;
  })
;

}


0
投票

2024 年,在我的一个项目开发过程中,我发现了解决方案(又名库),它在处理这些事情方面非常非常好。

react-pdf@react-pdf/renderer的组合在多页pdf中非常有用。 @react-pdf/renderer也支持基本的flexbox属性,所以我们也可以为pdf做css!

© www.soinside.com 2019 - 2024. All rights reserved.