HTML2canvas generates Blurry images
Asked Answered
M

9

38

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!

Monzonite answered 2/4, 2014 at 7:2 Comment(2)
Have you checked whether this concerns all web browsers?Streamline
i would try to set imageSmoothingEnabled to false (beware of vendor prefixes)Glaikit
M
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

Monzonite answered 2/4, 2014 at 17:42 Comment(3)
i am too facing this blur image problem but i didnt get your answer can u elaborate moreFungosity
Please make the solution more evident :)Stambul
@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 :)Stambul
A
42

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
});
Andrews answered 7/6, 2018 at 8:21 Comment(3)
dpi option not using in latest release.so use scale for high quality imageAndrews
scale is working perfectly :) another workaround is to change window.devicePixelRatio = 2; before calling html2canvasAeonian
@PatrikKelemen This worked for me and was the simplest and cleanest option, with minimal changes in code. Thank you!Bennybenoit
O
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

Oleoresin answered 26/4, 2016 at 7:26 Comment(6)
what version of the html2canvas library are you using for this fix?Fulminous
Works pefectly for me. Make sure you include this version of html2canvas script to make it work.Huambo
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.Fierro
@crclayton: also what is the difference between "canvas.width" and "canvas.style.width" ?Fierro
i have same problem as saadk.Mistress
I think the newer version keep quality while scaling. I used version 1 with scale config and work perfectlyEpaulet
J
11

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

Josiahjosias answered 1/6, 2020 at 4:59 Comment(3)
your suggestion of domtoimage worked like a charm for me. html2canvas was a terrible pain. domtoimage solved the issue of pixels. Thanks a lot :)Donniedonnish
As of 2022, the dom-to-image has not been updated for five years, so I use html-to-image.Colt
Do we have option to save as ppt file? @Sulman AzharBrunn
A
5

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

Adelinaadelind answered 14/8, 2020 at 13:7 Comment(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.Laxative
M
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

Monzonite answered 2/4, 2014 at 17:42 Comment(3)
i am too facing this blur image problem but i didnt get your answer can u elaborate moreFungosity
Please make the solution more evident :)Stambul
@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 :)Stambul
S
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 {};
    }
Sinister answered 1/2, 2016 at 16:24 Comment(1)
note that although it makes it better than what it was it still doesn't completely make it perfect.Sinister
O
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

Orion answered 19/10, 2020 at 23:1 Comment(1)
While this actually works, setting the scale value higher also increases the size of the file.Receiptor
I
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;
Intro answered 10/8, 2022 at 19:36 Comment(0)
C
-6

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!

Cottage answered 4/6, 2014 at 14:2 Comment(2)
Canvas2Image cannot improve the image quality if html2canvas already generates a low quality image, which is the problem in the first place.Yellowwood
use of third-party library for fixing a bug in another library always is not good approach. Good luck.Headliner

© 2022 - 2024 — McMap. All rights reserved.