16

I have a table(columns aligned differently) which is to be saved as pdf.I converted the table to image using html2canvas and then saved the image into pdf usng jspdf. It works well if the size of the image is less than or equal to page size of pdf but if the image size is bigger than the page size then it saves only first page of pdf(which has only a part of the image) and rest of the image is not displayed/saved in pdf. here the javascript code I used.

       $("#btnVC_saveGLSummary").click(function () {
        html2canvas($("#tblSaveAsPdf1"), {
        onrendered: function (canvas) {
        var myImage = canvas.toDataURL("image/jpeg");            
        var d = new Date().toISOString().slice(0, 19).replace(/-/g, "");
        filename = 'report_' + d + '.pdf';
        var doc = new jsPDF();
        doc.addImage(myImage, 'JPEG', 12, 10);
        doc.save(filename);
          }
         });
       });

Any ideas how to get the remaining part of the image on the second page of pdf.

user3687972
  • 308
  • 1
  • 6
  • 10

7 Answers7

43

It works for html2canvas and 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 = 10; // give some top padding to first page

doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= pageHeight;

while (heightLeft >= 0) {
  position += heightLeft - imgHeight; // top padding for other pages
  doc.addPage();
  doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
  heightLeft -= pageHeight;
}
doc.save( 'file.pdf');
Furkat U.
  • 431
  • 5
  • 20
Shuvro Akash
  • 540
  • 5
  • 17
  • 1
    it works great thank you, one tiny issue add `position += heightLeft - imgHeight;` to make some top padding in next pages – Furkat U. Aug 22 '19 at 12:28
  • 12
    I think there is a error in the position calculation for the third and subsequent pages. The += in the assignment position += heightLeft - imgHeight means the pageHeight gets deducted twice. So instead of positions being 0, -295, -590 etc they become 0, -295, -885 etc. The solution is just to use the = assignment as position = heightLeft - imgHeight or replace the position calculation in the loop with: x= x+1;position = (pageHeight*x)*-1; I hope this helps someone. – Lew Perren Apr 10 '20 at 13:20
  • how to set the pdf page size according to the image, after that image create new page and new image on new page – Manmeet Khurana Oct 13 '20 at 05:53
  • 1
    i think it meat to be `position = heightLeft - imgHeight + 10` (the original padding on the first page will cause offset 10 for the following pages.) – Alba Hoo Feb 25 '22 at 06:16
14

I use this method

function makePDF(){
var quotes = document.getElementById('container-fluid');
html2canvas(quotes, {
    onrendered: function(canvas) {
    //! MAKE YOUR PDF
    var pdf = new jsPDF('p', 'pt', 'a4');

    for (var i = 0; i <= quotes.clientHeight/980; i++) {
        //! This is all just html2canvas stuff
        var srcImg  = canvas;
        var sX      = 0;
        var sY      = 1120*i; // start 980 pixels down for every new page
        var sWidth  = 778;
        var sHeight = 1120;
        var dX      = 0;
        var dY      = 0;
        var dWidth  = 778;
        var dHeight = 1120;

        window.onePageCanvas = document.createElement("canvas");
        onePageCanvas.setAttribute('width', 778);
        onePageCanvas.setAttribute('height', 1120);
        var ctx = onePageCanvas.getContext('2d');
        // details on this usage of this function: 
        // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
        ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);

        // document.body.appendChild(canvas);
        var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);

        var width         = onePageCanvas.width;
        var height        = onePageCanvas.clientHeight;

        //! If we're on anything other than the first page,
        // add another page
        if (i > 0) {
            pdf.addPage(595, 842); //8.5" x 11" in pts (in*72)
        }
        //! now we declare that we're working on that page
        pdf.setPage(i+1);
        //! now we add content to that page!
        pdf.addImage(canvasDataURL, 'PNG', 0, 0, (width*.72), (height*.71));

    }
    //! after the for loop is finished running, we save the pdf.
    pdf.save('Test3.pdf');
  }
  });
  }

I hope it will be helpful

Inspired by another stack overflow response

Carlos Rodríguez
  • 745
  • 11
  • 20
  • 1
    it is giving error : Property 'onePageCanvas' does not exist on type 'Window' and Cannot find name 'onePageCanvas'. and create pdf with blank content – Bharti Ladumor Nov 24 '18 at 06:56
  • 1
    @BhartiLadumor - If you're not using this in a regular browser context, the `window` object isn't available. Instead of `window.onePageCanvas =`, use `var onePageCanvas =` to declare it as a local variable in the scope of the loop – ben_weller Mar 29 '19 at 16:20
  • Looks like it similar to real source https://stackoverflow.com/questions/19272933/jspdf-multi-page-pdf-with-html-renderer – ßiansor Å. Ålmerol Apr 22 '19 at 04:10
1

This was answered further up in a similar way, but I felt I wanted to give an example leaving out unnecessary code:

You can easily run through all pages and put 'watermark' texts or other items on every page like this:

let pdf = new jspdf();
// do something that creates multiple pages
for (let pageNumber = 1; pageNumber <= pdf.getNumberOfPages(); pageNumber++) {
  pdf.setPage(pageNumber)
  pdf.addImage('myImgOnEveryPage.png', 10,10,20,20);
  pdf.text('My text on every page, 12, 12);
}

(JSPDF version 2.1.1)

0
                var ctx = canvas.getContext("2d");
                ctx.drawImage(image, 0, 1025, sectionWidth, 1250, 0, 0, 1800, 950);
                var image2 = new Image();
                image2 = Canvas2Image.convertToJPEG(canvas);
                image2Data = image2.src;
                doc.addImage(image2Data, 'JPEG', -105, 5, 440, 325);

Basically, you get the context of your canvas and then you can use the drawImage function to create a new Image that is a portion of your original canvas. The parameters of drawImage are:

drawImage(img, startX, startY, originalW, originalH, destX, dextY, destW, destH);

Where startX and Y are your starting locations for the clipping on the original images, original W and H are the height and width of your clipping (on the original picture), basically how much to clip, destX and Y are where on your PDF to put the new clipping and destH and W define how big the clipping is when placed on the canvas (they stretch the image once you've clipped it)
Hope this helped,
Cheers

yodofizzy
  • 63
  • 2
  • 14
0

You can easily do this by adding small tweak in your own code.

$("#btnVC_saveGLSummary").click(function () {
    html2canvas($("#tblSaveAsPdf1"), {
    onrendered: function (canvas) {
    var myImage = canvas.toDataURL("image/jpeg");            
    var d = new Date().toISOString().slice(0, 19).replace(/-/g, "");
    filename = 'report_' + d + '.pdf';
    var doc = new jsPDF();
    var totalPages = doc.internal.getNumberOfPages();
    for(let i = 1; i < totalPages; i++) {
        doc.setPage(i);
        doc.addImage(myImage, 'JPEG', 12, 10);
    }       
    doc.save(filename);
    }
  });
});
Ubaid
  • 737
  • 8
  • 18
0

Function react convert multiple component to a PDF file

  const ids = ["id1", "id2", "id3"]; // list id component want to export



const handleExport = useCallback(async () => {
setIsLoading(true);

const pdf = jsPDF("p", "pt", "a4");
let allHeight = 0;

const canvasPromises = ids.map(async (id) => {
  // ! change to state id
  setIsLoading(true);

  const element = document.getElementById(id);
  const canvas = await html2canvas(element);
  const img = canvas.toDataURL("image/png");
  const imgProperties = pdf.getImageProperties(img);
  const pdfWidth = pdf.internal.pageSize.getWidth();
  const pdfHeight =
    (imgProperties.height * pdfWidth) / imgProperties.width;

  if (allHeight > 700) {  // heigth over a4 heigth add page for pdf
    allHeight = 5;
    pdf.addPage(1);
  }

  pdf.addImage(
    img,
    "PNG",
    0,
    allHeight,
    pdfWidth - 5,
    pdfHeight,
    id,
    "FAST",
  );

  allHeight += pdfHeight + 5;
});
const dataField = await Promise.all(canvasPromises).then(
  (res) => res,
);

pdf.save(`${title}-${new Date().toLocaleString()}.pdf`);
setIsLoading(false);
return dataField; 
}, [ids]);
0

You can also achieve this by below;

const doc = new jsPDF('p', 'mm');
const imgData = canvas.toDataURL('image/png');
const imgWidth = 210; 
const pageHeight = doc.internal.pageSize.getHeight();  
const imgHeight = (canvas.height * imgWidth) / canvas.width;
const totalPageSize = Math.ceil(imgHeight / pageHeight);
let yPosition = 10;

doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);

for (let pageIndex = 1; pageIndex < totalPageSize; pageIndex++) {
  // making it negative to crop the image
  // and adding 10 because of the initial padding
  yPosition = pageIndex * pageHeight * -1 + 10; 
  doc.addPage();
  doc.addImage(
    imgData,
    'PNG',
    0,
    yPosition,
    imageWidth,
    imageHeight
  );
}

doc.save( 'file.pdf');