[javascript] Capture HTML Canvas as gif/jpg/png/pdf?

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.

This question is related to javascript html canvas export png

The answer is


The simple answer is just to take the blob of it and set the img src to a new object URL of that blob, then add that image to a PDF using some library, like

_x000D_
_x000D_
var ok = document.createElement("canvas")
ok.width = 400
ok.height = 140
var ctx = ok.getContext("2d");
for(let k = 0; k < ok.height; k++) 
  (
    k 
    % 
    Math.floor(
      (
        Math.random()
      ) *
      10
    )
    == 
    0
  ) && (y => {
    for(var i = 0; i < ok.width; i++) {
      if(i % 25 == 0) {
        ctx.globalAlpha = Math.random()
        ctx.fillStyle = (
          "rgb(" + 
          Math.random() * 255 + "," +
          Math.random() * 255 + "," +
          Math.random() * 255 + ")"
        );

        (wdth =>
          ctx.fillRect(
            Math.sin(
              i * Math.PI / 180
            ) * 
              Math.random() *
              ok.width,
            Math.cos(
              i * Math.PI / 180,
            ) * wdth + y,
            wdth,
            wdth
          )
        )(15)
      }
    }
  })(k)

ok.toBlob(blob => {
  k.src = URL.createObjectURL(blob)
})
_x000D_
<img id=k>
_x000D_
_x000D_
_x000D_

Alternatively, if you wanted to work with low-level byte data, you can get the raw bytes of the canvas, then, depending on the file spec, write the raw image data into the necessary bytes of the data. you just need to call ctx.getImageData(0, 0, ctx.canvas.widht, ctx.canvas.height) to get the raw image data, then based on the file specification, write it to that


Another interesting solution is PhantomJS. It's a headless WebKit scriptable with JavaScript or CoffeeScript.

One of the use case is screen capture : you can programmatically capture web contents, including SVG and Canvas and/or Create web site screenshots with thumbnail preview.

The best entry point is the screen capture wiki page.

Here is a good example for polar clock (from RaphaelJS):

>phantomjs rasterize.js http://raphaeljs.com/polar-clock.html clock.png

Do you want to render a page to a PDF ?

> phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf

On some versions of Chrome, you can:

  1. Use the draw image function ctx.drawImage(image1, 0, 0, w, h);
  2. Right-click on the canvas

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.


If you are using jQuery, which quite a lot of people do, then you would implement the accepted answer like so:

var canvas = $("#mycanvas")[0];
var img = canvas.toDataURL("image/png");

$("#elememt-to-write-to").html('<img src="'+img+'"/>');

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

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.


if you want to emebed the canvas you can use this snippet

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id=canvas width=200 height=200></canvas>
    <iframe id='img' width=200 height=200></iframe>
    <script>
        window.onload = function() {
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            context.fillStyle = "green";
            context.fillRect(50, 50, 100, 100);
            document.getElementById('img').src = canvas.toDataURL("image/jpeg");
            console.log(canvas.toDataURL("image/jpeg"));
        }
    </script>
</body>
</html>

You can use jspdf to capture a canvas into an image or pdf like this:

var imgData = canvas.toDataURL('image/png');              
var doc = new jsPDF('p', 'mm');
doc.addImage(imgData, 'PNG', 10, 10);
doc.save('sample-file.pdf');

More info: https://github.com/MrRio/jsPDF


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


Here is some help if you do the download through a server (this way you can name/convert/post-process/etc your file):

-Post data using toDataURL

-Set the headers

$filename = "test.jpg"; //or png
header('Content-Description: File Transfer');
if($msie = !strstr($_SERVER["HTTP_USER_AGENT"],"MSIE")==false)      
  header("Content-type: application/force-download");else       
  header("Content-type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"$filename\"");   
header("Content-Transfer-Encoding: binary"); 
header("Expires: 0"); header("Cache-Control: must-revalidate"); 
header("Pragma: public");

-create image

$data = $_POST['data'];
$img = imagecreatefromstring(base64_decode(substr($data,strpos($data,',')+1)));

-export image as JPEG

$width = imagesx($img);
$height = imagesy($img);
$output = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($output,  255, 255, 255);
imagefilledrectangle($output, 0, 0, $width, $height, $white);
imagecopy($output, $img, 0, 0, 0, 0, $width, $height);
imagejpeg($output);
exit();

-or as transparent PNG

imagesavealpha($img, true);
imagepng($img);
die($img);

This is the other way, without strings although I don't really know if it's faster or not. Instead of toDataURL (as all questions here propose). In my case want to prevent dataUrl/base64 since I need a Array buffer or view. So the other method in HTMLCanvasElement is toBlob. (TypeScript function):

    export function canvasToArrayBuffer(canvas: HTMLCanvasElement, mime: string): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => canvas.toBlob(async (d) => {
    if (d) {
      const r = new FileReader();
      r.addEventListener('loadend', e => {
        const ab = r.result;
        if (ab) {
          resolve(ab as ArrayBuffer);
        }
        else {
           reject(new Error('Expected FileReader result'));
        }
      }); r.addEventListener('error', e => {
        reject(e)
      });
      r.readAsArrayBuffer(d);
    }
    else {
      reject(new Error('Expected toBlob() to be defined'));
    }
  }, mime));
}

Another advantage of blobs is you can create ObjectUrls to represent data as files, similar to HTMLInputFile's 'files' member. More info:

https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/toBlob


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to canvas

How to make canvas responsive How to fill the whole canvas with specific color? Use HTML5 to resize an image before upload Convert canvas to PDF Scaling an image to fit on canvas Split string in JavaScript and detect line break Get distance between two points in canvas canvas.toDataURL() SecurityError Converting Chart.js canvas chart to image using .toDataUrl() results in blank image Chart.js canvas resize

Examples related to export

Export multiple classes in ES6 modules Why Is `Export Default Const` invalid? How to properly export an ES6 class in Node 4? ES6 export all values from object Export a list into a CSV or TXT file in R How to export database schema in Oracle to a dump file Excel VBA to Export Selected Sheets to PDF How to export all data from table to an insertable sql format? Export pictures from excel file into jpg using VBA -bash: export: `=': not a valid identifier

Examples related to png

Convert UIImage to NSData and convert back to UIImage in Swift? Importing PNG files into Numpy? What is difference between png8 and png24 How to change the background colour's opacity in CSS Darkening an image with CSS (In any shape) Android splash screen image sizes to fit all devices How to convert a SVG to a PNG with ImageMagick? Convert RGBA PNG to RGB with PIL Set transparent background using ImageMagick and commandline prompt Converting a byte array to PNG/JPG