Node.jsで画像に文字を書く
地味に進めていたこのサイトのリニューアルもほぼ完了しました。
新しいサイトはSNS対応(OGPってやつ)をきっちりしてみたかったのですが、このためには記事1つ1つにアイキャッチ画像の設定が必要でした。 ただまあ、テキストとソースコードがほとんどのこのブログで画像を毎回作るのも面倒くさくて…
というわけで、Node.jsでコンテンツと一緒に生成させるようにしてみました。
具体的には、以下のような画像を読み込んで、
以下のように記事のタイトルを入れるものを作りました。
1. 必要なパッケージのインストール
今回はnode-canvasというライブラリを使用しました。 その名の通り、HTMLのCanvas APIをNode.js上で使えるようにしてくれるやつです。
$ npm install canvas
環境によっては依存関係を手動でインストールする必要があるので、問題があればGitHub上のREADMEを確認してください。
2. Canvasを用意する
まずはcreateCanvasという関数を使って、画像編集をするためのキャンバスの用意をします。 このキャンバスに色々書き込んでいく流れになります。
import { createCanvas } from 'canvas';
const canvas = createCanvas(640, 480); // 640x480の空のキャンバスを作る
// const canvas = document.querySelector('#canvas'); // 上の一行はブラウザの場合のコレに相当します
const ctx = canvas.getContext('2d'); // ここからはブラウザと共通
3. 画像を読み込む
次に、書き込み先となる画像を読み込みます。 画像の読み込みにはImageクラスを使うか、そのヘルパ関数であるloadImageを使います。
loadImage関数を使う場合(簡単)
import { loadImage } from 'canvas';
const image = await loadImage('./path/to/image.jpg'); // ここはURLを渡しても平気
ctx.drawImage(image, 0, 0, 640, 480); // さっき作ったCanvasの(0, 0)地点に640x480のサイズで描画
Imageクラスを使う場合(色々出来る?)
import { Image } from 'canvas';
const image = new Image();
image.src = './path/to/image.jpg'; // ここはURLでも良い(loadImageと一緒)
image.onerror = (err) => {
console.error(err);
};
image.onload = () => {
ctx.drawImage(image, 0, 0, 640, 480); // さっき作ったCanvasの(0, 0)地点に640x480のサイズで描画
};
4. 文字を書き込む(英数字だけバージョン)
書き込み先の画像の準備が出来たら、いよいよ文字を書き込みます。 まずはフォントを気にしなくて良い英数字だけの文字列から。
ctx.fillText('hello world', 10, 10); // (10, 10)の位置に"hello world"を書き込む
これだけで書き込みが出来ます。
このあたりの挙動はブラウザのCanvas APIと全く一緒なので、MDNあたりのリファレンスが参考になると思います。
5. 文字を書き込む(日本語バージョン)
5-1. フォントの読み込み
日本語(というかASCII文字以外)を書き込みたい場合は、まず始めにフォントの読み込みをする必要があります。 これには、registerFontという関数を使います。
ちなみに、registerFontの呼び出しはcreateCanvasを呼び出す前にやらないとダメみたいです。
import { registerFont } from 'canvas';
registerFont('./path/to/font.ttf', { family: 'Hoge Fuga' }); // font.ttfを登録する。フォント名は適当
これで登録が出来ます。 ttfもotfも読めるので、かなりつよい。
URLの指定は出来ないので、そこだけ注意。
5-2. 使うフォントを指定して文字を書き込む
フォントの登録が完了したら、以下のようにして使うフォントを指定して書き込みます。 この辺はブラウザと一緒。
ctx.font = '12px "Hoge Fuga"'; // フォントサイズとさっき指定したフォント名
ctx.fillText('日本語が使える!', 10, 10);