Adding text to images with Node.js
2025-03-30
My mother started experimenting with LLMs. That’s a sentence I wasn’t expecting to write. But she is. Yesterday, on our shared birthday (36 and 63) we had a chat about it. She’s using it as an assistant for her personal projects, outlining the script for a workshop she’s running. Good stuff. But she ran into a problem she didn’t know how to solve and the AI was spitting Python scripts at her so she called me and gave me a late night Saturday challenge.
The Problem
She created an image template for the ticket of an event and she has a spreadsheet with names and phone numbers of attendants. She wants to create tickets for each of them. She knows how to do this with image editing software but obviously it doesn’t scale. I’m sure Photoshop has a macros functionality but neither of us know how to use it.
I’m also sure that, being able to Ghibli-fy any picture, OpenAI’s new model can add some text to an image, but I don’t think it will do it for a list of 30+ people from the chat interface. At this point I can either:
- a. write a script to make all those calls to the OpenAI API (having to prompt engineer for consistency, which I hate doing)
- b. write a Node.js script using my own brain (which I still love doing)
The Solution
My frontend trained brain went first to loading the image into an HTML canvas, drawing the text and downloading the image. I know how to do that, but the visual part of the solution seems unnecessary. I’ve never had to do image processing for work, but I’m sure there’s a popular library on NPM. A quick search led me to sharp
, which from the description sounds like the ffmpeg
of images.
I’ll outline the main parts of the script, in good old JavaScript because types are not for the weekend (I also put it in a gist):
const sharp = require("sharp");
// Create an SVG with the text to insert
const nameSvg = `
<svg width="1200" height="250">
<style>
.title {
fill: ${fontColor};
font-size: ${fontSize}px;
font-family: ${font};
}
</style>
<text x="${x}" y="${y}" text-anchor="start" alignment-baseline="hanging" class="title">${name}</text>
</svg>
`;
// Turn it into a buffer
const nameBuffer = Buffer.from(nameSvg);
await sharp(inputImagePath)
.composite([
{
input: nameBuffer,
top: 1500, // Adjust as needed
left: 180, // Adjust as needed
},
])
.toFile(`./tickets/${name}.jpg`);
That’s pretty much it. Beautifully simple. All there’s left to do is parse a CSV file with all the names and phone numbers and call the code above in a loop:
const fs = require("fs");
const csvParser = require("csv-parser");
const inputImage = "./template.jpeg";
fs.createReadStream("./attendants.csv")
.pipe(csvParser())
.on("data", (row) => {
addTextToImage(inputImage, row.name, row.phone);
});
Final thoughts
I’m sure the Python script ChatGPT spat out did something like this, but this took me literally 30mins to write, I had fun, learned something new and made my mother proud. If I had copy pasted the script what would I had gained?
There’s a fun project here to turn this into a simple tool, basically one of those meme generators but with a CSV file as an input.