イネマルのプログラミング備忘録

趣味プログラマーのメモ

フォントファイルからフォント名を取得する

f:id:inemaru:20170611112448p:plain

目的

C++で、フォントファイルからフォント名(フォントファミリ名)を取得します。
対応フォーマットは、スタンダードに ttf, otf とします。

対応

結局のところ、バイナリから直接、フォント名を取得するのが高速だと思うので、
フォーマットを解析しながらフォント名を取得します。

既知の方法

今回は使用しない既知の方法としてGDIを使用した方法があります。

  • GDI+の「PrivateFontCollection」

GDIのインスタンスを起動させる必要があり
対応フォーマットは多種ですが、フォント名を取得するだけで使用するには低速です。

昔、この方法で実装しましたが、
「GDIの起動が低速」(+自分の実装ミスでバグ持ち)という問題があり、
かなり微妙でした。

  • GDI+の非公開API「GetFontResourceInfo」

高速に動作しますが取得した結果が、
英名だったり「 & 」で結合された結果が戻ったり仕様に不明点が多いです。
非公開APIなので最悪、突然使えなくなるかもしれないという危なっかしさもあります。

注意

勉強のついでの感覚で実装しているので、実用性は考慮していません。
また、バグとかあっても自己責任でお願いします。

準備

ブログにコードを載せるには量が多いので、ソースはアプロダに上げます。
フォントファイルからフォント名を取得.zip(フォントファイルからフォント名を取得.zip) ダウンロード | イネマルの備忘倉庫 | uploader.jpをダウンロードして
VS2015以降のコンソールプロジェクトに追加した状態で動く想定です。

プログラム

下記のように使用します。

int main()
{
	// ロケール設定
	std::locale::global(std::locale("japanese"));
	setlocale(LC_ALL, std::locale().c_str());

	// フォント名取得
	FontFamilyMap nameMap;
	if (GetFontFamilyName(L"./GenEiLateGo.otf", nameMap)) {
		std::wcout << L"英:" << nameMap[LANGUAGE_ID::LID_ENGLISH] << std::endl;
		std::wcout << L"日:" << nameMap[LANGUAGE_ID::LID_JAPANESE] << std::endl;
	}

	// 一時停止
	system("pause");

	return 0;
}

出力結果

英:GenEi LateGo
日:源暎ラテゴ
続行するには何かキーを押してください . . .

使用させて頂いたもの

  • フォント

源暎フォント置き場 - 御琥祢屋

  • 参考サイト

d.hatena.ne.jp
www.codeguru.com

あとがき

経緯について
プログラム中にインストールしていないフォントを
使用したいタイミングがあったとして
Windows環境だと、自プロセスで使用するフォントを追加する場合に、
AddFontResourceExを使用すると思います。

追加には、フォントファイルのパスが分かれば問題ないですが、
いざ使用する時、フォント名を指定する必要があります。

フォント名を明示しないといけないという柔軟さのなさを回避するには、
フォント名がフォントファイルから分かった方が都合が良いということで、
対応した結果を備忘録行き。