Vercel Satori で縁取りを付ける
※Pull request がマージされたので、下のようなことをしなくても縁取りを付けることができるようになった。
HTML・CSS を SVG 画像に変換する Vercel 製ライブラリ、Satori でテキストに縁取りを付ける。というおはなし。
SVG はテキストの縁取りに対応しているものの、Satori は対応していない。というのが現状。
解決方法
const svg = await satori(/* HTML */, {
/* まあなんやかんや設定がありまして */
embedFont: false
});
まずは Satori のオプションで embedFont
を false
に設定して、テキストをパスとして書き出すのではなく、SVG の <text>
要素を使用してテキストを書き出すようにする。
SVG 画像の文字列から、特定の文字列を検索対象として置換する。
const repFontSVG = svg.replaceAll('font-family="serif"', 'font-family="Noto Sans JP"');
const repStroke = repFontSVG.replaceAll('font-weight="900"', 'font-weight="900" paint-order="stroke" stroke-width="12px" stroke="#120112" stroke-linejoin="round"');
const image = await sharp(Buffer.from(repStroke)).png().toBuffer();
return new Response(image);
font-family
は serif
になってしまうので、好きなフォントを指定する。
もちろん SVG にフォントデータは入ってないので、例えば sharp ライブラリでラスタ画像に変換される際はインストールされているフォントが使用される。
あとは fill
なり font-weight
なりキーとなる属性で検索して、paint-order="stroke"
と stroke-width
と stroke
を追加する。paint-order
は文字の塗りよりも後ろに線を描画するために必要。好みで stroke-linejoin="round"
も追加する。これは線の結合方法をラウンド結合にするために必要。文字に対して丸い縁取りが必要な場合はこれを指定する。
あとは sharp などで画像化すると、縁取りした画像が生成される。いいね。
……というのは面倒ですよね
まあやりたいことは実現できたのだが、テキストの構成によっては検索での絞り込みが難しいケースもあるし、なにより脳筋ソリューションなのでかしこいやり方ではない。
ということで、こんなことをしなくても縁取りができるように、パラメータ WebkitTextStroke
を実装して Satori に Pull request を出してみた。これがマージされたら縁取りが楽になるね。