69

Is there any way to solve this? I tried to set width and height in mm. How can I set it to full-width?

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
sreeraj nyros
  • 929
  • 1
  • 6
  • 17
  • 2
    Why not simply set the width and the height in mm to be the same as the page-size in mm? The standard paper-sizes are easy to come by and, since you know how large your page is, you know how large to make your image. Or perhaps I'm missing something? – enhzflep Apr 07 '16 at 11:19
  • Check this example and auto width adjusting function using jsPDF http://www.freakyjolly.com/jspdf-multipage-example-generate-multipage-pdf-using-single-canvas-of-html-document-using-jspdf/ – Code Spy Jul 24 '18 at 09:53

17 Answers17

131

You can get the width and height of PDF document like below,

var doc = new jsPDF("p", "mm", "a4");

var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight();

Then you can use this width and height for your image to fit the entire PDF document.

var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJ......';

doc.addImage(imgData, 'JPEG', 0, 0, width, height);

Make sure that your image has the same size (resolution) of the PDF document. Otherwise it will look distorted (stretched).

If you want convert px to mm use this link http://www.endmemo.com/sconvert/millimeterpixel.php

Weihui Guo
  • 3,669
  • 5
  • 34
  • 56
Purushoth
  • 2,673
  • 3
  • 22
  • 36
  • 3
    How can you guarantee that your image is always the same size/resolution of the page/PDF document? A better way is to calculate the aspect ratio of the image and relative width/height ratio of the page. See my answer down [below](https://stackoverflow.com/a/54336658/4271117). – Weihui Guo Jan 23 '19 at 22:30
  • If you want to keep the ratio: ``` var ratio = canvas.width/canvas.height; var width = doc.internal.pageSize.getWidth(); var height = width / ratio; doc.addImage(imgData, 'PNG', 0, 0, width, height); ``` – Jared Chu Aug 14 '19 at 20:02
  • For this solution, even it would fit, but the pdf page end up being distorted. Thank u anyway – Minh Kha Sep 22 '20 at 07:06
  • I had a problem with scaling image height from `html2canvas` method and this solution fix it. For fit canvas width to the pdf I used this method: `html2canvas(pdfElement, { scrollY: -window.scrollY })` . Additionally with x, y values from `addImage()` method you can set the pdf content position in the page. – Falcon Feb 19 '21 at 07:45
  • 2
    doc.internal.pageSize.getWidth(); getting error as getWidth() is not a function – Karthic G Aug 24 '21 at 10:23
  • cool!! I was having problem with different resolutions and seems to be it's the solution – Ngima Sherpa Jan 31 '22 at 15:32
83

If you need to get width 100% of PDF file and auto height you can use getImageProperties property of html2canvas library

html2canvas(input)
      .then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF({
          orientation: 'landscape',
        });
        const imgProps= pdf.getImageProperties(imgData);
        const pdfWidth = pdf.internal.pageSize.getWidth();
        const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
        pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
        pdf.save('download.pdf');
      });
Mike
  • 14,010
  • 29
  • 101
  • 161
Philip
  • 830
  • 6
  • 7
27

My answer deals with a more specific case of what you are asking but I think one could draw some ideas from this to apply more generally. Also, I would post this as a comment to Purushoth's answer (on which mine is based), if only I could.

Ok, so my problem was how to fit a web page into the pdf document, without losing the aspect ratio. I used jsPDF in conjuction with html2canvas and I calculated the ratio from my div's width and height. I applied that same ratio to the pdf document and the page fit perfectly onto the page without any distortion.

var divHeight = $('#div_id').height();
var divWidth = $('#div_id').width();
var ratio = divHeight / divWidth;
html2canvas(document.getElementById("div_id"), {
     height: divHeight,
     width: divWidth,
     onrendered: function(canvas) {
          var image = canvas.toDataURL("image/jpeg");
          var doc = new jsPDF(); // using defaults: orientation=portrait, unit=mm, size=A4
          var width = doc.internal.pageSize.getWidth();    
          var height = doc.internal.pageSize.getHeight();
          height = ratio * width;
          doc.addImage(image, 'JPEG', 0, 0, width-20, height-10);
          doc.save('myPage.pdf'); //Download the rendered PDF.
     }
});
AryanJ-NYC
  • 2,529
  • 2
  • 20
  • 27
zerzevul
  • 417
  • 5
  • 11
  • This approach solved my problem of fitting my large images into letter format pages. Totally recommend it – E-Bat Dec 06 '21 at 16:59
16

I discovered this while experimenting with html2canvas this morning. While this doesn't include provisions for printing multiple pages it does scale the image to page width and reframes the height in ratio to the adjusted width:

html2canvas(document.getElementById('testdiv')).then(function(canvas){
        var wid: number
        var hgt: number
        var img = canvas.toDataURL("image/png", wid = canvas.width, hgt = canvas.height);
        var hratio = hgt/wid
        var doc = new jsPDF('p','pt','a4');
        var width = doc.internal.pageSize.width;    
        var height = width * hratio
        doc.addImage(img,'JPEG',20,20, width, height);
        doc.save('Test.pdf');
    });
carbon1479
  • 190
  • 1
  • 6
11

The API changed since this commit, using version 1.4.1 it's now

var width = pdf.internal.pageSize.getWidth();
var height = pdf.internal.pageSize.getHeight();
Max
  • 979
  • 7
  • 9
10

Solution for all screen sizes and dynamic orientation:

import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'

export default async function downloadComponentInPDF(Component: HTMLElement) {
  await html2canvas(Component).then((canvas) => {
    const componentWidth = Component.offsetWidth
    const componentHeight = Component.offsetHeight

    const orientation = componentWidth >= componentHeight ? 'l' : 'p'

    const imgData = canvas.toDataURL('image/png')
    const pdf = new jsPDF({
    orientation,
    unit: 'px'
  })

    pdf.internal.pageSize.width = componentWidth
    pdf.internal.pageSize.height = componentHeight

    pdf.addImage(imgData, 'PNG', 0, 0, componentWidth, componentHeight)
    pdf.save('download.pdf')
  })
}
Igor Ryan
  • 101
  • 1
  • 3
9

If you want a dynamic sized image to automatically fill the page as much as possible and still keep the image width/height-ratio, you could do as follows:

let width = doc.internal.pageSize.getWidth()
let height = doc.internal.pageSize.getHeight()

let widthRatio = width / canvas.width
let heightRatio = height / canvas.height

let ratio = widthRatio > heightRatio ? heightRatio : widthRatio

doc.addImage(
  canvas.toDataURL('image/jpeg', 1.0),
  'JPEG',
  0,
  0,
  canvas.width * ratio,
  canvas.height * ratio,
)
thephper
  • 2,342
  • 22
  • 21
  • but still the image looks stretched in smaller screen size like iphone . can we do something about it ? – NoushadM Dec 29 '21 at 10:01
6

It's easy to fit the page if you only have one image. The more challenge task is to fit images with various sizes to a pdf file. The key to archive that is to calculate the aspect ratio of the image and relative width/height ratio of the page. The following code is what I used to convert multiple images online to a PDF file. It will rotate the image(s) based on the orientation of the images/page and set proper margin. My project use images with online src. You should be able to modify to suit your needs.

As for image rotation, if you see a blank page after rotation, it could simply be that the image is out of bounds. See this answer for details.

function exportPdf(urls) {
    let pdf = new jsPDF('l', 'mm', 'a4');
    const pageWidth = pdf.internal.pageSize.getWidth();
    const pageHeight = pdf.internal.pageSize.getHeight();
    const pageRatio = pageWidth / pageHeight;

    for (let i = 0; i < urls.length; i++) {
        let img = new Image();
        img.src = urls[i];
        img.onload = function () {
            const imgWidth = this.width;
            const imgHeight = this.height;
            const imgRatio = imgWidth / imgHeight;
            if (i > 0) { pdf.addPage(); }
            pdf.setPage(i + 1);
            if (imgRatio >= 1) {
                const wc = imgWidth / pageWidth;
                if (imgRatio >= pageRatio) {
                    pdf.addImage(img, 'JPEG', 0, (pageHeight - imgHeight / wc) / 2, pageWidth, imgHeight / wc, null, 'NONE');
                }
                else {
                    const pi = pageRatio / imgRatio;
                    pdf.addImage(img, 'JPEG', (pageWidth - pageWidth / pi) / 2, 0, pageWidth / pi, (imgHeight / pi) / wc, null, 'NONE');
                }
            }
            else {
                const wc = imgWidth / pageHeight;
                if (1 / imgRatio > pageRatio) {
                    const ip = (1 / imgRatio) / pageRatio;
                    const margin = (pageHeight - ((imgHeight / ip) / wc)) / 4;
                    pdf.addImage(img, 'JPEG', (pageWidth - (imgHeight / ip) / wc) / 2, -(((imgHeight / ip) / wc) + margin), pageHeight / ip, (imgHeight / ip) / wc, null, 'NONE', -90);
                }
                else {

                    pdf.addImage(img, 'JPEG', (pageWidth - imgHeight / wc) / 2, -(imgHeight / wc), pageHeight, imgHeight / wc, null, 'NONE', -90);
                }
            }
            if (i == urls.length - 1) {
                pdf.save('Photo.pdf');
            }
        }
    }
}

If this is a bit hard to follow, you can also use .addPage([imgWidth, imgHeight]), which is more straightforward. The downside of this method is that the first page is fixed by new jsPDF(). See this answer for details.

Weihui Guo
  • 3,669
  • 5
  • 34
  • 56
3

my solution is to check what ratio (height or width) need to apply depending of the pdf orientation and image size. note: set margin to 0 if no margin is required.

   const imgData = canvas.toDataURL("image/jpeg");

   const pdf = new jsPDF({
       orientation: "portrait", // landscape or portrait
       unit: "mm",
       format: "a4",
   });
   const imgProps = pdf.getImageProperties(imgData);
   const margin = 0.1;

   const pdfWidth = pdf.internal.pageSize.width * (1 - margin);
   const pdfHeight = pdf.internal.pageSize.height * (1 - margin);

   const x = pdf.internal.pageSize.width * (margin / 2);
   const y = pdf.internal.pageSize.height * (margin / 2);

   const widthRatio = pdfWidth / imgProps.width;
   const heightRatio = pdfHeight / imgProps.height;
   const ratio = Math.min(widthRatio, heightRatio);
   
   const w = imgProps.width * ratio;
   const h = imgProps.height * ratio;

   pdf.addImage(imgData, "JPEG", x, y, w, h);
Chris
  • 1,122
  • 1
  • 12
  • 14
3

There where a lot of solutions with .addImage, I tried many of them, but nothing worked out. So I found the .html() function and after some tries the html2canvas-scale-option. This solution is no general solution, you have to adjust the scale so it will fit your pdf, but this is the only solution, which works for me.

var doc = new jspdf.jsPDF({
    orientation: 'p',
    unit: 'pt',
    format: 'a4'
});

doc.html(document.querySelector('#styledTable'), {
    callback: function (doc) {
        doc.save('file.pdf');
    },
    margin: [60, 60, 60, 60],
    x: 32,
    y: 32,
    html2canvas: {
        scale: 0.3, //this was my solution, you have to adjust to your size
        width: 1000 //for some reason width does nothing
    },
});
MoppieMop
  • 61
  • 5
3

Some answers above didn't cover responsive pages for html2canvas. If you need to resize your image based on changing element dimensions use this code:

html2canvas(input, { scrollY: -window.scrollY }).then((canvas) => {
  const imgData = canvas.toDataURL('image/jpeg');
  const pdf = new jsPDF('p', 'mm', 'a4');
  const imgProps = pdf.getImageProperties(imgData);

  // doc and image dimensions
  const pdfWidth = pdf.internal.pageSize.getWidth();
  const pdfHeight = pdf.internal.pageSize.getHeight();
  const imgWidth = imgProps.width;
  const imgHeight = imgProps.height;

  // claculating right scale to fit the page
  const scale = Math.max(pdfHeight / imgHeight, pdfWidth / imgWidth);
  const finalWidth = imgWidth * scale;
  const finalHeight = imgHeight * scale;
  const leftMargin = (pdfWidth - finalWidth) / 2;
  // add image with alias and compression of your choice
  pdf.addImage( imgData, 'PNG', leftMargin, 0, finalWidth, finalHeight, 'alias', 'FAST');
  pdf.save( 'report-name.pdf' );
});
Rafal
  • 45
  • 4
2

A better solution is to set the doc width/height using the aspect ratio of your image.

var ExportModule = {
  // Member method to convert pixels to mm.
  pxTomm: function(px) {
    return Math.floor(px / $('#my_mm').height());
  },
  ExportToPDF: function() {
    var myCanvas = document.getElementById("exportToPDF");

    html2canvas(myCanvas, {
      onrendered: function(canvas) {
        var imgData = canvas.toDataURL(
          'image/jpeg', 1.0);
        //Get the original size of canvas/image
        var img_w = canvas.width;
        var img_h = canvas.height;

        //Convert to mm
        var doc_w = ExportModule.pxTomm(img_w);
        var doc_h = ExportModule.pxTomm(img_h);
        //Set doc size
        var doc = new jsPDF('l', 'mm', [doc_w, doc_h]);

        //set image height similar to doc size
        doc.addImage(imgData, 'JPG', 0, 0, doc_w, doc_h);
        var currentTime = new Date();
        doc.save('Dashboard_' + currentTime + '.pdf');

      }
    });
  },
}
<script src="Scripts/html2canvas.js"></script>
<script src="Scripts/jsPDF/jsPDF.js"></script>
<script src="Scripts/jsPDF/plugins/canvas.js"></script>
<script src="Scripts/jsPDF/plugins/addimage.js"></script>
<script src="Scripts/jsPDF/plugins/fileSaver.js"></script>
<div id="my_mm" style="height: 1mm; display: none"></div>

<div id="exportToPDF">
  Your html here.
</div>

<button id="export_btn" onclick="ExportModule.ExportToPDF();">Export</button>
Pratik Soni
  • 2,498
  • 16
  • 26
vohrahul
  • 1,123
  • 10
  • 17
2

This is how I've achieved in Reactjs.

Main problem were ratio and scale If you do a quick window.devicePixelRatio, it's default value is 2 which was causing the half image issue.

const printDocument = () => {
  const input = document.getElementById('divToPrint');
  const divHeight = input.clientHeight
  const divWidth = input.clientWidth
  const ratio = divHeight / divWidth;

  html2canvas(input, { scale: '1' }).then((canvas) => {
    const imgData = canvas.toDataURL('image/jpeg');
    const pdfDOC = new JSPDF("l", "mm", "a0"); //  use a4 for smaller page

    const width = pdfDOC.internal.pageSize.getWidth();
    let height = pdfDOC.internal.pageSize.getHeight();
    height = ratio * width;

    pdfDOC.addImage(imgData, 'JPEG', 0, 0, width - 20, height - 10);
    pdfDOC.save('summary.pdf');   //Download the rendered PDF.
  })
}
Priyanshu Chauhan
  • 5,297
  • 5
  • 35
  • 34
1

i faced same problem but i solve using this code

html2canvas(body,{
                onrendered:function(canvas){
                    var pdf=new jsPDF("p", "mm", "a4");
                    var width = pdf.internal.pageSize.getWidth();    
                    var height = pdf.internal.pageSize.getHeight();
                    pdf.addImage(canvas, 'JPEG', 0, 0,width,height);
                    pdf.save('test11.pdf');
                }
            }) 
AryanJ-NYC
  • 2,529
  • 2
  • 20
  • 27
Ravi Guru
  • 71
  • 3
0

Change the PDF page width to size of the image as follows

const exportOrgChartPdfFormat = async (response) => {
  try {
    const blob = new Blob([response.data], { // response.data contains blob
      type: "image/png",
    });
    const reader = new FileReader();
    reader.onloadend = () => {
      const base64data = reader.result;
      const img = new Image();
      img.onload = function () {
        const imgWidth = this.width;
        const imgHeight = this.height;
        const pdf = new jsPDF(
          imgWidth > imgHeight ? "l" : "p",
          "pt",
          [imgWidth, imgHeight]
        );
        **pdf.internal.pageSize.width = imgWidth;**
        **pdf.internal.pageSize.height = imgHeight;**
        pdf.addImage(
          base64data,
          "PNG",
          0,
          0,
          imgWidth,
          imgHeight
        );
        pdf.save("export.pdf");
      };

      img.src = base64data;
    };
    reader.readAsDataURL(blob);
  } catch (e) {
    return e;
  }
};
Sudhakar Reddy
  • 338
  • 5
  • 14
-1
convertPhotoImageToPdf(imgPath){
   var doc = new jsPDF(undefined, null, null, true);
   var imgData = 'data:image/jpeg;base64,'+ imgPath;
   doc.addImage(imgData, 'JPEG',10,10,0,0,null,'FAST',0);
   //if want add one page 
   //doc.addPage()
   doc.save('testPdf.pdf')
}
-2
        var width = doc.internal.pageSize.width;    
        var height = doc.internal.pageSize.height;
  • 4
    Please don't post only code as an answer, but also provide an explanation of what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Ran Marciano Jan 31 '21 at 21:03