resvgのSVGフォント:図形に必要な書体を読み込む
明示的なフォントファイルでresvgのSVG文字の欠落や置換を直します。小さなNodeの例と3種類の出力を比較し、編集可能な図形マスターを保ちます。
目次
resvgでSVGのフォントを確実に描画するには、フォントファイルをレンダラーに渡し、そのファミリー名をSVGで使います。ネイティブのNodeバインディング @resvg/resvg-js では fontFiles を設定します。処理が受け取るフォントを正確にテストしたい場合は、loadSystemFonts: false にしてください。プロジェクトのNodeの例で、この設定を示しています。
PNGが完全に見えても、違う書体を使っている場合があります。書き出しコマンドが成功しても文字の形を確認してください。
3種類のフォント入力で同じSVGを描画する
私たちはパスで小さな山の紋章を作り、横に編集可能な文字 PINE & FIELD を置きました。SVGはAbelファミリーの通常のウェイトを要求します。同じ元データを @resvg/resvg-js 2.6.2、Node 22.19.0、macOS arm64で3回描画しました。すべてシステムフォントの探索を無効にしています。
| 渡したフォントファイル | 観察した結果 |
|---|---|
| なし | パスの紋章は描画され、ラベルは消えました。 |
| Antonのみ | 明らかに違う太い書体でラベルが描画されました。 |
| Abel | 意図した細い文字が描画されました。 |

この観察は今回の例と設定を説明するもので、別のフォント群、バインディング、バージョンがどの代替を選ぶかを確定しません。有用な診断はもっと単純です。要求したファミリーがない場合、文字が欠けるか、一見もっともらしい代替文字になる可能性があります。
resvg-jsでローカルのフォントを読み込む
この例は別のWebAssemblyパッケージではなく、ネイティブのNodeパッケージを使います。バインディングのバージョン付き型定義では、font オプションに fontFiles、fontDirs、loadSystemFonts が掲載されています。
新しい作業フォルダーに、ここで使うバージョンをインストールします。
npm install --save-exact @resvg/resvg-js@2.6.2Google FontsのAbelディレクトリーから Abel-Regular.ttf と付属の OFL.txt を取得し、両方を fonts サブフォルダーに保管します。AbelはSIL Open Font Licenseで提供されるため、この例を配布するときはライセンスもフォントと一緒に保持してください。
次を label.svg として保存します。
<svg xmlns="http://www.w3.org/2000/svg"
width="880" height="240" viewBox="0 0 880 240">
<rect width="880" height="240" fill="#f6f2e8"/>
<path d="M46 155 L96 57 L147 155 Z" fill="#176b5b"/>
<path d="M75 155 L112 88 L166 155 Z" fill="#81ab78"/>
<text x="195" y="151" font-family="Abel"
font-size="82" font-weight="400" fill="#152e29">
PINE & FIELD
</text>
</svg>その後、SVGの隣に render.mjs を保存します。
import { access, readFile, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { Resvg } from '@resvg/resvg-js';
const fontFile = fileURLToPath(
new URL('./fonts/Abel-Regular.ttf', import.meta.url)
);
await access(fontFile);
const svg = await readFile(new URL('./label.svg', import.meta.url));
const renderer = new Resvg(svg, {
font: {
loadSystemFonts: false,
fontFiles: [fontFile],
},
});
const png = renderer.render().asPng();
await writeFile(new URL('./label.png', import.meta.url), png);node render.mjs を実行します。file URLにより入力と出力がスクリプトからの相対パスになるので、ターミナルの作業ディレクトリーを変えても、開くフォントは変わりません。access() はフォントがないかアクセスできない場合に直接ファイルシステムのエラーを返しますが、フォント内容を検証するものではありません。
対照条件を再現するには、SVGは変えません。最初の行では空の fontFiles 配列を使います。2つ目ではGoogle FontsのAntonディレクトリーから Anton-Regular.ttf を取得し、ライセンスを保管してAbelの代わりに渡します。他のものを変える前に各PNGを確認してください。
ファイル名ではなくファミリー名を合わせる
Abel-Regular.ttf はファイルパスで、Abel はSVGが要求するファミリーです。font-family="Abel-Regular.ttf" と書いても、レンダラーにそのファイルを開く指示にはなりません。
SVGのfont-family属性はファミリー名や総称ファミリーを受け付け、複数を指定すると優先順のリストになります。CSSにも対応するプロパティがあり、適用されるCSSの font-family 宣言はプレゼンテーション属性より優先します。
自分の図形では、3つをまとめて確認してください。
- ファミリー: フォント内部に記録され、SVGが要求する名前。
- スタイルとウェイト: 渡した書体が意図する文字と一致するか。
- 文字: 実際のラベルの文字や記号がフォントにあるか。
readFile の成功はバイト列を読めた証明にすぎません。単語が見えることも、何らかの文字が描画された証明にすぎません。どちらも選ばれた書体がデザインのものだとは証明しません。
編集可能な文字とアウトラインについての広い診断は、SVGのフォントが書き出し後に変わる理由を参照してください。
書き出し環境で同じ入力を確認する
フォントを図形の処理の入力として扱います。必要なフォントを配備や処理のファイル一式に含め、そこで解決されたパスがファイルを指すことを確認してください。デザイン用ノートPCに入った書体は、サーバー処理を組み立てるときに見落としがちです。
システム探索を無効にし、テストラベルの文字に対応する最小限の明示的なフォント一覧から始めます。正しい出力が得られたら、図形が実際に使う語句、句読点、ウェイト、言語をテストします。今回の通常のラテン文字ラベルは、他の文字体系や複雑なフォントファミリーをテストしていません。
文字がまだ違うなら、元データのCSS上書きと入れ子の <tspan> スタイルを調べます。紋章とラベルの両方が予想外に切れたり拡大縮小されたりするなら、SVGの境界とラスター寸法を別々に調べます。CairoSVGのサイズ調整の手順は別のレンダラーでこの違いを扱いますが、オプションはCairoSVG専用です。
バグ報告や再現可能な書き出し処理を共有するなら、SVG、正確なバインディングの版、フォントのファイル名と版、レンダラーのオプション、期待する画像を含めます。ファイルをまとめる際にはフォントの再配布許可にも注意してください。
PNGとともに編集可能な元データを保持する
上のコードが書くのはPNGです。ラスターの納品ファイルであり、見える文字は編集可能なSVG文字ではありません。後の文言変更の元データとして、label.svg とフォント入力を保管します。
固定文字のベクターロゴが必要な受け取り側には、ベクター編集ソフトで別のアウトラインSVG納品コピーを作り、確認します。編集可能な文字のマスターは残してください。ロゴファイル形式のガイドは、元データと納品ファイルの異なる役割を説明しています。
必要な紋章がPNGやJPGでしか存在しないなら、PerfectVectorのロゴベクター化ツールでその部分の図形を復元できます。パスを確認し、不要なトレース文字を除き、既知のフォントでラベルを打ち直してからresvgで書き出します。ベクター化は元のフォントを特定せず、編集可能な文字も復元しません。画像ベクター化ガイドは、変換で変わるものを説明しています。
よくある質問
システムフォントを無効にすると文字が消えるのはなぜですか? 今回の空のフォントのテストでは、ラベル用の書体が渡されず、パス図形だけが表示されました。適切なフォントを明示的に読み込み、ファミリー、スタイル、文字の対応範囲を確認してください。
フォントのファイル名をSVGのファミリー名にできますか? SVGにはフォントのファミリー名を使い、ローカルのファイル名はfontFilesで別途渡します。ファイルの名前を変えても内部のファミリー名は変わりません。
resvgはPNGロゴを編集可能なSVGに変えますか? この例はSVGをPNGに描画します。ラスターロゴをベクター化しません。必要ならベクター化の手順で紋章を復元し、編集可能な文字を加えて、そのSVGをマスターとして保持します。
参考資料
- resvg-js — 2.6.2のREADME — ネイティブNodeの使用と明示的なフォント読み込みを説明しています。
- resvg-js — 2.6.2の型定義 — フォント設定と描画画像APIを説明しています。
- MDN — SVGのfont-family — ファミリーのリストとCSSの優先を説明しています。
- Google Fonts — Abel — 意図したラベルに使った通常の書体とライセンスです。
- Google Fonts — Anton — 置換の対照条件に使ったフォントとライセンスです。
ラスターの紋章が作業を止めているなら、ロゴ図形をベクター化し、編集ソフトでエッジを確認してラベルを編集可能な文字で追加します。その後、フォントファイルを明示して描画し、渡す前にPNGをマスターと比較してください。

