Using Canvas in Node JS

Have you ever wanted to generate dynamic images on the server side? With Node Canvas, it's easy! Node Canvas is a module that allows you to use the canvas element on the backend, making it simple to create images based on user input.

Hero Image

Node Canvas is a module that allows you to use the canvas element on the server side for generating dynamic images. You can see an example of this by going to the URL below and replacing test-image with any text to get a random image.

1https://decode.sh/hero/Test%20Image

Installation

1npm install canvas

Note: canvas uses Cairo, a 2D graphics library with support for multiple output devices, which you may need to install in order to get canvas working properly. Use the table below to install.

OS Command
OS X Using Homebrew: brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman
Ubuntu sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
Fedora sudo yum install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel
Solaris pkgin install cairo pango pkg-config xproto renderproto kbproto xextproto
OpenBSD doas pkg_add cairo pango png jpeg giflib
Windows See the wiki
Others See the wiki

Mac OS X v10.11+: If you have recently updated to Mac OS X v10.11+ and are experiencing trouble when compiling, run the following command: xcode-select --install. Read more about the problem on Stack Overflow. If you have xcode 10.0 or higher installed, in order to build from source you need NPM 6.4.1 or higher.

Usage

To use canvas, you will first need to import createCanvas like this:

1import { createCanvas } from "canvas";

Creating the canvas is as simple as with the native module

1const canvas = createCanvas(width, height);
2const ctx = canvas.getContext("2d");

Example

Creating the canvas is as easy as with the native module. Here is an example from the official documentation that draws the word 'Awesome!' along with an image of a cat wearing a lime helmet:

 1const { createCanvas, loadImage } = require("canvas");
 2const canvas = createCanvas(200, 200);
 3const ctx = canvas.getContext("2d");
 4
 5// Write "Awesome!"
 6ctx.font = "30px Impact";
 7ctx.rotate(0.1);
 8ctx.fillText("Awesome!", 50, 100);
 9
10// Draw line under text
11var text = ctx.measureText("Awesome!");
12ctx.strokeStyle = "rgba(0,0,0,0.5)";
13ctx.beginPath();
14ctx.lineTo(50, 102);
15ctx.lineTo(50 + text.width, 102);
16ctx.stroke();
17
18// Draw cat with lime helmet
19loadImage("examples/images/lime-cat.jpg").then((image) => {
20  ctx.drawImage(image, 50, 0, 70, 70);
21
22  console.log('<img src="' + canvas.toDataURL() + '" />');
23});

Exporting

To send the image to the client, you can use the non-standard API's in the documentation to convert the image to a buffer and return it in the Response object like this:

Svelte example

Using the same code as above, to send the image to the client all you have to do is convert the image to a buffer and return it in the Response object.

Converting the canvas to a buffer

1canvas.toBuffer("image/jpeg");

Full code example

 1import { error } from '@sveltejs/kit';
 2import { createCanvas } from "canvas";
 3
 4export function GET({ params, url }) {
 5    return new Promise((resolve, reject) => {
 6        ctx.font = '30px Impact'
 7  ctx.rotate(0.1)
 8  ctx.fillText('Awesome!', 50, 100)
 9
10  // Draw line under text
11  var text = ctx.measureText('Awesome!')
12  ctx.strokeStyle = 'rgba(0,0,0,0.5)'
13  ctx.beginPath()
14  ctx.lineTo(50, 102)
15  ctx.lineTo(50 + text.width, 102)
16  ctx.stroke()
17
18  // Draw cat with lime helmet
19  loadImage('examples/images/lime-cat.jpg').then((image) => {
20    ctx.drawImage(image, 50, 0, 70, 70)
21
22        resolve(new Response(canvas.toBuffer("image/jpeg")));
23    }).catch(() => {
24        throw error(404, 'Not found');
25    })
26}