アプリケーションで、文字化けを回避するためのアプローチ

こんにちは、Visual Studio サポートチームです。

今回は、ミッシング グリフについてご案内いたします。

文字を表示したり、印刷する際に時折、文字化けに悩まされることがあります。
では、どうして文字化けが発生するのでしょうか?
その要因の一つとして、このミッシング グリフが挙げられます。

グリフとは 文字コードに対応する文字の形状であり、フォント ファイルに含まれるデータとなります。
アプリケーションで、文字を表示する際には、フォントと文字コードを指定すると、Win32 API や .NET Framework の内部処理では、フォントファイルを参照し、文字コードに対応するグリフを検索をします。
この検索で、グリフが見つからない場合、文字化けが発生します。

つまり、アプリケーションが指定したフォントと文字コードのミスマッチが、文字化けの原因となります。
この状態をミッシング グリフと称します。

ミッシング グリフが発生した場合には、フォント ファイルのグリフの 0 番目に代替用のグリフを用意していますが、このグリフは、"□" であったり "・" であったり、どのようなグリフが用意されているかは決まっていません。
また、Win32 API や .NET Framework の内部処理では、ミッシング グリフが発生した場合、別のフォントを代用して、ターゲットの文字コードに対するグリフの検索を行っています。
この代用処理は、代表的なフォントに対してのみ検索しており、インストールされている全てのフォントは検索していないため、残念ながらこの代用処理でもミッシンググリフを確実に回避することはできません。
また、複数のフォントを検索するため、フォント ファイルが用意している代替用のグリフを利用せず、Win32 API や .NET Framework の Runtime が個別に用意している代替用のグリフが利用されます。
これらの代替用のグリフは Win32 API や .NET Framework ごとに共通ではなく、各関数やメソッドごとに異なるグリフが利用されます。

このため、アプリケーションがフォントと文字コードのミスマッチを起こすような処理を行うと、以下の何れかの現象が発生します。

  - 指定したフォントとは異なるグリフで文字が表示もしくは印刷される。

  - "□" や "・" などの代替用のグリフで文字が表示もしくは印刷される。

このような、ミッシング グリフが発生した場合、どのグリフが代替用に利用されるかについて確定したルールはありません。
そのため、代替用のグリフに一意の文字のみが利用されるように制御したい場合、アプリケーション側で独自な実装を追加する以外には方法がありません。

アプリケーションが、文字化けに対して考慮をしないのであれば、このような動作でも問題はないと思います。
ただ、文字化けに対して、より高度な考慮をするのであれば、代替が必要であるかの判断も含めて、Win32 API や .NET Framework の Runtime に主体となる処理を任せるのではなく、アプリケーションが主体となって代替の処理を行う必要があります。

例として、FontFamily クラスを利用する場合は、以下のように複数のフォントを指定して、代替するフォントを指定する方法があります。

  myTextBlock.FontFamily = new FontFamily("Comic Sans MS, Verdana");

また、複合フォントと呼ばれる ".CompositeFont" ファイルで、文字コードとフォントのマッチングをあらかじめ指定する方法もあります。

Win32 API では、GetGlyphIndices 関数を使用して、文字コードに対するグリフが、デバイス コンテキストに割り当てられたフォントから取得できるかをチェックする方法があります。
ただ、この Win32 API では、IVS コード (Ideographic Variation Sequence) のような複雑な文字コードは利用できないため、これらの文字種を意識した場合、Uniscribe と呼ばれる API 群を利用する方法がよりよい方法となります。

なお、簡易的な方法ですが、制御コードのような、どのようなフォントでもミッシング グリフが発生することがわかっているコードをチェックし、除外することでミッシンググリフを防ぐ方法があります。
この方法は、フォントに関係なくチェックを行えますが、制御コード以外のコードのミッシング グリフは防ぐことはできません。

[参考資料]

FontFamily クラス
<https://msdn.microsoft.com/ja-jp/library/system.windows.media.fontfamily.aspx>

GetGlyphIndices
<https://msdn.microsoft.com/ja-jp/library/cc428689.aspx>

Uniscribe
<https://msdn.microsoft.com/ja-jp/library/cc422022.aspx>