'jsPDF addHTML exporting low quality image to PDF

Simple question searching from last 2 days but didnt find solution i am converting html to pdf using this addHTML api of jsPDF

$('#loadPdf').on('click', function() {
        var pdf = new jsPDF('p', 'in', 'a4');
        pdf.addHTML($('#complete')[0], function() {
            pdf.save('new.pdf');
            pdf.output('datauri');
        });
    });

this is producing blur image pdf the text is showing blurry. I searched a lot find some links (share below) but didn't get answer.

html2canvas-generates-blurry-images

addHTML image quality

jspdf and addHTML / blurry font

is there any way available to get high quality image pdf. If i don't use addHTML api and use any other then image is not displaying in pdf. help please



Solution 1:[1]

It looks like that many are still using pdf.addHTML() and have the same low quality issue. pdf.addHTML() is actually deprecated now. The new vector-supporting API, pdf.html(), works much better. See their sample for yourself. Here is the working code using jsPDF and html2canvas 1.0.0-alpha.11 :

<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" 
        integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/"
        crossorigin="anonymous">
</script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
    function download() {
        let pdf = new jsPDF('l', 'pt', 'a4');
        pdf.html(document.getElementById('id'), {
            callback: function () {
                //pdf.save('test.pdf');
                window.open(pdf.output('bloburl')); // to debug
            }
        });
    }
</script>

Solution 2:[2]

Try with this: html2canvas + jspDF.js
My pdf quality issue got solved with this

function createPDFObject() {
  html2canvas(document.getElementById("main"), {
   onrendered:function(canvas) {

  var contentWidth = canvas.width;
  var contentHeight = canvas.height;

  //One page pdf shows the height of canvas generated by html page;
  var pageHeight = contentWidth / 592.28 * 841.89;
  //html page height without pdf generation
  var leftHeight = contentHeight;
  //Page offset
  var position = 0;
  //a4 paper size [595.28841.89], width and height of image in pdf of canvas generated by html page
  var imgWidth = 595.28; 
  var imgHeight = 592.28/contentWidth * contentHeight;

  //Return picture dataURL, parameters: picture format and sharpness (0-1)
  var pageData = canvas.toDataURL('image/jpeg', 1.0);

  //Direction is vertical by default, dimension ponits, format A4 [595.28841.89]
  var pdf = new jsPDF('', 'pt', 'a4');
  
  //There are two heights to distinguish, one is the actual height of the html page, and the height of the generated pdf page (841.89)
  //When the content does not exceed the display range of one page of pdf, paging is not required
  if (leftHeight < pageHeight) {
      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
  } else {
      while(leftHeight > 0) {
          pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
          leftHeight -= pageHeight;
          position -= 841.89;
          //Avoid adding blank pages
          if(leftHeight > 0) {
            pdf.addPage();
          }
      }
  }
   pdf.save('stone.pdf');

  }
 });

Solution 3:[3]

This issue is related to scaling. In my case i have doubled the height and width at run time in angular application. This had resolve my issue. You can try also with increasing height and weight. It will resolve the issue.

import * as jsPDF from 'jspdf';
import * as html2canvas from "html2canvas";
import * as $ from 'jquery';
export class Print {
    static exportTwo(elem: any,progress:any) {
        var canvasToImage = function (canvas: any) {
            var img = new Image();
            var dataURL = canvas.toDataURL('image/png', 0.92);
            img.src = dataURL;
            return img;
        };
        var canvasShiftImage = function (oldCanvas: any, shiftAmt: any) {
            shiftAmt = parseInt(shiftAmt) || 0;
            if (!shiftAmt) { return oldCanvas; }

            var newCanvas = document.createElement('canvas');
            newCanvas.height = oldCanvas.height - shiftAmt;
            newCanvas.width = oldCanvas.width;
            var ctx = newCanvas.getContext('2d');
            ctx['imageSmoothingEnabled'] = false; /* standard */
            ctx['mozImageSmoothingEnabled'] = false; // Firefox 
            ctx['oImageSmoothingEnabled'] = false; // Opera /
            ctx['webkitImageSmoothingEnabled'] = false; // Safari /
            ctx['msImageSmoothingEnabled'] = false; // IE */
            //ctx.fillStyle = "#";
            var img = canvasToImage(oldCanvas);
            ctx.drawImage(img, 0, shiftAmt, img.width, img.height, 0, 0, img.width, img.height);

            return newCanvas;
        };


        var canvasToImageSuccess = function (canvas: any) {
            var l = {
                orientation: 'p',
                unit: 'mm',
                format: 'a4',
                compress: true,
                fontSize: 40,
                lineHeight: 1,
                autoSize: false,
                printHeaders: true
            };
            var pdf = new jsPDF(l),
                pdfInternals = pdf.internal,
                pdfPageSize = pdfInternals.pageSize,
                pdfScaleFactor = pdfInternals.scaleFactor,
                pdfPageWidth = pdfPageSize.width,
                pdfPageHeight = pdfPageSize.height,
                totalPdfHeight = 0,
                htmlPageHeight = canvas.height,
                htmlScaleFactor = canvas.width / (pdfPageWidth * pdfScaleFactor),
                safetyNet = 0;
            while (totalPdfHeight < htmlPageHeight && safetyNet < 15) {
                var newCanvas = canvasShiftImage(canvas, totalPdfHeight);
                pdf.addImage(newCanvas, 'PNG', 0, 0, pdfPageWidth, pdfPageHeight, 'NONE', 'SLOW');

                totalPdfHeight += (pdfPageHeight * pdfScaleFactor * htmlScaleFactor);

                if (totalPdfHeight < (htmlPageHeight)) {
                    pdf.addPage();
                }
                safetyNet++;
            }
            var source = $('#print')[0];
            pdf.save('invoice.pdf');
        };

        var bigCanvas = $("<div>").appendTo($('#print'));  // This will be the 2x sized canvas we're going to render
        var scaledElement = $('#print').clone()
            .css({
                'margin': '2%',
                'padding': '1%',
                'transform': 'scale(2,2)',
                'transform-origin': '0 0',
            })
            .appendTo(bigCanvas);

        var oldWidth = scaledElement.width();
        var oldHeight = scaledElement.height();

        var newWidth = oldWidth * 2;
        var newHeight = oldHeight * 2;

        bigCanvas.css({
            'width': newWidth+200,
            'height': newHeight+200,
            'margin': '2%',
            'padding': '1%',
        })

        html2canvas(bigCanvas[0]).then((canvas: any) => {
            canvasToImageSuccess(canvas);
            bigCanvas.remove();
            progress.done();
        });
    }
}

Solution 4:[4]

Check out this solution:

http://plnkr.co/edit/nNSvHL8MZcT6nNKg9CG9

From:

https://github.com/MrRio/jsPDF/issues/339

<html>

  <head>
    <link data-require="[email protected]" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
    <link rel="stylesheet" href="style.css" />

    <script data-require="[email protected]" data-semver="2.0.1" src="http://code.jquery.com/jquery-2.0.1.min.js"></script>
    <script src="html2canvas.min.js"></script>
    <script src="jspdf.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <span class="navbar-brand pull-left">Some Brand</span>
        </div>
      </div>
    </nav>
    <main class="container">
      <ol class="breadcrumb">
        <li>
          <a href="#">Home</a>
        </li>
        <li>
          <a href="#">Fake Link</a>
        </li>
        <li class="active">Fake Page thing</li>
      </ol>
      <div class="jumbotron">
        <h1>Cool Export Test Page!</h1>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce egestas elementum justo sed placerat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin vehicula quam a dolor ullamcorper iaculis. In et laoreet est, commodo placerat lectus. Sed ac ullamcorper diam. Curabitur id sem leo. Proin non dictum massa. Aliquam et dui ante</p>
        <p>
          <button type="button" class="btn btn-primary btn-lg" id="button1">Export 1</button>
          <button type="button" class="btn btn-default btn-lg" id="button2">Export 2</button>
        </p>
      </div>
       <h3>Another header!</h3>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce egestas elementum justo sed placerat.</p>
      <div class="panel panel-primary">
        <div class="panel-heading">Panel Heading</div>
        <table class="table table-bordered table-striped">
          <thead>
            <tr>
              <th>Apples</th>
              <th>Bananas</th>
              <th>Carrots</th>
              <th>Donuts</th>
              <th>French Fries</th>
              <th>Grapes</th>
              <th>Ham</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
            <tr>
              <td>100%</td>
              <td>Lorem ipsum dolor sit</td>
              <td>0.2245</td>
              <td>$1.25</td>
              <td>1231235</td>
              <td>asdf</td>
              <td>11/11/12</td>
            </tr>
          </tbody>
        </table>
      </div>
      <div class="well">
        <h3>Okay this is probably enough data</h3>
        <p>Finish strong with some lorem ipsum</p>
        </div>
    </main>
    <footer>
      <div class="container">This is a footer</div>
    </footer>
  </body>

</html>

Solution 5:[5]

I found an answer from this discussion: How to scale an image (in data URI format) in JavaScript (real scaling, not using styling) and implemented it this way, works for my usecase:

    var A4_width = 595; //pixels
    var A4_height = 842; //pixels
    var ratio = 2; // scale for higher image's dpi

    var oldCanvas = document.createElement('canvas');
    oldCanvas.width = A4_width;
    oldCanvas.height = A4_height;
    var oldContext = oldCanvas.getContext('2d');
    var oldImg = new Image();
    oldImg.src = oldCanvas.toDataURL();
    oldContext.drawImage(oldImg, 0, 0, A4_width, A4_height);

    var newImg = new Image();
    newImg.onload = function () {
        var newCanvas = document.createElement('canvas');
        newCanvas.width = A4_width * ratio;
        newCanvas.height = A4_height * ratio;
        var newContext = newCanvas.getContext('2d');

        // Scale and draw the source image to the canvas
        newContext.drawImage(newImg, 0, 0, A4_width * ratio, A4_height * ratio);
        newImg.src = newCanvas.toDataURL();
        var pdfDoc = new jsPDF({
            unit: 'mm'
        });
        pdfDoc.addImage(newImg, 'png', 0, 0, 210, 297); // imageData, format, x, y, w, h
        pdfDoc.save('testFile.pdf'); //save file
        newImg.onload = undefined; // kill the func
    }
    newImg.src = oldImg.src; //set source to the old image

Solution 6:[6]

This works fine

          var ctx = onePageCanvas.getContext('2d');
          //set the image quality
            ctx.webkitImageSmoothingEnabled = true;
            ctx.mozImageSmoothingEnabled = true;
            ctx.imageSmoothingEnabled = true;
            ctx.imageSmoothingQuality = "high";

            ctx.drawImage(srcImg,0,0); //this gives good img quality 

            var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0); //set png image with quality

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

           pdf.addImage(canvasDataURL, 'PNG', 10, 10, (width*.62), (height*.62),undefined,'FAST'); //addimage to jspdf

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Chandan Kumar
Solution 3 Dhanik Lal Sahni
Solution 4 Steve Seeger
Solution 5 Terry Truong
Solution 6 Shalini