Capture HTML Canvas as gif/jpg/png/pdf?

703,788

Solution 1

Original answer was specific to a similar question. This has been revised:

const canvas = document.getElementById('mycanvas')
const img    = canvas.toDataURL('image/png')

with the value in IMG you can write it out as a new Image like so:

document.getElementById('existing-image-id').src = img

or

document.write('<img src="'+img+'"/>');

Solution 2

HTML5 provides Canvas.toDataURL(mimetype) which is implemented in Opera, Firefox, and Safari 4 beta. There are a number of security restrictions, however (mostly to do with drawing content from another origin onto the canvas).

So you don't need an additional library.

e.g.

 <canvas id=canvas width=200 height=200></canvas>
 <script>
      window.onload = function() {
          var canvas = document.getElementById("canvas");
          var context = canvas.getContext("2d");
          context.fillStyle = "green";
          context.fillRect(50, 50, 100, 100);
          // no argument defaults to image/png; image/jpeg, etc also work on some
          // implementations -- image/png is the only one that must be supported per spec.
          window.location = canvas.toDataURL("image/png");
      }
 </script>

Theoretically this should create and then navigate to an image with a green square in the middle of it, but I haven't tested.

Solution 3

I thought I'd extend the scope of this question a bit, with some useful tidbits on the matter.

In order to get the canvas as an image, you should do the following:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png");

You can use this to write the image to the page:

document.write('<img src="'+image+'"/>');

Where "image/png" is a mime type (png is the only one that must be supported). If you would like an array of the supported types you can do something along the lines of this:

var imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/tiff']; //Extend as necessary 
var acceptedMimes = new Array();
for(i = 0; i < imageMimes.length; i++) {
    if(canvas.toDataURL(imageMimes[i]).search(imageMimes[i])>=0) {
        acceptedMimes[acceptedMimes.length] = imageMimes[i];
    }
}

You only need to run this once per page - it should never change through a page's lifecycle.

If you wish to make the user download the file as it is saved you can do the following:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); //Convert image to 'octet-stream' (Just a download, really)
window.location.href = image;

If you're using that with different mime types, be sure to change both instances of image/png, but not the image/octet-stream. It is also worth mentioning that if you use any cross-domain resources in rendering your canvas, you will encounter a security error when you try to use the toDataUrl method.

Solution 4

function exportCanvasAsPNG(id, fileName) {

    var canvasElement = document.getElementById(id);

    var MIME_TYPE = "image/png";

    var imgURL = canvasElement.toDataURL(MIME_TYPE);

    var dlLink = document.createElement('a');
    dlLink.download = fileName;
    dlLink.href = imgURL;
    dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');

    document.body.appendChild(dlLink);
    dlLink.click();
    document.body.removeChild(dlLink);
}

Solution 5

I would use "wkhtmltopdf". It just work great. It uses webkit engine (used in Chrome, Safari, etc.), and it is very easy to use:

wkhtmltopdf stackoverflow.com/questions/923885/ this_question.pdf

That's it!

Try it

Share:
703,788
nosid
Author by

nosid

Xpenser Founder, Former Yahoo, startup guy.

Updated on July 08, 2022

Comments

  • nosid
    nosid almost 2 years

    Is it possible to capture or print what's displayed in an html canvas as an image or pdf?

    I'd like to generate an image via canvas, and be able to generate a png from that image.

  • nosid
    nosid over 13 years
    Thanks michael, looks like getContext together with toDataURL would do it
  • Surya
    Surya almost 13 years
    one more question, how can I save the image I got in this tag to server. Any guess??
  • Erik Karulf
    Erik Karulf almost 13 years
    @Surya - In the example above, I would use AJAX to POST the img variable to the server. Alternatively, you could set the value of a hidden field in a form.
  • alemomo
    alemomo about 12 years
    I'm in the wkhtmltopdf camp, too. We've been using it for archiving and its AMAZING.
  • jnthnclrk
    jnthnclrk over 11 years
    Is this technique suitable for making a screenshot of a web page?
  • llamerr
    llamerr over 11 years
    @jnthnclrk I don't think so, since it's only saving canvas (until all your page is a canvas)
  • llamerr
    llamerr over 11 years
    @jnthnclrk you can take a look for screenshot making at screengrab addon for firefox sources (and seems for chrome too?) - code.google.com/p/screengrab/source/browse/trunk/src/chrome/‌​… maybe it will help
  • chinna_82
    chinna_82 almost 11 years
    Where the image will be saved. Location in my local?
  • johndodo
    johndodo over 10 years
    +1: PhantomJS is simple, well documented and well thought-out system, perfect for this job. It allows much more than just grabbing a canvas too - for instance, you can modify the page or part of it (through JS) before grabbing so make it look just the way you want it. Perfect!
  • So4ne
    So4ne over 10 years
    With your solution for downloading the file, I must choose the software I want to use, it's a bit unconvenient... Is there a way to re-replace the mime as png once downloaded?
  • gauti
    gauti over 10 years
    But if i use var img = canvas.toDataURL("image/jpeg"); am getting the background as complete black. How to rectify that
  • donohoe
    donohoe over 10 years
    @Gauti Likely a browser issue. JPEG isn't supported by all (should work on Chrome/Firefox though)
  • meiamsome
    meiamsome over 10 years
    @So4ne I don't think so, it has to be an image/octet-stream to prompt the user for a download. If you get rid of that line, you'll end up with the page redirecting to the image. I would love to know if someone else knows a way to do this nicely, though.
  • meiamsome
    meiamsome over 10 years
    @Gauti It's likely your background is the RGBA colour (0,0,0,0) i.e. completely transparent black. JPEG does not support transparency and so this is converted to just be black I think.
  • Kai Carver
    Kai Carver about 10 years
    the image will be displayed as an image in your browser. You can then save it to disk or whatever. Here's a quick and dirty generic "Canvas2PNG" bookmarklet that converts the first canvas in the page to PNG and displays it in the browser in a new window: javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/‌​png"))
  • confile
    confile almost 10 years
    @donohoe This is not working on IOS7 when the canvas contains an SVG image.
  • donohoe
    donohoe almost 10 years
    Oh come on. I answered this in 2009. What do you expect?
  • Alan Wells
    Alan Wells almost 10 years
    Instead of using document.write() you can use: document.getElementById('theID_of_a_DIV_to_Wrap_IMG_In').inn‌​erHTML = "<img src='" + img + "'>";
  • j6m8
    j6m8 almost 10 years
    Do note that the only usage of jQuery here is the selection of the canvas. .toDataURL is native JS.
  • Ramesh S
    Ramesh S over 9 years
    I have save issue some one can help me see this link :stackoverflow.com/questions/25131763/…
  • Ax3l
    Ax3l over 9 years
    using target="_blank" on <a> link and .click() it should work, too to trigger the download (tested with FF data-urls and download="filename" for text/csv and text/plain)
  • jahu
    jahu about 9 years
    If the image is a few MB in size, prepare to crash your browser (I did that a while back in FireFox).
  • Naeel Maqsudov
    Naeel Maqsudov about 9 years
    Pure (100%) jQuery solution is the following: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png‌​')).appendTo($('#ele‌​ment-to-write-to').e‌​mpty()); Exactly one line.
  • ElectroBit
    ElectroBit about 9 years
    Works for me right now, but somehow not a year ago or so. I knew about this before, but it didn't work before.
  • msciwoj
    msciwoj about 9 years
    doesn't work for me - for png I get transparent box image (no visible data), for jpeg the same as reported above - all black. Any ideas?
  • nick
    nick almost 9 years
    @donohoe actually you answered it in August 2010 :)
  • Chief Alchemist
    Chief Alchemist almost 9 years
    This is great. Thanks! But what if I want to save to server and not local? Will a form file input accept the img src as something that is uploadable?
  • Chief Alchemist
    Chief Alchemist almost 9 years
    Oops. Just found the answer. Leaving the previous question in case someone else is looking as well stackoverflow.com/questions/13198131/…
  • Razi Syed
    Razi Syed over 8 years
    This works except on Mac Safari when there is an embedded <image> tag. Safari ignores the image, whether the image is base64 or a link. Has anyone got in to this issue and resolved it? Would really like to know.
  • Greg0ry
    Greg0ry over 8 years
    I would only add this: be careful when you scale your image. If you let user manipulate scaled image (i.e. you only show small tile when dropping on google map) you probably want to keep original (usually much bigger) image in hidden img and use this as source you feed to canvas. Othervise you will get qyality of your image reduced since drawing img on canvas will take whatever size of your img.
  • Mentalist
    Mentalist over 8 years
    How can this be used to download multiple images?
  • Mentalist
    Mentalist over 8 years
    How could this be modified to render multiple images?
  • Oki Erie Rinaldi
    Oki Erie Rinaldi over 8 years
    what about saving image from svg (not canvas)?
  • nullpointer
    nullpointer about 8 years
    The saved file stays in .svg format. How to save it as png?
  • khaled  Dehia
    khaled Dehia over 7 years
    How to use WKHTMLtoPDF in page that required login info ? I am using Jsreport to convert to PDF but I capture my content with HTML2Canvas ,I have issue with sending the Canvas as parameter to JSreport
  • lepe
    lepe over 7 years
  • gman
    gman over 7 years
    It would use a lot less memory to do something like var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. The document.write code is making the data URL, them making a HTML string, then putting a copy of that string in the DOM, the browser then has to parse that HTML string, put another copy on the image element, then parse it again to turn the data URL into image data, then finally it can show the image. For a screen size image that's a huge amount of memory/copying/parsing. Just a suggestion
  • Jose Cherian
    Jose Cherian almost 7 years
    This is a nice solution except that it may not work on IE. Getting error "The data area passed to a system call is too small"
  • Ecker00
    Ecker00 over 6 years
    In Chrome it says "Network error", while in Firefox it works great. (On Linux)
  • Merc
    Merc almost 6 years
    PhantomJs is now obsolete
  • Juha Syrjälä
    Juha Syrjälä almost 6 years
    Data URIs have max length, so there is upper limit on the size of an image that you can put to a data url.
  • JED
    JED over 5 years
    @DilaGurung you need to do var img = canvas[0].toDataURL("image/png"); . See: stackoverflow.com/questions/8667458/todataurl-not-a-function
  • M. D. P
    M. D. P over 5 years
    if "/home/Desktop/dataset/" is my path and i want to save image as " image_1.jpg" , what changes i need to do --> ('<img src="'+img+'"/>'); ?? @donohoe
  • Umesh Patadiya
    Umesh Patadiya over 5 years
    is it possible to export canvas as video in format like mp4?
  • sc0ttj
    sc0ttj almost 4 years
    PhantomJS is not "obsolete" - it is unmaintained.... It still supports most ES6 stuff, and is still the only modern/decent headless browser that works on x86 and does not need compiling. Therefore it still the only [proper] headless browser that works on various embedded or lightweight distros/systems.
  • ClownCoder
    ClownCoder over 3 years
    This answer must be marked as the correct one and need to be upvoted. Thanks!
  • Vesper
    Vesper over 3 years
    @OkiErieRinaldi just make a canvas, draw that SVG over the canvas aaand... use this to grab the image just drawn.