Multipage pdf with html2Canvas
Asked Answered
C

2

3

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

Cason answered 28/11, 2017 at 10:34 Comment(0)
N
2

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.

Numeral answered 11/3, 2018 at 19:40 Comment(0)
A
1

Are you try?

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

}

Aquiculture answered 23/1, 2021 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.