How to dynamically generate images with Node.js

🚫 Problem

Having to manually 😴 create unique images for Social Media (Open Graph) for your new blog posts.

βœ… Solution

Let's use Node.js to engineer a script to take care of this for us 😎

❀️ Generated image

This is the final result, a dynamically generated image:

πŸ€” How does this work?

A part from playing with the file system (fs) module from Node.js, the actual image creation will be done using canvas:

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

I assume you're comfortable adding NPM packages to your package.json file.

Require all functions needed from canvas

We'll start our index.js file by requiring this, as well as the file system module:

const fs = require('fs');
const {
  createCanvas,
  loadImage,
  registerFont,
} = require('canvas');Code language: JavaScript (javascript)

Creating a canvas

To define the area we will be working with, define it like so:

const imageCanvas = createCanvas(1200, 630);
const context = imageCanvas.getContext('2d');Code language: JavaScript (javascript)

Loading a custom font (optional)

In case the system you're creating the images in does not have the fonts you want, simply include the .ttf files and register the custom font like so:

registerFont('comicsans.ttf', { family: 'Comic Sans' })Code language: JavaScript (javascript)

Read more on the registerFont function.

Adding a background color to the canvas

You'll notice the width and height match the canvas size we defined earlier.

context.fillStyle = '#343a40';
context.fillRect(0, 0, 1200, 630);Code language: JavaScript (javascript)

Adding text to the canvas

Use these 3 properties to define properties of the text, and then add the text in the position you want relative to the canvas.

context.fillStyle = '#fff';
context.font = 'bold 30pt Menlo';
context.fillText('ricard.dev', 580, 520);Code language: JavaScript (javascript)

Writing to disk

The final step is to simply write a file with the canvas as PNG format:

fs.writeFileSync(
  `./images/myImage.png`,
  imageCanvas.toBuffer('image/png'),
);Code language: JavaScript (javascript)

At this point you would be done πŸ‘. You now know how to create images with text with canvas from within Node. You don't have to continue if you don't use WordPress. Just jump to the end to grab the final code.

What improvements can be done?

  • Use a database.txt file to list all the images you want to create (this can be found in the final code).
  • Create this on the fly. You could even serve the image on the fly rather than storing it to disk (not covered in this blog post).

WordPress (optional)

If you're using WordPress here are small snippets you'll be needing:

Generate the database

List of post and their ID's:

$path = preg_replace('/wp-content.*$/','',__DIR__);

include($path.'wp-load.php');

$args = array(
  'numberposts' => -1
);

$posts = get_posts( $args );

echo "<pre>";

if ( $posts ) {
  foreach ( $posts as $post ) {
    print_r($post->ID . "|" . $post->post_title . "\n");
  }
}

echo "</pre>";Code language: PHP (php)

It will output something like this:

9099|How to list recently edited pages in Hugo
9072|Moving from Docusaurus to HugoCode language: plaintext (plaintext)

Loop the database

From the database you just created, it would only make sense to loop it while creating the images.

const databaseContent = fs.readFileSync('./database.txt', { encoding: 'utf8', flag: 'r' });
const lines = databaseContent.split(/\r?\n/)

lines.forEach((line) => {
  const content = line.split('|');
  const id = content[0];
  const text = content[1];

  // Do stuff with the canvas
  // Add text, colors, etc
  // ...
});Code language: JavaScript (javascript)

Overwrite Yoast SEO plugin output

By default the plugin will get the actual featured image from the post, you want to customize that output. Should you have placed the script inside your theme, you will also want this in your functions.php file

function wp_open_graph_overwrite_YOAST( $url ) {
  if (!is_singular('post')) {
    return $url;
  }

  // Check if the file exists on disk
  $image = '/image-generator/images/' . get_the_ID() . ".png";
  $imageURL = get_stylesheet_directory_uri() . $image;
  $imagePath = get_stylesheet_directory() . $image;

  if (file_exists($imagePath)) {
    return $imageURL;
  }

  return $url;
}

add_filter( 'wpseo_opengraph_image', 'wp_open_graph_overwrite_YOAST' );Code language: PHP (php)

πŸ‘¨β€πŸ’» Grab the complete code

Check out the GitHub repository:

https://github.com/quicoto/image-generator

Leave a Reply

Your email address will not be published. Required fields are marked *