How to write text over images using Node js and Jimp

We can write text over multiple images using Nodejs. To do this we will use JIMP also known as Javascript Image Manipulation Program.

https://www.npmjs.com/package/jimp

In this tutorial, we will write text from a text file line by line over multiple images. Suppose there are 20 lines in the text our script will download 20 images and write all those lines one by one over 20 images.

To make this program work you need to create a text file text.txt and write all the text that you wanted to write over images. In this tutorial, we are downloading images from the Internet but in case you already have images in your computer then you can read those images and pass text to Jimp to write over it.

const Jimp = require('jimp') ;
const Fs = require('fs');  
const Path = require('path');  
const Axios = require('axios');
const readline = require('readline');


// Read text line by line and write over image
async function processLineByLine() {
  const fileStream = Fs.createReadStream('text.txt');

  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity
  });
  for await (const line of rl) {

    downloadImage(line, line.slice(0, 40).replace(/[^a-zA-Z ]/g, "").replace(/s/g, '-')+'-image.jpg')

  }
}

// Function to download images from Usplash
async function downloadImage (quote,imageName) {  
  const url = 'https://picsum.photos/700/700'
  const path = Path.resolve(__dirname, 'image', imageName)
  const writer = Fs.createWriteStream(path)

  const response = await Axios({
    url,
    method: 'GET',
    responseType: 'stream'
  })

  response.data.pipe(writer)

  let imageDownloaded = new Promise((resolve, reject) => {
    writer.on('close', resolve)
    writer.on('error', reject)
  });

  imageDownloaded.then(
    (value)=> {
      textOverlay(quote,imageName);     
    },
    (value)=> {console.log(value)}
  )

}

// Function to write text over images using JIMP
async function textOverlay(quote,imageName) {

  const maxWidth =650;
  const maxHeight=340;
  // Defining the text font
  const fontBlack = await Jimp.loadFont(Jimp.FONT_SANS_32_BLACK);
  const fontWhite = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE);

   let overlayImageHeight = 200;
   let overlayImageYPosition = 180;
   let imagePrintPositionY =100;

  if(quote.length>180){
    overlayImageHeight =280;
    overlayImageYPosition = 175;
    imagePrintPositionY =180;
  }

   // Reading image
   console.log(imageName);
   const image = await Jimp.read(__dirname+'/image/'+imageName);  
   let colorArray =['#fff2ed','#ffebed','#fff7ec','#ddedc9','#c9eddd','#c9cced','#eac9ed','#edc9d6','#e3edc9'];
   let randomColor = colorArray[Math.floor(Math.random()*colorArray.length)];

   let overLayImage =new Jimp(700, overlayImageHeight, randomColor, (err, image) => {
    // this image is 256 x 256, every pixel is set to #FF00FF
   });

   image.composite(overLayImage, 0, overlayImageYPosition, {
    mode: Jimp.BLEND_SOURCE_OVER,
    opacitySource: 0.7,
    opacityDest: 1
  });

   //image.blit(overLayImage, 0, overlayImageYPosition);

   image.color([
      { apply: 'darken', params: [5] }
    ]);


   image.print(
    fontBlack, 
    10, 
    imagePrintPositionY, 
    {
      text: quote,
      alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
      alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
    },
    maxWidth,
    maxHeight
    );

    image.print(fontWhite, 550, 650, 'Copyright @xyz.com');

   // Writing image after processing
   await image.writeAsync(__dirname+'/p_image/'+imageName);
}

processLineByLine();

We also need to create two folders to make this APP work, name one folder as image and another one as p_image. image folder will store images that are being download from the internet and p_image folder will store images that are already processed by JIMP