Html2canvas: Way to increase resolution of the image generated via toDataURL

Created on 10 Jul 2013  ·  58Comments  ·  Source: niklasvh/html2canvas

This is more of a feature request. I am easily able to generate the PNG by calling toDataURL on the returned canvas. But the quality of the image is rather blurry/poor. I did some googling & found out that by default it just returns an image at 96 dpi. And there doesnt seem to be a standard way of improving this. Also the toDataURLHD is experimental and does not work any ways.

Is there any way html2canvas can return an image at a higher resolution? Or even if it can provide a way to get the DOM being rendered, I can use some library that uses the DOM (with all the computed styles applied to it) and then generate whatever image I want.

Most helpful comment

+1 for this. Looking to get an image with html2canvas to insert into a PDF, but getting a blurry quality.

All 58 comments

I know there was talk about this at some point in other issues/requests and someone had submitted a pull request, but I never saw the pull requests merged in.

I have a working method that we use to check the device pixel density. But this can have a hit to performance. Instead maybe we want to have a paramater to tell it to render with higher dpi?

@missing Yeah a parameter to specify the DPI would be awesome.

Also if you dont mind sharing the working method for device pixel density, that will be cool. My primary application is to just export a png of a word cloud of maximum 50-ish terms. So I am not that too concerned with performance hit on this one.

is it your problem is the quality of the image or is a blurry effect (in some instances some images are generated by html2canvas with blurry effect)?

@brcontainer I think the quality of the image is the problem. I think. E.g. On 100% zoom the photo looks ok-decent-ish. But as soon as I zoom even 5% you can see noticeable drop in the quality of the photo. Please see attached image.
association-cloud-apple-twitter

I can only be sure of something seeing an example of the problem at runtime.

Try the same place using the http://jsfiddle.net/ , and post the link here.

[edit]
chance you be trying apply _zoom_ in a canvas generated by html2canvas, you can try using (before saving as an image):

ctx.webkitImageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;

Good Luck

Hi,

We need a higher resolution than 96DPI. We need more like 300 DPI.

Is this even _possible_ to do with html2canvas?

We have the same issue with blurriness on the image. We need any solution, that will remove our blurryness, and give us a DPI that looks good.

Any thoughts/suggestions on how this might be done, or any alternate ways to achieve the same effect?

Thanks

@brcontainer I just your edit now. I did what you suggested and still no luck with image quality. Here is what I did -

                var ctx = canvas.getContext('2d');

                ctx.webkitImageSmoothingEnabled = false;
                ctx.mozImageSmoothingEnabled = false;
                ctx.imageSmoothingEnabled = false;

                var rawData = canvas.toDataURL("image/png");

is in the wrong order, you have to apply "ImageSmoothingEnabled" before resizing the image.

Put a sample of your code in http://jsfiddle.net and I'll try editing it

Hi guys,

I wish upload high resolution images without the 96dpi constraint of toDataURL. Since toDataURLHD isn't available yet, how can I realize my dream? :-)

Thanks in advance for any hint

@brcontainer I am not sure I understand what you mean by applying the smoothing before resizing, because I am not reszing the image at all. In any case I have created a jsfiddle for you to look at http://jsfiddle.net/tankchintan/92mra/4/

Really looking forward to getting this resolved! :)

Friend you are confusing, there is the toDataURL that has to resize, you have to resize the CANVAS.
I'm trying to create an example, but still could not make it work.

Hi,

I been trying to follow these suggestions for a better image quality, and it's not clear to me either.

brcontainer, is it possible you could clarify, or change/create a JS fiddle that tankchintan created, with the ideas your talking about? This makes no sense to me, even if we create a image at 2x the size, the pixilation in the image still remains after we convert the image to 192 DPI.

Hi guys, is there any more feedback on this issue? I am experiencing extremely pro image quality with html2canvas compared to something like PhantomJS where you can set zoomFactor (among other tweaks) to increase the quality/resolution.

I have a similar issue. I have a requirement of getting a snapshot of the web page into PDF document for which I'm using html2canvas to convert my div in to an image and then I use iTextsharp to add the image to a PDF. However, the image generated appears to be tad bit blurry and makes it difficult on the eye to constantly view at it. I want to know if I can create an image of specified resolution at create time itself in html2canvas.

Hi,
I have exactly same requirement as above. and same problem iam facing.
"Getting a snapshot of the web page into PDF document for which I'm using html2canvas to convert my div in to an image and then add the image to a PDF."
However, the image generated appears to be bit blurry.

I followed above suggestions but still i getting a blurry image.
here in my code: html2canvas generates snapshot of webpage is based on the system Resolution.
Iam getting same webpage "snapshot" in different sizes, based on the system resolution.

Example :
image size : 816x422
image size :1193x437
image size :1275x437
Here my expectation is :2000 x 1784 Dimension and above.

is it possible to get this Dimension of image.
please give your valuable suggestions and thank you for your valuable time.

+1 for this. Looking to get an image with html2canvas to insert into a PDF, but getting a blurry quality.

Have you tried using CSS transform matrix on a parentNode to the element you're wishing to export at a higher resolution? This works for me. E.g. "transform: scale(2, 2)"

@mudcube worked out partially for me

@brcontainer it's working fine for me

is there any solution found?? please share how to enhance resolution of blurry image i have to make a pdf of it

+1 is there any solution/guideline for this yet?

any solution found ?

Guys, use transform: scale(2, 2) it works out.

Can you provide more details?

@matiasinsaurralde right before making screen shot add css class .x2 containing css rule from above to the element, then remove that class in html2canvas callback. You will get double-sized element and double-sized screenshot also. And it seamless so you likely won't observe any resizings.

image
screenshot when i tried to follow ur suggestion @Ajaxy . i think the problem is on my code? it took so long to render the page

scale did not increase resolution for me. Had to solve it with JS -
https://github.com/niklasvh/html2canvas/issues/379

Any luck guys?

transform: scale(2, 2); is not the solution for dygraph.js either

@premerddyn, see my solution in the linked issue.
It is working well, but requires enlargement before screenshot.
If my comment isn't clear I'll add more explanation

well what i had done is make a twice size div and made it visibility collapse and every content i had in here i posted to that div and took a screenshot.That way no image clarity is loss and i tweaked some font size code to make it work.I get this working fine.But my problem is with text-stroke and multiline text-background.

scaling by 2 works for me, however, I find that the rendering is limited by the window resolution/size. If the scaled div is wider than the window, then part of it will be cut off

so, is there no way to capture canvases larger than the screen?

Ah, from this thread:

var h = $(element)[0].ownerDocument.defaultView.innerHeight;
    $(element)[0].ownerDocument.defaultView.innerHeight = $(element).height();
    html2canvas($(element)).then(function(canvas) {
        $(element)[0].ownerDocument.defaultView.innerHeight = h;
        //Do whatever you want with your canvas
    }

https://jsfiddle.net/enjoythedaycsk/9L966sdd/1/

I tried to achieve high resolution thing in this example but didn't get that...

Click on download pngx2 button..

Is it possible to do operations on backend like when button is clicked canvas turns into twice its size and then pic is captured and then again canvas is taken back to regular size..

Sure, you could do that. I trigger a canvas of the size I want using the
code provided. I found that getting the value can be inaccurate, so I just
set the width/height directly.

On Saturday, May 7, 2016, enjoytheday [email protected] wrote:

https://jsfiddle.net/enjoythedaycsk/9L966sdd/1/

I tried to achieve high resolution thing in this example but didn't get
that...

Click on download pngx2 button..

Is it possible to do operations on backend like when button is clicked
canvas turns into twice its size and then pic is captured and then again
canvas is taken back to regular size..


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/niklasvh/html2canvas/issues/241#issuecomment-217634634

The World's Longest Ongoing Illustration
ForeverScape.com http://www.foreverscape.com/ | @foreverscape
https://twitter.com/foreverscape | On Github
https://github.com/vance/foreverscapecore | In the News
http://www.foreverscape.com/art/reviews/

@vance can you please set this this in jsfiddle example?

https://jsfiddle.net/enjoythedaycsk/9L966sdd/1/

I tried but its not being set by me.

You can edit it completely or can create new one.

It will be helpful to many :dancer:

I tried to mock it up quickly but didn't have time to fix the test div. Capturing something with transform:scale() doesn't do anything because the internal height of the div is _NOT_ affected. That's why it's a transform. It's w/h properties are unchanged (internally), which you can test by getting getBoundingClientRect(). It's width/height only _actually_ change when viewed in the context of the parent. You have to grab the container div after it's scaled.

https://jsfiddle.net/jano9ao4/1/

I face a same problem, is there any workable solution?ヾ(´・ ・`。)ノ"

I was able to get it to work, to capture elements larger than the window. Just remember, you can't get a "larger" image simply from a transformed element, because (to itself), it still has the same dimensions.

I had to do mine in an iframe and send the base64 data back as a message...because doing the following BREAKS the window resize event.

Again with comments:

   //store the original size
    var h = $(element)[0].ownerDocument.defaultView.innerHeight;
    var w = $(element)[0].ownerDocument.defaultView.innerWidth;

   //set the document to the element's size
    $(element)[0].ownerDocument.defaultView.innerHeight = $(element).height();
    $(element)[0].ownerDocument.defaultView.innerWidth = $(element).width();

    html2canvas($(element)).then(function(canvas) {
        //restore the document size
        $(element)[0].ownerDocument.defaultView.innerHeight = h;
        $(element)[0].ownerDocument.defaultView.innerWidth = w;
        //Do whatever you want with your canvas
    }

I wrote the following function to easily get a higher-DPI screenshot from an HTML element using html2canvas.

  • if the height or width is constrained (e.g. there is a fixed body width), the constraints must be removed during processing - the source element must be able to grow up to the desired scale
  • srcEl should be an existing element
  • destIMG should be an existing (empty) image element
  • dpi should be multiples of 96
var makeHighResScreenshot = function(srcEl, destIMG, dpi) {
    var scaleFactor = Math.floor(dpi / 96);
    // Save original size of element
    var originalWidth = srcEl.offsetWidth;
    var originalHeight = srcEl.offsetHeight;
    // Save original document size
    var originalBodyWidth = document.body.offsetWidth;
    var originalBodyHeight = document.body.offsetHeight;

    // Add style: transform: scale() to srcEl
    srcEl.style.transform = "scale(" + scaleFactor + ", " + scaleFactor + ")";
    srcEl.style.transformOrigin = "left top";

    // create wrapper for srcEl to add hardcoded height/width
    var srcElWrapper = document.createElement('div');
    srcElWrapper.id = srcEl.id + '-wrapper';
    srcElWrapper.style.height = originalHeight*scaleFactor + 'px';
    srcElWrapper.style.width = originalWidth*scaleFactor + 'px';
    // insert wrapper before srcEl in the DOM tree
    srcEl.parentNode.insertBefore(srcElWrapper, srcEl);
    // move srcEl into wrapper
    srcElWrapper.appendChild(srcEl);

    // Temporarily remove height/width constraints as necessary
    document.body.style.width = originalBodyWidth*scaleFactor +"px";
    document.body.style.height = originalBodyHeight*scaleFactor +"px";

    window.scrollTo(0, 0); // html2canvas breaks when we're not at the top of the doc, see html2canvas#820
    html2canvas(srcElWrapper, {
        onrendered: function(canvas) {
            destIMG.src = canvas.toDataURL("image/png");
            srcElWrapper.style.display = "none";
            // Reset height/width constraints
            document.body.style.width = originalBodyWidth + "px";
            document.body.style.height = originalBodyHeight + "px";
        }
    });
};

Usage:

var src = document.getElementById("screenshot-source");
var img = document.getElementById("screenshot-img");
makeHighResScreenshot(src, img, 192); // DPI of 192 is 4x resolution (2x normal DPI for both width and height)

Did you find that doing this also breaks window.onresize event handlers? For this reason, I had to do all of this inside an iframe and post the result back using parent.window.postMessage(data) to return the contents. This only matters to me because it is a mobile App, and it is critical to have onresize fire.

@vance: In my case I don't need or use any of those things - I'm actually using this to work around a bug in an HTML-to-PDF renderer. I'd love to see a full example of your method, it seems more flexible.

I figured out another way to get a high resolution image that doesn't need to resize the body. However, it does have to absolutely position the source element due to a bug in html2canvas (#790, #820, #893, #922, etc). Based on @MisterLamb's retina code.

function takeHighResScreenshot(srcEl, destIMG, scaleFactor) {
    // Save original size of element
    var originalWidth = srcEl.offsetWidth;
    var originalHeight = srcEl.offsetHeight;
    // Force px size (no %, EMs, etc)
    srcEl.style.width = originalWidth + "px";
    srcEl.style.height = originalHeight + "px";

    // Position the element at the top left of the document because of bugs in html2canvas. The bug exists when supplying a custom canvas, and offsets the rendering on the custom canvas based on the offset of the source element on the page; thus the source element MUST be at 0, 0.
    // See html2canvas issues #790, #820, #893, #922
    srcEl.style.position = "absolute";
    srcEl.style.top = "0";
    srcEl.style.left = "0";

    // Create scaled canvas
    var scaledCanvas = document.createElement("canvas");
    scaledCanvas.width = originalWidth * scaleFactor;
    scaledCanvas.height = originalHeight * scaleFactor;
    scaledCanvas.style.width = originalWidth + "px";
    scaledCanvas.style.height = originalHeight + "px";
    var scaledContext = scaledCanvas.getContext("2d");
    scaledContext.scale(scaleFactor, scaleFactor);

    html2canvas(srcEl, { canvas: scaledCanvas })
    .then(function(canvas) {
        destIMG.src = canvas.toDataURL("image/png");
        srcEl.style.display = "none";
    });
};

Usage:

var src = document.getElementById("screenshot-src");
var img = document.getElementById("screenshot-img");
takeHighResScreenshot(src, img, 2); // This time we provide desired scale factor directly, no more messing with DPI

EDIT: Reduced hackiness using absolute positioning instead of actually moving the element and adjusting margins, thanks to @jason-o-matic for the suggestion.

this works with the newest version(0.5.0-alpha). but not 0.4.1

if you wanna solve this issue in 0.4.1, you have to play around with the canvas size.

Just a quick note for anyone using @airdrummingfool 's fix (which works great)...

You cannot have any "relative" elements wrapping the element you wish to screen dump no matter how far up the xtree they are. They need to be switched to static for the duration of screendump so the element you want actually appears at 0,0 relative to the window, not a surrounding DIV.

It took me several hours to work this out so I hope this helps someone avoid the same problems.

Good Afternoon guys,
does anybody have a jsfiddle of @airdrummingfool solution, I am trying to implement it in my project with no luck. A working example would be great for me to understand how this works and would help me very much in trying to implement it in my project.

Thankyou very much for any assistance that can be provided.

Hi everyone! I'm trying to use @airdrummingfool solution. But I get one annoying error. Inside the element I want to get the image from, there is a element and when doing the procedure, the img element goes blank and the src is ignored. Do you know how can I solve this? Has anyone face this issue before with html2canvas?

Thanks in advance to this thread! It's saving me!! :D

EDIT: I'm also getting only half of the image rendered. But resolution looks perfect xD

Fixed the image problem!! The useCORS wasn't enabled! But I'm still getting only half the image rendered.

Great! The half-image might be due to the off-canvas rendering issue. I've also made a pull request to add resolution/scaling to html2canvas, you may find it easier to use than the @airdrummingfool solution.

Until those get merged in to html2canvas, you can get my custom build with both of those and a few other bugfixes here.

Hi @eKoopmans. Thanks for your answer. I just managed to fix mine by multiplying the height by 2. But, I think I'm getting a bigger image with white spaces above and below... so... I'm gonna try yours and report back in a few minutes!

OM(F)G @eKoopmans .. Your's worked out of the box. Thanks a lot man. That pull request... they should just accept it now. There are A LOT of people wanting this dpi option for html2canvas.

Closing in favor of #1087

@airdrummingfool ... Thank you. That works perfect.

latest version of html2canvas provides you with an option of scaling. Works really well.

html2canvas(element, {
scale: 2
});

For multiple page pdf rendering from html and image content, setting scale: 1 might fix the resolution issue and at the same time avoid images exceeding the pdf border.

I think this helps, i used html2canvas

downloadpdf() {
var doc = new jsPDF({
format: "a4"
});

html2canvas(document.getElementById("pdf-doc"), {
scale: "5"
}).then(canvas => {
this.imgFile = canvas;
doc.addImage(this.imgFile, "JPEG", 5, 5, 200, 285);
doc.save("filename" + ".pdf");
});
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

anthonymejia picture anthonymejia  ·  4Comments

rrutkows picture rrutkows  ·  4Comments

stevencherry1 picture stevencherry1  ·  3Comments

dking3876 picture dking3876  ·  4Comments

AlphaDu picture AlphaDu  ·  4Comments