Multipage pdf with html2Canvas

岁酱吖の 提交于 2019-12-11 07:18:50

问题


I am using react-typescript and I have successfully created a PDF file from an html page with the help of this ref Generating a PDF file from React Components

But if we want to create a PDF with multiple pages then what to do? with a4 size page with appropriate margins at all sides and in each new page that margin should be applied.

And here is my code.

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

please help me its argent. Thank you in advance


回答1:


I tried to use jsPDF to workaround this problem, but i did not succeed. The way that jsPDF manage the content to split in paged are not clear to me. So i decided to use pdfMake, another amazing js library. I got these infos in this question: Generating PDF files with JavaScript

In the question that you metioned (Generating a PDF file from React Components), the best answer sugest a good way to handle the pagination. You make a div for each page. But in my case, my content can dinamically increase your vertical size, so i can't fix the div's vertical sizes. So, i did like this:

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>

Using the Promise.map by bluebird with the async/await resources, we can ensure that we'll wait till the end of generation of all images from canvas. This process can take a while depending of your image's size.

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

Take a look at pdfMake's github: https://github.com/bpampuch/pdfmake

And his playground with excelent examples and how tos: http://pdfmake.org/playground.html

I'll still trying to upgrade this way to solve this problem with the pagination, but it was the quickest way that i solved the problem and i hope to be useful for somebody.



来源:https://stackoverflow.com/questions/47529365/multipage-pdf-with-html2canvas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!