34

I am using jsPDF and it uses html2canvas to generate an image from some html element and insert on the .pdf file. But there is a problem on html2canvas, it generates blurry images from the html. See example below:

HTML content:

http://puu.sh/7SZz4.png

html2canvas generated image:

http://puu.sh/7SZAT.png

Is there any way to fix it or is there any better option to get the image form html?

thanks!

jgabrielfaria
  • 1,543
  • 3
  • 15
  • 19

9 Answers9

38

you can use scale options in html2canvas.

In the latest release, v1.0.0-alpha.1, you can use the scale option to increase the resolution (scale: 2 will double the resolution from the default 96dpi).

// Create a canvas with double-resolution.
html2canvas(element, {
    scale: 2,
    onrendered: myRenderFunction
});
// Create a canvas with 144 dpi (1.5x resolution).
html2canvas(element, {
    dpi: 144,
    onrendered: myRenderFunction
});
Ricky sharma
  • 701
  • 9
  • 21
14

I had this problem because I was on a retina display. I solved in by using MisterLamb's solution here.

$(window).load(function () {

    var scaleBy = 5;
    var w = 1000;
    var h = 1000;
    var div = document.querySelector('#screen');
    var canvas = document.createElement('canvas');
    canvas.width = w * scaleBy;
    canvas.height = h * scaleBy;
    canvas.style.width = w + 'px';
    canvas.style.height = h + 'px';
    var context = canvas.getContext('2d');
    context.scale(scaleBy, scaleBy);

    html2canvas(div, {
        canvas:canvas,
        onrendered: function (canvas) {
            theCanvas = canvas;
            document.body.appendChild(canvas);

            Canvas2Image.saveAsPNG(canvas);
            $(body).append(canvas);
        }
    });
});

HTML and PNG without scaling

enter image description here

HTML and PNG with scaling

enter image description here

Charles Clayton
  • 17,005
  • 11
  • 87
  • 120
  • what version of the html2canvas library are you using for this fix? – gyochum Nov 16 '16 at 18:22
  • 1
    Works pefectly for me. Make sure you include [this version of html2canvas script](https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.min.js) to make it work. – Tanuj Dhaundiyal Feb 07 '17 at 08:44
  • 3
    this is not generating the way is should be.. i makes a 702 size into 800 in width, but when image generates, it shows smaller and cut from top and right side in image. – saadk Feb 09 '17 at 11:45
  • @crclayton: also what is the difference between "canvas.width" and "canvas.style.width" ? – saadk Feb 09 '17 at 11:55
  • i have same problem as saadk. – Caleb Pitman Jun 27 '17 at 00:23
  • I think the newer version keep quality while scaling. I used version 1 with scale config and work perfectly – Ishan Fernando May 23 '19 at 11:33
10

I was facing this problem and i solved it by using domtoimage instead of html2canvas.

This HTML2CANVAS solution was not working good for me i know the scale option does increase the target div's size before capturing it but it won't work if you have something inside that div which won't resize e.g in my case it was canvas for my editing tool.

Anyway for this i opted for domtoimage and trust me i think that this is the best solution of them all.

I didn't had to face any problem of html2canvas for example:

need to be at the top of webpage so html2canvas can capture the shot completely and low dpi problem

function print()
{
    var node = document.getElementById('shirtDiv');
    var options = {
        quality: 0.95
    };

    domtoimage.toJpeg(node, options).then(function (dataUrl)
    {
        var doc = new jsPDF();
        doc.addImage(dataUrl, 'JPEG', -18, 20, 240, 134.12);
        doc.save('Test.pdf');
    });
}

Cdn for dom to image:

https://cdnjs.com/libraries/dom-to-image

Cdn for jspdf:

https://cdnjs.com/libraries/jspdf

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
Sulman Azhar
  • 977
  • 1
  • 9
  • 26
  • 1
    your suggestion of domtoimage worked like a charm for me. html2canvas was a terrible pain. domtoimage solved the issue of pixels. Thanks a lot :) – adir1521 Oct 07 '21 at 16:34
  • As of 2022, the dom-to-image has not been updated for five years, so I use [html-to-image](https://www.npmjs.com/package/html-to-image). – foske Nov 17 '22 at 11:24
4

solution is very simple, after X hours of testing.

Set your ALL div's 2x higher, your IMG 2x higher, and finally set html zoom on 0.5, or if you want better quality yet, set 3x higher (in this case the html zoom must be 0.33) or more, (the original image sizes are assumed to be larger).

For example:

HTML

<body>
 <div class="pdf">
   <img src="image.jpg">
 </div>
</body>

CSS before

body {
    background: #b2b2b2;
}
.pdf {
   background: #fff;
   /* A4 size */
   width: 842px;
   height: 595px;
 }
img {
   width: 300px;
   height: 200px;
}

CSS after (only changes)

html {
   zoom: 0.5;
}

.pdf {
   /* A4 size before . 2 */
   width: 1684; 
   height: 1190px; 
 }
img { /* size before . 2 */
   width: 600px;
   height: 400px;
}

AND here is my result:

PDF before PDF after

granakj
  • 41
  • 3
  • 1
    I've been trying to fix my blurry PDFs for hours. Due to the various possible combinations of jspdf and html2canvas, I was not able to find any js solution that worked. However, this CSS solution works perfectly for my needs. Thanks for such a simple answer. – CChoma Jan 21 '21 at 15:08
2

I have found out my problem. Happens that my screen is a Retina Display, so when the canvas2html will render the HTML, due to the difference of pixel density on retina screen, the image is rendered blurred.

Found out the solution here:

https://github.com/cburgmer/rasterizeHTML.js/blob/master/examples/retina.html

jgabrielfaria
  • 1,543
  • 3
  • 15
  • 19
  • 16
    i am too facing this blur image problem but i didnt get your answer can u elaborate more – Mohammad Faizan khan Mar 20 '15 at 11:42
  • 3
    Please make the solution more evident :) – kashesandr Jun 28 '16 at 15:33
  • 1
    @YoYo actually no. There is no proper solution to print PDFs from all kind of HTML+SVG with only front-end stack. But you may configure the stuff to work with some simple web pages. You probably should use Phantomjs for PDF-printing functionality, its much more stable but requires an additional server. Also there are online services where you may provide a public url and get the pdf back. Also you're welcome to write the pdf-printing lib for front-end :) – kashesandr Jul 17 '16 at 09:47
2

This is what fixed it for me. And it wasn't because I was using a retina display (because I don't have one):

https://github.com/niklasvh/html2canvas/issues/576

Just change the getBounds() method in html2canvas.js with this one:

 function getBounds (node) {
        if (node.getBoundingClientRect) {
            var clientRect = node.getBoundingClientRect();
            var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
            return {
                top   : Math.floor(clientRect.top),
                bottom: Math.floor(clientRect.bottom || (clientRect.top + clientRect.height)),
                right : Math.floor(clientRect.left + width),
                left  : Math.floor(clientRect.left),
                width : width,
                height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
            };
        }
        return {};
    }
Shai UI
  • 50,568
  • 73
  • 204
  • 309
  • 4
    note that although it makes it better than what it was it still doesn't completely make it perfect. – Shai UI Feb 01 '16 at 16:28
1

If anyone is still looking for a solution to work for them I had success by setting scale: 5. Check it out here in their documentation. https://html2canvas.hertzen.com/configuration

  • 1
    While this actually works, setting the scale value higher also increases the size of the file. – krish Dec 03 '22 at 11:48
0

dom-to-image library worked perfect for me!

import domtoimage from "dom-to-image";
// Convert dom to image function
const exportAsImage = async (el, imageFileName) => {
  domtoimage
    .toPng(el)
    .then(function (dataUrl) {
      const image = dataUrl;

      downloadImage(image, imageFileName);
    })
    .catch(function (error) {
      console.error("oops, something went wrong!", error);
    });
};
// dowload image function
const downloadImage = (blob, fileName) => {
  const fakeLink = window.document.createElement("a");
  fakeLink.style = "display:none;";
  fakeLink.download = fileName;
  fakeLink.href = blob;
  document.body.appendChild(fakeLink);
  fakeLink.click();
  document.body.removeChild(fakeLink);
  fakeLink.remove();
};

export default exportAsImage;
-5

Try the Canvas2Image library, it gives a better quality image at least for me div to image (fiddle).

    html2canvas($("#widget"), {
        onrendered: function(canvas) {
            theCanvas = canvas;
            Canvas2Image.saveAsPNG(canvas);  // Convert and download as image with a prmompt. 
        }
    });

Good luck!

Marco
  • 129
  • 1
  • 1
  • 9
  • 3
    Canvas2Image cannot improve the image quality if html2canvas already generates a low quality image, which is the problem in the first place. – Martin Peter Apr 15 '15 at 16:02