How to print a canvas to a data URL

By

Learn how to print a canvas to a data URL in Node.js using the canvas npm package and toDataURL(), then embed the generated image directly in your HTML.

~~~

To print a canvas to a data URL, call the toDataURL() method on the canvas object. It returns the whole image encoded as a base64 string, ready to be used as the src of an img tag.

Data URLs are a useful feature provided by browsers.

We can have an image that instead of referencing a file system file, like

<img src="image.png" />

it embeds the image in the HTML itself, something like this:

<img src="data:image/png;base64,iVBORw0KGgoAA…" />

where the garbage part that’s composed by seemingly random letters and numbers is very long.

I was playing with the Canvas API to generate an image dynamically, and I stumbled upon the toDataURL() method of the Canvas object.

I think that this is especially useful when you create a server-side image and you want to serve it in a web page, server-side generated. All from a Node.js process.

Generating the image in Node.js

Node.js has no canvas built in, but the canvas npm package implements the same API we have in the browser. Install it with npm install canvas. On common platforms npm downloads a prebuilt binary, so there’s nothing to compile.

Here’s a complete example. We create a 200x200 canvas, draw some text into it, and print the data URL:

const { createCanvas } = require('canvas')

const canvas = createCanvas(200, 200)
const ctx = canvas.getContext('2d')

ctx.fillText('Hello, World!', 50, 100)

console.log(canvas.toDataURL())
// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgA…

We can then append that string to the HTML we’re building:

const imageHTML = '<img src="' + canvas.toDataURL() + '" />'

Choosing the image format

By default toDataURL() gives you a PNG. You can ask for a JPEG instead, and pass a second argument to set the quality, from 0 to 1:

canvas.toDataURL('image/jpeg', 0.8)

For photos, a JPEG at 0.8 quality is usually much smaller than a PNG.

In the browser

You can do the same on the frontend, of course, except now the canvas object is a reference to a <canvas> HTML element you are drawing to:

const canvas = document.getElementById('canvas')
//…
const imageHTML = '<img src="' + canvas.toDataURL() + '" />'

Be careful with one thing in the browser: if you drew an image loaded from another origin onto the canvas, the canvas is considered tainted, and toDataURL() throws a SecurityError. The fix is to set crossOrigin = 'anonymous' on the image, and serve the image with CORS headers that allow your site.

Watch out for size

Base64 encoding makes the data about 33% bigger than the binary image file. For small generated images, like badges or avatars, that’s fine.

For bigger images you’re inflating the page for no good reason. In Node, canvas.toBuffer('image/png') gives you the raw bytes, and you can serve those directly with a Content-Type: image/png header instead of embedding them.

Tagged: Node.js · All topics
~~~

Related posts about node: