DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

システムにインストールされていないフォントを使用する

ここでは、システムにインストールされていないフォントをファイルやリソースから読み込んで、Fontオブジェクトを作成する方法を紹介します。

なおシステムにインストールされているフォントを取得する方法については、「インストールされているフォントを取得する」をご覧ください。

フォントファイルを読み込む方法

システムにインストールされていないフォントを使用するには、PrivateFontCollectionクラス(System.Drawing.Text名前空間)を使用します。

.ttfファイルのようなフォントファイルからフォントをPrivateFontCollectionに追加するには、AddFontFileメソッドを使います。

MSDNによると、AddFontFileメソッドはTrueTypeをサポートしていますが、OpenTypeフォントは制限付きでしかサポートしていません。また、Windows 2000より古いOSでは使用できません。

以下に、和田研細丸ゴシックの「wlmaru2004p4u.ttf」というフォントファイルを使用する例を示します。

VB.NET
コードを隠すコードを選択
'PrivateFontCollectionオブジェクトを作成する
Dim pfc As New System.Drawing.Text.PrivateFontCollection()
'PrivateFontCollectionにフォントを追加する
pfc.AddFontFile("C:\test\wlmaru2004p4u.ttf")
'同様にして、複数のフォントを追加できる
'pfc.AddFontFile("C:\test\wlmaru20044u.ttf")

'PrivateFontCollectionに追加されているフォントの名前を列挙する
For Each ff As System.Drawing.FontFamily In pfc.Families
    Console.WriteLine(ff.Name)
Next

'PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する
Dim f As New System.Drawing.Font(pfc.Families(0), 12)

'Labelコントロールのフォントに設定する
Label1.Font = f

'後始末
pfc.Dispose()
C#
コードを隠すコードを選択
//PrivateFontCollectionオブジェクトを作成する
System.Drawing.Text.PrivateFontCollection pfc =
    new System.Drawing.Text.PrivateFontCollection();
//PrivateFontCollectionにフォントを追加する
pfc.AddFontFile(@"C:\test\wlmaru2004p4u.ttf");
//同様にして、複数のフォントを追加できる
//pfc.AddFontFile(@"C:\test\wlmaru20044u.ttf");

//PrivateFontCollectionに追加されているフォントの名前を列挙する
foreach (System.Drawing.FontFamily ff in pfc.Families)
{
    Console.WriteLine(ff.Name);
}

//PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する
System.Drawing.Font f =
    new System.Drawing.Font(pfc.Families[0], 12);

//Labelコントロールのフォントに設定する
Label1.Font = f;

//後始末
pfc.Dispose();

リソースに埋め込んだフォントを使用する方法

フォントをリソースに埋め込んだ時は、埋め込んだフォントをバイト配列で読み込み、そのメモリのポインターをAddMemoryFontメソッドに渡します。

MSDNによると、メモリフォントを使用する場合はGDI+で描画する必要があります。

リソースにデータを埋め込む方法については、「Visual Studioでリソースを管理する」や「画像やテキストファイルを実行ファイルに埋め込む」をご覧ください。

以下に、和田研細丸ゴシック(wlmaru2004p4u.ttf)がリソースに埋め込まれている時、これを使用する例を示します。

この例では、リソースは「Visual Studioでリソースを管理する」の方法で埋め込まれているものとします。「画像やテキストファイルを実行ファイルに埋め込む」の方法でリソースを埋め込んだ時は、コメントの「または、次のようにしてリソースを読み込む」以下を参考にして下さい。

また、C#では、アンセーフコードが許可されている(プロジェクトのプロパティで、「ビルド」タブの「アンセーフコードの許可」が有効になっている)ものとします。許可しない場合は、コメントの「または、次のようにしてポインターを取得する」以下を参考にして下さい。

VB.NET
コードを隠すコードを選択
'PrivateFontCollectionオブジェクトを作成する
Dim pfc As New System.Drawing.Text.PrivateFontCollection()

'リソース(wlmaru2004p4u)をバイト配列に読み込む
Dim fontBuf As Byte() = My.Resources.wlmaru2004p4u

'または、次のようにしてリソースを読み込む
'Dim asm As System.Reflection.Assembly = _
'    System.Reflection.Assembly.GetExecutingAssembly()
'Dim strm As System.IO.Stream = _
'    asm.GetManifestResourceStream("Project1.wlmaru2004p4u.ttf")
'Dim fontBuf As Byte() = New Byte(strm.Length - 1) {}
'strm.Read(fontBuf, 0, fontBuf.Length)
'strm.Close()

'バイト配列のポインターを取得する
Dim fontBufPtr As IntPtr = System.Runtime.InteropServices. _
    Marshal.AllocCoTaskMem(fontBuf.Length)
System.Runtime.InteropServices. _
    Marshal.Copy(fontBuf, 0, fontBufPtr, fontBuf.Length)
'PrivateFontCollectionにフォントを追加する
pfc.AddMemoryFont(fontBufPtr, fontBuf.Length)
System.Runtime.InteropServices. _
    Marshal.FreeCoTaskMem(fontBufPtr)

'PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する
Dim f As New System.Drawing.Font(pfc.Families(0), 12)

'Labelコントロールのフォントに設定する
'GDI+で描画されるようにする
Label1.UseCompatibleTextRendering = True
Label1.Font = f

'後始末
pfc.Dispose()
C#
コードを隠すコードを選択
//PrivateFontCollectionオブジェクトを作成する
System.Drawing.Text.PrivateFontCollection pfc =
    new System.Drawing.Text.PrivateFontCollection();

//リソース(wlmaru2004p4u)をバイト配列に読み込む
byte[] fontBuf = Properties.Resources.wlmaru2004p4u;

//または、次のようにしてリソースを読み込む
//System.Reflection.Assembly asm =
//    System.Reflection.Assembly.GetExecutingAssembly();
//System.IO.Stream strm =
//    asm.GetManifestResourceStream("Project1.wlmaru2004p4u.ttf");
//byte[] fontBuf = new byte[strm.Length];
//strm.Read(fontBuf, 0, fontBuf.Length);
//strm.Close();

//バイト配列のポインターを取得する
//アンセーフコードが許可されている必要がある
unsafe
{
    fixed (byte* pFontBuf = fontBuf)
    {
        //PrivateFontCollectionにフォントを追加する
        pfc.AddMemoryFont((IntPtr)pFontBuf, fontBuf.Length);
    }
}

//または、次のようにしてポインターを取得する
//IntPtr fontBufPtr = System.Runtime.InteropServices.
//    Marshal.AllocCoTaskMem(fontBuf.Length);
//System.Runtime.InteropServices.
//    Marshal.Copy(fontBuf, 0, fontBufPtr, fontBuf.Length);
////PrivateFontCollectionにフォントを追加する
//pfc.AddMemoryFont(fontBufPtr, fontBuf.Length);
//System.Runtime.InteropServices.
//    Marshal.FreeCoTaskMem(fontBufPtr);

//PrivateFontCollectionの先頭のフォントのFontオブジェクトを作成する
System.Drawing.Font f =
    new System.Drawing.Font(pfc.Families[0], 12);

//Labelコントロールのフォントに設定する
//GDI+で描画されるようにする
Label1.UseCompatibleTextRendering = true;
Label1.Font = f;

//後始末
pfc.Dispose();

TextBoxコントロールなどでメモリフォントを使用する

先に説明した通り、AddMemoryFontメソッドを使用する場合は、GDI+で描画する必要があります。そのため、TextBoxなどのコントロールでは、通常この方法が使えません。しかし、「Using an embedded font on a textbox」によると、AddMemoryFontメソッドを呼び出す前にAddFontMemResourceEx functionを呼び出しておけば、うまく行くということです。

つまり、例えば以下のようにします。

VB.NET
コードを隠すコードを選択
<System.Runtime.InteropServices.DllImport("gdi32.dll", _
    ExactSpelling:=True)>
Private Shared Function AddFontMemResourceEx(pbFont As Byte(), _
    cbFont As Integer, pdv As IntPtr, ByRef pcFonts As UInteger _
    ) As IntPtr
End Function

Private Sub Button1_Click(sender As Object, e As EventArgs _
                          ) Handles Button1.Click

    Dim pfc As New System.Drawing.Text.PrivateFontCollection()
    Dim fontBuf As Byte() = My.Resources.wlcmaru2004p4u


    Dim fontBufPtr As IntPtr = System.Runtime.InteropServices. _
        Marshal.AllocCoTaskMem(fontBuf.Length)
    System.Runtime.InteropServices. _
        Marshal.Copy(fontBuf, 0, fontBufPtr, fontBuf.Length)

    'AddFontMemResourceExを呼び出す
    Dim cFonts As UInteger
    AddFontMemResourceEx(fontBuf, fontBuf.Length, IntPtr.Zero, cFonts)

    pfc.AddMemoryFont(fontBufPtr, fontBuf.Length)
    System.Runtime.InteropServices. _
        Marshal.FreeCoTaskMem(fontBufPtr)
    Dim f As New System.Drawing.Font(pfc.Families(0), 12)

    'TextBoxコントロールのフォントに設定する
    TextBox1.Font = f

    pfc.Dispose()
End Sub
C#
コードを隠すコードを選択
[System.Runtime.InteropServices.DllImport("gdi32.dll",
    ExactSpelling = true)]
private static extern IntPtr AddFontMemResourceEx(
    byte[] pbFont, int cbFont, IntPtr pdv, out uint pcFonts);

private void Button1_Click(object sender, EventArgs e)
{
    System.Drawing.Text.PrivateFontCollection pfc =
        new System.Drawing.Text.PrivateFontCollection();
    byte[] fontBuf = Properties.Resources.wlcmaru2004p4u;

    IntPtr fontBufPtr = System.Runtime.InteropServices.
        Marshal.AllocCoTaskMem(fontBuf.Length);
    System.Runtime.InteropServices.
        Marshal.Copy(fontBuf, 0, fontBufPtr, fontBuf.Length);

    //AddFontMemResourceExを呼び出す
    uint cFonts;
    AddFontMemResourceEx(fontBuf, fontBuf.Length, IntPtr.Zero, out cFonts);

    pfc.AddMemoryFont(fontBufPtr, fontBuf.Length);
    System.Runtime.InteropServices.
        Marshal.FreeCoTaskMem(fontBufPtr);

    System.Drawing.Font f =
        new System.Drawing.Font(pfc.Families[0], 12);

    //TextBoxコントロールのフォントに設定する
    TextBox1.Font = f;

    pfc.Dispose();
}
  • 履歴:
  • 2016/3/13 「TextBoxコントロールなどでメモリフォントを使用する」を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。