プログラミング: fontconfig を C言語で使う

概要

fontconfig とは linux をはじめとするシステムに於いてインストールされているフォントを管理する機能である.

fontconfig を用いることによってフォントを必要とするプログラムに於いて, フォントのパス指定が必要なくなる. また, スタイルや文字セットなどの指定から最適なフォントを選択することもできる.

しかし, fontconfig に関する資料が少なく苦戦したため, メモとしてこの記事を執筆する. なお, プログラムを作成するに当たり fc-match コマンドのソースコードを参照した.

インクルード

#include <fontconfig/fontconfig.h>

pkg-config --cflags --libs fontconfig で必要なコンパイラフラグが得られる. この場合でも fontconfig/fontconfig.h なので注意.

利用

プログラムでは現在デフォルトで利用できるフォントをとにかく一つ選ぶ機能に利用したため, それを例として示す.

初期化

FcInit();

FcPattern

フォント選択に関する条件を指定する構造体. 関数を通じて情報の取得や設定を行う. フォント検索の結果もこの構造体に入る(すべての条件が埋まった状態として).

FcPattern の作成

FcPattern *pattern = FcPatternCreate();

後述の検索関数 FcFontMatch に渡すには指定していない条件に適切なデフォルト値が含まれている必要がある.

この設定を行うのが FcConfigSubstitute 関数と FcDefaultSubstitute 関数である.

// 未指定の条件を埋める

// 第1引数の 0 は fontconfig デフォルトの設定を用いるという意味.
// 必要ならば FcInitLoadConfig() 関数などで設定を取得し変更できる.
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);

FcFontMatch

指定したパターンにマッチするフォント情報を取得する関数.

// FcFontMatch の第3引数に渡す. 関数の成否が代入される.
FcResult fcresult;

// FcPattern としてマッチ結果が返される
FcPattern *result = FcFontMatch(0, pattern, &fcresult);

// FcResult 列挙体のメンバについてはヘッダファイルを参照.
if (fcresult == FcResultNoMatch) {
    printf("No Match\n");
}

FcPatternGetString

FcPattern から情報を取り出す関数. マニュアルにもあるが, 代入される値は FcPattern の該当メンバへの参照なので解放してはいけない.

シグネチャは次の通り

FcResult FcPatternGetString(FcPattern* pattern, const char *key, int index, FcChar8 **valueptr);

FcPattern pattern のキーkeyindex番目の値をvalueptrに代入する関数という意味. なお FcPatternGetStringString の部分は値の型により種類がある. 詳しくはマニュアルを参照.

そしてその使用

// 今回はマッチしたフォントのファイル名を取得する.
unsigned char *filepath;
// ファイル名を表すキーは "file".
// 第3引数は値が複数含まれている場合のインデックス(ここでは 0 番目).
FcPatternGetString(result, "file", 0, &filepath);

後始末

解放する必要があるのは, FcPattern. 注意しなければならないのは FcFontMatch の返り値も解放しなければならないことである.

最後に FcFini 関数を呼んで終了である.

FcPatternDestroy(pattern);
FcPatternDestroy(result);

FcFini();

全体像

参考までに例をすべてつなげたものを載せる.

FcInit();
FcPattern *pattern = FcPatternCreate();

FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);

FcResult fcresult;

FcPattern *result = FcFontMatch(0, pattern, &fcresult);

if (fcresult == FcResultNoMatch) {
    printf("No Match\n");
}

unsigned char *filepath;
FcPatternGetString(result, "file", 0, &filepath);

FcPatternDestroy(pattern);
FcPatternDestroy(result);

FcFini();

その他の便利な関数

  • FcPatternPrint(FcPattern*)

    FcPattern 構造体の中身を人間の読める形式で標準出力に出力する. 具体的にはキーと値の対応を整形して出力する.

  • FcPatternGet(FcPattern*, const char*, int, FcValue*)

    キーを指定して FcPattern に含まれる値を取得する. FcValue は型情報を含む共用体で, FcPattern に含まれる任意の値を格納できる.

  • FcValuePrint(FcValue)

    FcValue 共用体に含まれている値を人間の読める形式で標準出力に出力する. 文字列なら二重引用符でくくられる.

他の関数については fontconfig のマニュアルを参照.

感想

  • 日本語の資料は期待できない
  • 英語の資料も期待できない. ヘッダファイルと fc- 系のソースコードを読むと手がかりが得られる.
  • fontconfig のマニュアルにはサンプルソースがないのである程度分かってきてから読むと役立つ.

他の選択肢

SDL2 を使ったプログラムでフォント関連を扱うために fontconfig に手を出したわけだが, 検討した他の選択肢もメモしておく.

  • pango

    有名な多言語対応の文字レンダラ. GTK+ などで用いられており, テキストのレンダリングに関する様々な機能を提供する. もちろん fontconfig 関連も扱える. マークアップなども使える. ただ, マニュアルを読むのが辛かった.

  • pango cairo

    pango を cairo で利用できるようにしたもの. SDL2 のサーフェースに描画できる. ただ, やりたいことをするには設定が大げさすぎた.

  • sdl_pango

    pango を SDL で利用できるようにしたもの. SDL2 だとうまく行かない気がする.

今のプログラムで実現したいことが増えたならこれらがまた使われるかもしれない.

以上