英語のフォント名

そこそこ調べたけど、結局使わなかったコードの断片を記録します。

症状

C++のプログラムで、フォント名(font face name)の英語表記を欲しかったのですが、日本語環境ではなかなか得ることができませんでした。つまり、下のような英語表記が欲しかったのです。

日本語 英語
MS Pゴシック MS PGothic
メイリオ Meiryo
  • gimpイラストレータInkscapeなどは英語表記のフォント名です(どうやってるのでしょう)。
  • Inkscapeは日本語表記のフォントを拒絶するのでsvgを渡せないことも起きたりします。
  • ロケール周りをいじっても、WindowsAPIのEnumFontsは日本語フォント名を返します。
  • フォントピッカーはあくまでも日本語表記になります。

解決方法

.NETの FontFamily.GetName(1033) を使う。

経緯とサンプル

  • サンプルは、VS2012Express、Win32コンソールアプリで作成しました。[空のプロジェクト]を作成して、プロジェクトのプロパティで、共通ランタイムサポート(/clr)を選択したものです。

サンプルソリューションのパック(ConsoleApplication7.zip)

  • (記事の下の方にdll化してみたものも置いてます。)
  • ちなみに、英語LCID(=1033)は、次のコードで得られます。

WORD  langid =MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
DWORD lcid   =MAKELCID( langid, SORT_DEFAULT );

  • 識別子の一覧に関しては、サンプルコード中のコメントを参照してください。
  • サンプルは
    1. .NETのフォントピッカーを開いて、
    2. マネージされた英語のフォント名をC++の文字列に変換して
    3. コンソールに表示するものです。

#pragma once

#include <SDKDDKVer.h> // windows.hのインクルードに必要で、アーキテクチャや
#include <Windows.h>   // プラットフォームを限定するためのものです。

#include <stdio.h>
#include <tchar.h>
#include <iostream>

#include <vcclr.h>      // pin_ptrを使用するためのものです。

/*
* オブジェクトの参照が必要です。ソリューションエクスプローラのプロジェクトを右クリして、
*  [プロパティ][共通プロパティ][Frameworkと参照][新しい参照の追加(N)...]
* でチェックすることで、有効化できます。コンパイラの/FUオプションになります。
* あるいは、#usingディレクティブを使って、コード中に埋め込むこともできます。
*/
#using <System.dll>                
#using <System.Windows.Forms.dll>  
#using <System.Drawing.dll>        


int main(int argc, _TCHAR* argv[])
{
	std::locale::global(std::locale("japanese"));

	System::Windows::Forms::FontDialog^ fd=gcnew System::Windows::Forms::FontDialog();
	fd->ShowDialog();
	System::Drawing::FontFamily^ ff=fd->Font->FontFamily;
	
	/*
	* MAKELANGID, MAKELCID マクロや識別子に関しては、次のような文言でWeb検索すると
	* マイクロソフトの開発者用リファレンスが参照できます。
	* 国際化に関係した識別子一覧があります。
	*
	* ・National Language Support Reference
	* ・Language Identifier Constants and Strings
	* ・Sort Order Identifiers
	*
	*/
	WORD  langid =MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
	DWORD lcid   =MAKELCID( langid, SORT_DEFAULT );

	System::String^ strFFName_EN =ff->GetName(lcid);
	System::String^ strFFName_JP =ff->GetName(0);

	/*
	* pin_ptrを使って、String^をwchar_t*に変更することで、普通のC++のように記述できます。
	* 次の文言でWeb検索すると、pin_ptr のサンプルが見れます。
	*
	* ・方法: System::String を wchar_t* または char* に変換する
	*/
	pin_ptr<const wchar_t> wchFFName_EN = PtrToStringChars(strFFName_EN);
	pin_ptr<const wchar_t> wchFFName_JP = PtrToStringChars(strFFName_JP);

	std::wcout <<L"英語:" <<(const wchar_t*)wchFFName_EN <<std::endl;
	std::wcout <<L"日本語:" <<(const wchar_t*)wchFFName_JP <<std::endl;
	
	std::wcout <<L"Press ENTER to exit:";
	std::cin.ignore();

	return 0;
}

  • .NETを使用するために、/clrオプションを指定すること、
  • #usingで適切な.dllを宣言することが必要です。
  • あるいは、プロジェクトの[共通プロパティ][Frameworkと参照]にて、参照を参加させます。

  • サンプル起動直後にフォントピッカーが開くので、フォントを選択します。

  • コンソールにフォントの日本語と英語の表記が出力されます。


DLL化したサンプル

ふっと思いついて、.NET部分をDLLに封じ込めてみました。
DLL化したサンプル(ConsoleApplication7b.zip)
メイリオ」を渡すと「Meiryo」を返すdll。「メイリオ」などと有効なフォント名でないと、何が起きるかわかりません。

メイン(ConsoleApplication.cpp)
#pragma once

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include "FontFamily\FontFamily.h"

int main(int argc, _TCHAR* argv[])
{
	std::locale::global(std::locale("japanese"));

	const wchar_t* wchNameEn =GetName(L"メイリオ");

	std::wcout <<L"英語:" <<(const wchar_t*)wchNameEn <<std::endl;
	
	std::wcout <<L"Press ENTER to exit:";
	std::cin.ignore();

	return 0;
}
DLL(FontFamily.cpp)
#include "stdafx.h"
#include "FontFamily.h"
#include <vcclr.h>
#using <System.Drawing.dll>

FONTFAMILY_API const wchar_t* GetName( const wchar_t* nameJp )
{
	System::Drawing::FontFamily^ ff 
		=gcnew System::Drawing::FontFamily( gcnew System::String(nameJp) );

	WORD  langid =MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
	DWORD lcid   =MAKELCID( langid, SORT_DEFAULT );
	System::String^ strNameEn =ff->GetName(lcid);

	pin_ptr<const wchar_t> wchNameEn =PtrToStringChars(strNameEn);
	
	return (const wchar_t*)wchNameEn;
}


  • Dllの名前がFontFamilyだったり、エクスポート関数名がGetNameだったりと非実用的なネーミングです。
  • 文字列のポインタ返しとか大丈夫なのか?とか今の僕にはわかりません。
  • 記事書いて、ご飯食べたら、ふっと思いついただけなので...
  • フォントピッカーは出ません。「メイリオ」決め打ちです。
  • vcclr.hは、PtrToStringCharsを使うためのものですね。訂正します。
  • 今思うと、なぜdll化したのだろう。単に関数化でもよかったかな?
  • ご飯食べてて、ふっと思いついた勢いで作ったので...
  • 思い出した、本体側で/clrしなくてもよいことになるからでした。

以上です。