814

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.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Parand
  • 102,950
  • 48
  • 151
  • 186
  • Here's a pythonic solution: http://stackoverflow.com/questions/19395649/python-pil-create-and-save-image-from-data-uri in addition to answer http://stackoverflow.com/a/3514404/529442 – Eugene Gr. Philippov May 23 '16 at 16:20
  • 1
    [HTMLCanvasElement/toDataURL#Examples](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL#Examples) – sam Oct 08 '16 at 22:10
  • Example here http://www.freakyjolly.com/convert-html-document-into-image-jpg-png-from-canvas/ – Code Spy Jun 08 '18 at 09:45
  • 2
    You might find canvas2image library useful for this: https://github.com/hongru/canvas2image – koders Dec 29 '18 at 01:17
  • 2
    If someone is looking for an answer related to React, I wrote two tutorials about it yesterday: [React Component to Image](https://www.robinwieruch.de/react-component-to-image) and [React Component to PDF](https://www.robinwieruch.de/react-component-to-pdf). – Robin Wieruch Sep 30 '21 at 15:35

16 Answers16

836

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+'"/>');
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
donohoe
  • 13,867
  • 4
  • 37
  • 59
  • Thanks michael, looks like getContext together with toDataURL would do it – Parand Aug 18 '10 at 18:08
  • 21
    one more question, how can I save the image I got in this tag to server. Any guess?? – Surya Jun 27 '11 at 08:41
  • 2
    @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. – Erik Karulf Jul 13 '11 at 08:36
  • Is this technique suitable for making a screenshot of a web page? – jnthnclrk Oct 08 '12 at 18:29
  • 1
    @jnthnclrk I don't think so, since it's only saving canvas (until all your page is a canvas) – llamerr Oct 23 '12 at 13:13
  • @jnthnclrk you can take a look for screenshot making at screengrab addon for firefox sources (and seems for chrome too?) - http://code.google.com/p/screengrab/source/browse/trunk/src/chrome/content/NsUtils.js maybe it will help – llamerr Oct 23 '12 at 13:21
  • 8
    But if i use var img = canvas.toDataURL("image/jpeg"); am getting the background as complete black. How to rectify that – gauti Dec 23 '13 at 14:55
  • @Gauti Likely a browser issue. JPEG isn't supported by all (should work on Chrome/Firefox though) – donohoe Dec 23 '13 at 16:23
  • 3
    @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. – meiamsome Dec 26 '13 at 18:03
  • @donohoe This is not working on IOS7 when the canvas contains an SVG image. – Michael May 21 '14 at 13:32
  • 227
    Oh come on. I answered this in 2009. What do you expect? – donohoe May 21 '14 at 16:48
  • 1
    Instead of using `document.write()` you can use: `document.getElementById('theID_of_a_DIV_to_Wrap_IMG_In').innerHTML = "";` – Alan Wells Jul 04 '14 at 01:44
  • Works for me right now, but somehow not a year ago or so. I knew about this before, but it didn't work before. – ElectroBit May 03 '15 at 18:27
  • 2
    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? – msciwoj May 09 '15 at 15:45
  • 43
    @donohoe actually you answered it in August 2010 :) – nick May 21 '15 at 21:59
  • This works **except** on Mac Safari when there is an embedded 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. – Razi Syed Aug 17 '15 at 22:00
  • 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. – Greg0ry Sep 18 '15 at 15:34
  • 1
    what about saving image from svg (not canvas)? – Oki Erie Rinaldi Nov 18 '15 at 03:08
  • 21
    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 – gman Jan 25 '17 at 08:26
  • @DilaGurung you need to do `var img = canvas[0].toDataURL("image/png");` . See: https://stackoverflow.com/questions/8667458/todataurl-not-a-function – JED Oct 02 '18 at 18:15
  • if "/home/Desktop/dataset/" is my path and i want to save image as " image_1.jpg" , what changes i need to do --> (''); ?? @donohoe – M. D. P Dec 05 '18 at 11:17
  • @OkiErieRinaldi just make a canvas, draw that SVG over the canvas aaand... use this to grab the image just drawn. – Vesper Dec 10 '20 at 07:19
121

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.

ballade4op52
  • 2,142
  • 5
  • 27
  • 42
olliej
  • 35,755
  • 9
  • 58
  • 55
  • 2
    Where the image will be saved. Location in my local? – chinna_82 Jul 17 '13 at 03:30
  • 6
    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"))` – Kai Carver Apr 02 '14 at 12:10
  • If the image is a few MB in size, prepare to crash your browser (I did that a while back in FireFox). – jahu Mar 14 '15 at 14:16
  • 1
    How could this be modified to render multiple images? – Mentalist Oct 15 '15 at 11:56
  • Data URIs have max length, so there is upper limit on the size of an image that you can put to a data url. – Juha Syrjälä Jun 14 '18 at 04:24
48

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.

meiamsome
  • 2,876
  • 1
  • 17
  • 19
46
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);
}
david.barkhuizen
  • 5,239
  • 4
  • 36
  • 38
19

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

ballade4op52
  • 2,142
  • 5
  • 27
  • 42
lepe
  • 24,677
  • 9
  • 99
  • 108
  • 1
    I'm in the wkhtmltopdf camp, too. We've been using it for archiving and its AMAZING. – Daniel Szabo Mar 30 '12 at 15:06
  • 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 – khaled Dehia Jan 02 '17 at 00:02
  • @khaledDehia check: http://stackoverflow.com/questions/10287386/generate-pdf-behind-authentication-wall – lepe Jan 02 '17 at 02:30
15

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);
Community
  • 1
  • 1
12

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

Nayuki
  • 17,911
  • 6
  • 53
  • 80
cancerbero
  • 6,799
  • 1
  • 32
  • 24
8

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
Cybermaxs
  • 24,378
  • 8
  • 83
  • 112
  • 2
    +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! – johndodo Sep 18 '13 at 06:57
  • 1
    PhantomJs is now obsolete – Merc May 21 '18 at 06:46
  • 1
    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. – sc0ttj Aug 05 '20 at 10:31
4

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+'"/>');
ballade4op52
  • 2,142
  • 5
  • 27
  • 42
Pattle
  • 5,983
  • 8
  • 33
  • 56
  • 13
    Do note that the *only* usage of jQuery here is the selection of the canvas. `.toDataURL` is native JS. – j6m8 Jul 09 '14 at 00:32
  • I have save issue some one can help me see this link :http://stackoverflow.com/questions/25131763/how-to-save-the-canvas-text-image-in-gallery?noredirect=1#comment39171750_25131763 – Ramesh Somalagari Aug 11 '14 at 16:22
  • 2
    Pure (100%) jQuery solution is the following: `$('').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());` Exactly one line. – Naeel Maqsudov Mar 21 '15 at 05:57
2

The key point is

canvas.toDataURL(type, quality)


And I want to provide an example for someone like me who wants to save SVG to PNG(also can add some text if you wish), which may be from an Online source or font-awesome icon, etc.

Example

100% javascript and no other 3-rd library.

<script>
  (() => {
    window.onload = () => {
      // Test 1: SVG from Online
      const canvas = new Canvas(650, 500)
      // canvas.DrawGrid() // If you want to show grid, you can use it.
      const svg2img = new SVG2IMG(canvas.canvas, "https://upload.wikimedia.org/wikipedia/commons/b/bd/Test.svg")
      svg2img.AddText("Hello", 100, 250, {mode: "fill", color: "yellow", alpha: 0.8})
      svg2img.AddText("world", 200, 250, {mode: "stroke", color: "red"})
      svg2img.AddText("!", 280, 250, {color: "#f700ff", size: "72px"})
      svg2img.Build("Test.png")

      // Test 2: URI.data
      const canvas2 = new Canvas(180, 180)
      const uriData = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc21pbGUtd2luayBmYS13LTE2IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhciIgZGF0YS1pY29uPSJzbWlsZS13aW5rIiByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQ5NiA1MTIiIGRhdGEtZmEtaTJzdmc9IiI+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMjQ4IDhDMTExIDggMCAxMTkgMCAyNTZzMTExIDI0OCAyNDggMjQ4IDI0OC0xMTEgMjQ4LTI0OFMzODUgOCAyNDggOHptMCA0NDhjLTExMC4zIDAtMjAwLTg5LjctMjAwLTIwMFMxMzcuNyA1NiAyNDggNTZzMjAwIDg5LjcgMjAwIDIwMC04OS43IDIwMC0yMDAgMjAwem0xMTcuOC0xNDYuNGMtMTAuMi04LjUtMjUuMy03LjEtMzMuOCAzLjEtMjAuOCAyNS01MS41IDM5LjQtODQgMzkuNHMtNjMuMi0xNC4zLTg0LTM5LjRjLTguNS0xMC4yLTIzLjctMTEuNS0zMy44LTMuMS0xMC4yIDguNS0xMS41IDIzLjYtMy4xIDMzLjggMzAgMzYgNzQuMSA1Ni42IDEyMC45IDU2LjZzOTAuOS0yMC42IDEyMC45LTU2LjZjOC41LTEwLjIgNy4xLTI1LjMtMy4xLTMzLjh6TTE2OCAyNDBjMTcuNyAwIDMyLTE0LjMgMzItMzJzLTE0LjMtMzItMzItMzItMzIgMTQuMy0zMiAzMiAxNC4zIDMyIDMyIDMyem0xNjAtNjBjLTI1LjcgMC01NS45IDE2LjktNTkuOSA0Mi4xLTEuNyAxMS4yIDExLjUgMTguMiAxOS44IDEwLjhsOS41LTguNWMxNC44LTEzLjIgNDYuMi0xMy4yIDYxIDBsOS41IDguNWM4LjUgNy40IDIxLjYuMyAxOS44LTEwLjgtMy44LTI1LjItMzQtNDIuMS01OS43LTQyLjF6Ij48L3BhdGg+PC9zdmc+"
      const svg2img2 = new SVG2IMG(canvas2.canvas, uriData)
      svg2img2.Build("SmileWink.png")

      // Test 3: Exists SVG
      ImportFontAwesome()
      const range = document.createRange()
      const fragSmile = range.createContextualFragment(`<i class="far fa-smile" style="background-color:black;color:yellow"></i>`)
      document.querySelector(`body`).append(fragSmile)

      // use MutationObserver wait the fontawesome convert ``<i class="far fa-smile"></i>`` to SVG. If you write the element in the HTML, then you can skip this hassle way.
      const observer = new MutationObserver((mutationRecordList, observer) => {
        for (const mutation of mutationRecordList) {
          switch (mutation.type) {
            case "childList":
              const targetSVG = mutation.target.querySelector(`svg`)
              if (targetSVG !== null) {
                const canvas3 = new Canvas(64, 64) //  Focus here. The part of the observer is not important.
                const svg2img3 = new SVG2IMG(canvas3.canvas, SVG2IMG.Convert2URIData(targetSVG))
                svg2img3.Build("Smile.png")
                targetSVG.remove() // This SVG is created by font-awesome, and it's an extra element. I don't want to see it.
                observer.disconnect()
                return
              }
          }
        }
      })
      observer.observe(document.querySelector(`body`), {childList: true})
    }
  })()

  class SVG2IMG {
    /**
     * @param {HTMLCanvasElement} canvas
     * @param {string} src "http://.../xxx.svg"  or "data:image/svg+xml;base64,${base64}"
     * */
    constructor(canvas, src) {
      this.canvas = canvas;
      this.context = this.canvas.getContext("2d")
      this.src = src
      this.addTextList = []
    }

    /**
     * @param {HTMLElement} node
     * @param {string} mediaType: https://en.wikipedia.org/wiki/Media_type#Common_examples_%5B10%5D
     * @see https://en.wikipedia.org/wiki/List_of_URI_schemes
     * */
    static Convert2URIData(node, mediaType = 'data:image/svg+xml') {
      const base64 = btoa(node.outerHTML)
      return `${mediaType};base64,${base64}`
    }

    /**
     * @param {string} text
     * @param {int} x
     * @param {int} y
     * @param {"stroke"|"fill"} mode
     * @param {string} size, "30px"
     * @param {string} font, example: "Arial"
     * @param {string} color, example: "#3ae016" or "yellow"
     * @param {int} alpha, 0.0 (fully transparent) to 1.0 (fully opaque) // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors#transparency
     * */
    AddText(text, x, y, {mode = "fill", size = "32px", font = "Arial", color = "black", alpha = 1.0}) {
      const drawFunc = (text, x, y, mode, font) => {
        return () => {
          // https://www.w3schools.com/graphics/canvas_text.asp
          // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillText
          const context = this.context
          const originAlpha = context.globalAlpha
          context.globalAlpha = alpha
          context.font = `${size} ${font}`

          switch (mode) {
            case "fill":
              context.fillStyle = color
              context.fillText(text, x, y)
              break
            case "stroke":
              context.strokeStyle = color
              context.strokeText(text, x, y)
              break
            default:
              throw Error(`Unknown mode:${mode}`)
          }
          context.globalAlpha = originAlpha
        }
      }
      this.addTextList.push(drawFunc(text, x, y, mode, font))
    }

    /**
     * @description When the build is finished, you can click the filename to download the PNG or mouse enters to copy PNG to the clipboard.
     * */
    Build(filename = "download.png") {
      const img = new Image()
      img.src = this.src
      img.crossOrigin = "anonymous" // Fixes: Tainted canvases may not be exported

      img.onload = (event) => {
        this.context.drawImage(event.target, 0, 0)
        for (const drawTextFunc of this.addTextList) {
          drawTextFunc()
        }

        // create a "a" node for download
        const a = document.createElement('a')
        document.querySelector('body').append(a)
        a.innerText = filename
        a.download = filename

        const quality = 1.0
        // a.target = "_blank"
        a.href = this.canvas.toDataURL("image/png", quality)
        a.append(this.canvas)
      }

      this.canvas.onmouseenter = (event) => {
        // set background to white. Otherwise, background-color is black.
        this.context.globalCompositeOperation = "destination-over" // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation // https://www.w3schools.com/tags/canvas_globalcompositeoperation.asp
        this.context.fillStyle = "rgb(255,255,255)"
        this.context.fillRect(0, 0, this.canvas.width, this.canvas.height)
        this.canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})])) // copy to clipboard
      }
    }
  }

  class Canvas {

    /**
     * @description for do something like that: ``<canvas width="" height=""></>canvas>``
     **/
    constructor(w, h) {
      const canvas = document.createElement("canvas")
      document.querySelector(`body`).append(canvas)
      this.canvas = canvas;
      [this.canvas.width, this.canvas.height] = [w, h]
    }

    /**
     * @description If your SVG is large, you may want to know which part is what you wanted.
     * */
    DrawGrid(step = 100) {
      const ctx = this.canvas.getContext('2d')
      const w = this.canvas.width
      const h = this.canvas.height

      // Draw the vertical line.
      ctx.beginPath();
      for (let x = 0; x <= w; x += step) {
        ctx.moveTo(x, 0);
        ctx.lineTo(x, h);
      }
      // set the color of the line
      ctx.strokeStyle = 'rgba(255,0,0, 0.5)'
      ctx.lineWidth = 1
      ctx.stroke();

      // Draw the horizontal line.
      ctx.beginPath();
      for (let y = 0; y <= h; y += step) {
        ctx.moveTo(0, y)
        ctx.lineTo(w, y)
      }
      ctx.strokeStyle = 'rgba(128, 128, 128, 0.5)'
      ctx.lineWidth = 5
      ctx.stroke()
    }
  }

  function ImportFontAwesome() {
    const range = document.createRange()
    const frag = range.createContextualFragment(`
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" integrity="sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/js/all.min.js" integrity="sha512-UwcC/iaz5ziHX7V6LjSKaXgCuRRqbTp1QHpbOJ4l1nw2/boCfZ2KlFIqBUA/uRVF0onbREnY9do8rM/uT/ilqw==" crossorigin="anonymous"/>
`)
    document.querySelector("head").append(frag)
  }
</script>

if you want to run on stackoverflow and move your mouse on the picture may get error

DOMException: The Clipboard API has been blocked because of a permissions policy applied to the current document

You can copy the code on your local machine and run it again, will be fine.

Carson
  • 6,105
  • 2
  • 37
  • 45
1

upload image from <canvas />:

async function canvasToBlob(canvas) {
  if (canvas.toBlob) {
    return new Promise(function (resolve) {
      canvas.toBlob(resolve)
    })
  } else {
    throw new Error('canvas.toBlob Invalid')
  }
}

await canvasToBlob(yourCanvasEl)
Junior Tour
  • 439
  • 7
  • 8
0

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
Peter
  • 373
  • 3
  • 10
0

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

ferralucho
  • 637
  • 7
  • 24
0

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

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)
})
<img id=k>

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

0

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>
MrAni
  • 23
  • 6
-1

Capture to a Gif (unpacked) is a chrome extension to record an HTML canvas to a GIF file

postprocessing: you will need to cut and compress the video (ffmpeg, kdenlive, ...)

why compress? the result will have a constant framerate, not the original framerate. this is a limitation of all canvas-recording-tools (ccapture, jsgif, gif-capture-canvas, ...)

milahu
  • 2,447
  • 1
  • 18
  • 25