目的
この note のページのogp画像を以下の仕様で自動生成したい。
結果

OSS
すでにこのサイトでは、画像処理に sharp を使用しているので、ここでも sharp を使用する。
以前は jimp を使用していたが、 sharp の方が扱いやすい上に処理も早かった。
const sharp = require('sharp')
 
await sharp('ベース画像')
    .composite([{ input: タイトル画像 }])
    .toFile('出力画像'))
  }
sharp は文字を扱えないので、文字を画像化するためにこれを使用する。
text2png() に文字列とオプションを与えると画像バッファを返してくれる。 
const text2png = require('text2png')
 
const options = {
    font: '72px NotoSansJP-Bold',
    localFontPath: '/fonts/NotoSansJP-Bold.otf',  
    localFontName: 'NotoSansJP-Bold',
    color: '#345',
    lineSpacing: 20
  }
  const titleImage = text2png('タイトル文字列', options)
タイトルの文字列
タイトルが長すぎるとタイトル画像がベース画像よりも大きくなって、sharp に怒られる。
なのでタイトル文字列を以下のように編集する関数を作る
function proofread(str) {
    let count = 0 
    let lineCount = 1 
    let newStr = ''
    const lineLength = 22 
    for (let i = 0; i < str.length; i++) {
        encodeURI(str.charAt(i)).length >= 4 ? (count += 2) : (count += 1)
        newStr += str.slice(i, i + 1)
        if (count > lineLength) {
            if (lineCount === 1) {
                newStr += '\n' 
                count = 0
                lineCount += 1
            } else {
                newStr += '..'
                break 
            }
        }
    }
    return newStr
}
最終形態
const sharp = require('sharp')
const text2png = require('text2png')
const proofread = require('./proofread')
 
async function createThumImage(title) {
    const options = {
        font: '72px NotoSansJP-Bold',
        localFontPath: '/fonts/NotoSansJP-Bold.otf',
        localFontName: 'NotoSansJP-Bold',
        color: '#345',
        lineSpacing: 20
    }
    const noteTitle = proofread(title)
    const titleImage = text2png(noteTitle, options)
    await sharp('ベース画像')
        .composite([{ input: titleImage }])
        .toFile('出力画像')
}