Welcome to a tutorial on how to add text to an image in NodeJS. In client-side Javascript, we can use the native Canvas API to write text on an image. Thankfully in NodeJS, we also have a canvas library to simulate that – Read on for the examples!
ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.
TLDR – QUICK SLIDES
Fullscreen Mode – Click Here
TABLE OF CONTENTS
DOWNLOAD & NOTES
Firstly, here is the download link to the example code as promised.
QUICK NOTES
- Download and unzip into your project folder.
- Install the required canvas module –
npm install canvas
. - Run the examples.
EXAMPLE CODE DOWNLOAD
Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
NODEJS ADD TEXT TO IMAGE
All right, let us now get into the examples of adding text to an image in NodeJS.
1) SIMPLE ADD TEXT TO AN IMAGE
// (A) LOAD MODULES
const fs = require("fs"),
{ createCanvas, loadImage } = require("canvas");
// (B) SETTINGS
const
sFile = "demo.png", // source image
sSave = "demoA.png", // "save as"
sText = "FRIED RICE", // text to write
sX = 380, sY = 80; // text position
// (C) LOAD IMAGE + DRAW TEXT
loadImage(sFile).then(img => {
// (C1) CREATE CANVAS
const canvas = createCanvas(img.width, img.height),
ctx = canvas.getContext("2d");
// (C2) DRAW IMAGE ONTO CANVAS
ctx.drawImage(img, 0, 0);
// (C3) WRITE TEXT ONTO IMAGE
ctx.fillText(sText, sX, sY);
// (C4) SAVE
const out = fs.createWriteStream(sSave),
stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("Done"));
});
For you guys who are somehow lost, it’s easier to focus on section (C) only:
- (C) Load the image first.
- (C1) When the image is loaded, create an empty canvas.
- (C2) “Copy” the entire image onto the canvas.
- (C3) Then write the text on top.
- (C4) Finally, save the canvas as an image file.
2) MORE TEXT OPTIONS
// (A) LOAD MODULES
const fs = require("fs"),
{ createCanvas, loadImage } = require("canvas");
// (B) SETTINGS
const
sFile = "demo.png", // source image
sSave = "demoA.png", // "save as"
sText = "FRIED RICE", // text to write
sX = 380, sY = 80; // text position
registerFont("C:/Windows/Fonts/arialbd.ttf", { family: "Arial Bold" });
// (C) LOAD IMAGE + DRAW TEXT
loadImage(sFile).then(img => {
// (C1) CREATE CANVAS
const canvas = createCanvas(img.width, img.height),
ctx = canvas.getContext("2d");
// (C2) DRAW IMAGE ONTO CANVAS
ctx.drawImage(img, 0, 0);
// (C3) WRITE TEXT ONTO IMAGE
ctx.font = '36px "Arial Bold"';
ctx.fillStyle = "rgba(255, 0, 0, 0.4)";
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(0, 0, 0)";
ctx.fillText(sText, sX, sY);
ctx.strokeText(sText, sX, sY);
// (C4) SAVE
const out = fs.createWriteStream(sSave),
stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("Done"));
});
I know, the above text is too small and needs some “improvements”. There are quite a number of ways we can work with the text, here are a few of the common ones:
- To use a custom font:
- (B) We have to
registerFont()
first – Remember to change this to your own. - (C3) Use
ctx.font
to specify the font size, font weight, and font family.
- (B) We have to
- To set transparent text, use
ctx.fillStyle = "rgba(R,G,B,A)"
. - To stroke (outline) the text:
- Use
ctx.lineWidth
to control the thickness. - Use
ctx.strokeStyle
to control the outline color and opacity. - Draw the outline using
ctx.strokeText()
. - Take note,
strokeText()
will only draw the outline. It is necessary to callfillText()
if you want to fill in the text.
- Use
3) CENTER TEXT ON IMAGE
// (A) LOAD MODULES
const fs = require("fs"),
{ registerFont, createCanvas, loadImage } = require("canvas");
// (B) SETTINGS - CHANGE FONT TO YOUR OWN!
const
sFile = "demo.png", // source image
sSave = "demoC.png", // "save as"
sText = "FRIED RICE", // text to write
sX = 380, sY = 80; // text position
registerFont("C:/Windows/Fonts/arialbd.ttf", { family: "Arial Bold" });
// (C) LOAD IMAGE + DRAW TEXT
loadImage(sFile).then(img => {
// (C1) CREATE CANVAS + DRAW IMAGE
const canvas = createCanvas(img.width, img.height),
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// (C2) TEXT DIMENSIONS
ctx.font = '36px "Arial Bold"';
ctx.fillStyle = "rgba(255, 0, 0, 0.4)";
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(0, 0, 0)";
let td = ctx.measureText(sText),
tw = td.width,
th = td.actualBoundingBoxAscent + td.actualBoundingBoxDescent;
// (C3) CALCULATE CENTER & WRITE ON CENTER
let x = Math.floor((img.naturalWidth - tw) / 2),
y = Math.floor((img.naturalHeight - th) / 2);
ctx.strokeText(sText, x, y);
ctx.fillText(sText, x, y);
// (C4) SAVE
const out = fs.createWriteStream(sSave),
stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("Done"));
});
Lastly, centering the text is unfortunately Mathematical.
- (C2) Define the “text settings” as usual, then use
ctx.measureText()
to get the text box dimensions. - (C3) To calculate the center XY coordinates:
X = FLOOR((IMAGE WIDTH - TEXT WIDTH) ÷ 2)
Y = FLOOR((IMAGE HEIGHT - TEXT HEIGHT) ÷ 2)
EXTRA BITS & LINKS
That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.
A COUPLE OF ISSUES…
- The Node Canvas library does not support
WEBP
at the time of writing. You can try using Sharp to convert the image file format. - There’s some funny custom font issue in Windows. If the font is not installed in Windows, the script will throw an error.
LINKS & REFERENCES
- Node Canvas – GitHub
- Node Canvas – NPM
INFOGRAPHIC CHEAT SHEET

THE END
Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!