Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to increase resolution of the image generated via toDataURL #241

Closed
tankchintan opened this issue Jul 9, 2013 · 58 comments
Closed

Way to increase resolution of the image generated via toDataURL #241

tankchintan opened this issue Jul 9, 2013 · 58 comments

Comments

@tankchintan
Copy link

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.

@jordanaustin
Copy link

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?

@tankchintan
Copy link
Author

@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.

@brcontainer
Copy link
Contributor

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)?

@tankchintan
Copy link
Author

@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

@brcontainer
Copy link
Contributor

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

@panthar1
Copy link

panthar1 commented Aug 7, 2013

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

@tankchintan
Copy link
Author

@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");

@brcontainer
Copy link
Contributor

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

@LacioDrom
Copy link

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

@tankchintan
Copy link
Author

@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! :)

@brcontainer
Copy link
Contributor

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.

@panthar1
Copy link

panthar1 commented Aug 9, 2013

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.

@kylemclaren
Copy link

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.

@nookalalakshmi
Copy link

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.

@lavakumart
Copy link

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.

@IvoPereira
Copy link

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

@mudcube
Copy link

mudcube commented Dec 23, 2014

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)"

@Ajaxy
Copy link

Ajaxy commented Jan 29, 2015

@mudcube worked out partially for me

@syammohanmp
Copy link

syammohanmp commented Feb 12, 2015

@brcontainer it's working fine for me

@mfkj
Copy link

mfkj commented Mar 20, 2015

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

@jpatel3
Copy link

jpatel3 commented Apr 23, 2015

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

@ejlocop
Copy link

ejlocop commented May 4, 2015

any solution found ?

@Ajaxy
Copy link

Ajaxy commented May 4, 2015

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

@matiasinsaurralde
Copy link

Can you provide more details?

@Ajaxy
Copy link

Ajaxy commented May 22, 2015

@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.

@ejlocop
Copy link

ejlocop commented Jun 16, 2015

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

@yonatanmn
Copy link

scale did not increase resolution for me. Had to solve it with JS -
#379

@premreddyn
Copy link

Any luck guys?

@mathiasleroy
Copy link

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

@yonatanmn
Copy link

@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

@vance
Copy link

vance commented Apr 30, 2016

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
    }

@enjoytheday
Copy link

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..

@vance
Copy link

vance commented May 11, 2016

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 notifications@github.com 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
#241 (comment)

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/

@enjoytheday
Copy link

@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 💃

@vance
Copy link

vance commented May 19, 2016

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/

@AndyBoat
Copy link

AndyBoat commented Sep 5, 2016

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

@vance
Copy link

vance commented Sep 5, 2016

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
    }

@airdrummingfool
Copy link

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)

@vance
Copy link

vance commented Sep 14, 2016

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.

@airdrummingfool
Copy link

@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.

@airdrummingfool
Copy link

airdrummingfool commented Sep 16, 2016

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.

@Nomia
Copy link

Nomia commented Oct 31, 2016

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.

@tregenza
Copy link

tregenza commented Nov 6, 2016

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.

@Jacksta66
Copy link

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.

@mora260
Copy link

mora260 commented May 25, 2017

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

@mora260
Copy link

mora260 commented May 25, 2017

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

@eKoopmans
Copy link
Contributor

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.

@mora260
Copy link

mora260 commented May 25, 2017

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!

@mora260
Copy link

mora260 commented May 25, 2017

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.

@niklasvh
Copy link
Owner

Closing in favor of #1087

@venuvadde
Copy link

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

@shakercs
Copy link

shakercs commented Jun 1, 2019

@snowPu
Copy link

snowPu commented Aug 16, 2019

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

html2canvas(element, {
scale: 2
});

@jsrpy
Copy link

jsrpy commented Sep 23, 2019

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.

@aljeesjose
Copy link

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");
});
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests