如何在C#应用程序中嵌入字体? (使用Visual Studio 2005)

时间:2023-01-13 12:45:23

What is the best way to embed a truetype font within the application i'm developing? Basically i want to make sure a particular font is available to my application when installed on another machine. I have the *.ttf font file and just need a way of embedding it or automatically installing it when the application is run.

在我正在开发的应用程序中嵌入truetype字体的最佳方法是什么?基本上我想确保在我的应用程序安装在另一台机器上时可以使用特定字体。我有* .ttf字体文件,只需要一种嵌入它的方法或在运行应用程序时自动安装它。

Do i need to set the installation program to install the font during installation or can i dynamically load the font during runtime of the application? In fact both would be nice to know.

我是否需要设置安装程序以在安装期间安装字体,还是可以在应用程序运行期间动态加载字体?事实上两者都很高兴知道。

The application is being developed in C# using .NET 2.0.

该应用程序是使用.NET 2.0在C#中开发的。

4 个解决方案

#1


This blog post should help you.

这篇博文应该可以帮到你。

Basically you add the font as an embedded resource then load it into a PrivateFontCollection object.

基本上,您将字体添加为嵌入式资源,然后将其加载到PrivateFontCollection对象中。

#2


Here's Will's answer, translated to C# (untested):

这是Will的答案,翻译成C#(未经测试):

PrivateFontCollection pfc = new PrivateFontCollection();

using (Stream fontStream = GetType().Assembly.GetManifestResourceStream("Alphd___.ttf"))
{
    if (null == fontStream)
    {
        return;
    }

    int fontStreamLength = (int) fontStream.Length;

    IntPtr data = Marshal.AllocCoTaskMem(fontStreamLength);

    byte[] fontData = new byte[fontStreamLength];
    fontStream.Read(fontData, 0, fontStreamLength);

    Marshal.Copy(fontData, 0, data, fontStreamLength);

    pfc.AddMemoryFont(data, fontStreamLength);

    Marshal.FreeCoTaskMem(data);
}

along with their Paint() method:

以及他们的Paint()方法:

protected void Form1_Paint(object sender, PaintEventArgs e)
{
    bool bold = false;
    bool italic = false;

    e.Graphics.PageUnit = GraphicsUnit.Point;

    using (SolidBrush b = new SolidBrush(Color.Black))
    {
        int y = 5;

        foreach (FontFamily fontFamily in pfc.Families)
        {
            if (fontFamily.IsStyleAvailable(FontStyle.Regular))
            {
                using (Font font = new Font(fontFamily, 32, FontStyle.Regular))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }
            if (fontFamily.IsStyleAvailable(FontStyle.Bold))
            {
                bold = true;
                using (Font font = new Font(fontFamily, 32, FontStyle.Bold))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }
            if (fontFamily.IsStyleAvailable(FontStyle.Italic))
            {
                italic = true;
                using (Font font = new Font(fontFamily, 32, FontStyle.Italic))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }

            if(bold && italic)
            {
                using(Font font = new Font(fontFamily, 32, FontStyle.Bold | FontStyle.Italic))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }

            using (Font font = new Font(fontFamily, 32, FontStyle.Underline))
            {
                e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                y += 40;
            }

            using (Font font = new Font(fontFamily, 32, FontStyle.Strikeout))
            {
                e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
            }
        }
    }
}

#3


Its easier than this seems; you can embed the font as a resource in your app and access it as a strongly-typed property within the Properties namespace of your app. But the given link should be a good starting point.

它似乎比这更容易;您可以将字体作为资源嵌入到应用程序中,并将其作为应用程序的“属性”命名空间中的强类型属性进行访问。但是给定的链接应该是一个很好的起点。


For the VB-disabled:

对于VB禁用:

Add the font as a resource in your application. Call the resource MyFontLol. You can access this resource (as a byte array) from Properties.Resources.MyFontLol.

将字体添加为应用程序中的资源。调用资源MyFontLol。您可以从Properties.Resources.MyFontLol访问此资源(作为字节数组)。

I haven't tested the following, but it appears to be workable:

我没有测试过以下内容,但它似乎可行:

public void LoadMyFontLolKThx()
{
    // get our font and wrap it in a memory stream
    byte[] myFont = Properties.Resources.MyFontLol;
    using (var ms = new MemoryStream(myFont))
    {
        // used to store our font and make it available in our app
        PrivateFontCollection pfc = new PrivateFontCollection();
        // The next call requires a pointer to our memory font
        // I'm doing it this way; not sure what best practice is
        GCHandle handle = GCHandle.Alloc(ms, GCHandleType.Pinned);
        // If Length > int.MaxValue this will throw
        checked
        {
            pfc.AddMemoryFont(
                handle.AddrOfPinnedObject(), (int)ms.Length); 
        }
        var font = new Font(pfc.Families[0],12);

        // use your font here
    }
}

One last note. The PFC stores the font as a GDI+ font. These aren't compatible with some forms controls. From the docs:

最后一点。 PFC将字体存储为GDI +字体。这些与某些表单控件不兼容。来自文档:

To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.

要使用内存字体,必须使用GDI +呈现控件上的文本。使用SetCompatibleTextRenderingDefault方法,传递true,通过将控件的UseCompatibleTextRendering属性设置为true,在应用程序或单个控件上设置GDI +呈现。某些控件无法使用GDI +呈现。

#4


it might not be the best way but couldn't you just include the font with your resources and then copy it to the font's folder on the windows dir?

它可能不是最好的方法,但你不能只用你的资源包含字体,然后将其复制到windows目录上的字体文件夹?

#1


This blog post should help you.

这篇博文应该可以帮到你。

Basically you add the font as an embedded resource then load it into a PrivateFontCollection object.

基本上,您将字体添加为嵌入式资源,然后将其加载到PrivateFontCollection对象中。

#2


Here's Will's answer, translated to C# (untested):

这是Will的答案,翻译成C#(未经测试):

PrivateFontCollection pfc = new PrivateFontCollection();

using (Stream fontStream = GetType().Assembly.GetManifestResourceStream("Alphd___.ttf"))
{
    if (null == fontStream)
    {
        return;
    }

    int fontStreamLength = (int) fontStream.Length;

    IntPtr data = Marshal.AllocCoTaskMem(fontStreamLength);

    byte[] fontData = new byte[fontStreamLength];
    fontStream.Read(fontData, 0, fontStreamLength);

    Marshal.Copy(fontData, 0, data, fontStreamLength);

    pfc.AddMemoryFont(data, fontStreamLength);

    Marshal.FreeCoTaskMem(data);
}

along with their Paint() method:

以及他们的Paint()方法:

protected void Form1_Paint(object sender, PaintEventArgs e)
{
    bool bold = false;
    bool italic = false;

    e.Graphics.PageUnit = GraphicsUnit.Point;

    using (SolidBrush b = new SolidBrush(Color.Black))
    {
        int y = 5;

        foreach (FontFamily fontFamily in pfc.Families)
        {
            if (fontFamily.IsStyleAvailable(FontStyle.Regular))
            {
                using (Font font = new Font(fontFamily, 32, FontStyle.Regular))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }
            if (fontFamily.IsStyleAvailable(FontStyle.Bold))
            {
                bold = true;
                using (Font font = new Font(fontFamily, 32, FontStyle.Bold))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }
            if (fontFamily.IsStyleAvailable(FontStyle.Italic))
            {
                italic = true;
                using (Font font = new Font(fontFamily, 32, FontStyle.Italic))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }

            if(bold && italic)
            {
                using(Font font = new Font(fontFamily, 32, FontStyle.Bold | FontStyle.Italic))
                {
                    e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                }
                y += 40;
            }

            using (Font font = new Font(fontFamily, 32, FontStyle.Underline))
            {
                e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
                y += 40;
            }

            using (Font font = new Font(fontFamily, 32, FontStyle.Strikeout))
            {
                e.Graphics.DrawString(font.Name, font, b, 5, y, StringFormat.GenericTypographic);
            }
        }
    }
}

#3


Its easier than this seems; you can embed the font as a resource in your app and access it as a strongly-typed property within the Properties namespace of your app. But the given link should be a good starting point.

它似乎比这更容易;您可以将字体作为资源嵌入到应用程序中,并将其作为应用程序的“属性”命名空间中的强类型属性进行访问。但是给定的链接应该是一个很好的起点。


For the VB-disabled:

对于VB禁用:

Add the font as a resource in your application. Call the resource MyFontLol. You can access this resource (as a byte array) from Properties.Resources.MyFontLol.

将字体添加为应用程序中的资源。调用资源MyFontLol。您可以从Properties.Resources.MyFontLol访问此资源(作为字节数组)。

I haven't tested the following, but it appears to be workable:

我没有测试过以下内容,但它似乎可行:

public void LoadMyFontLolKThx()
{
    // get our font and wrap it in a memory stream
    byte[] myFont = Properties.Resources.MyFontLol;
    using (var ms = new MemoryStream(myFont))
    {
        // used to store our font and make it available in our app
        PrivateFontCollection pfc = new PrivateFontCollection();
        // The next call requires a pointer to our memory font
        // I'm doing it this way; not sure what best practice is
        GCHandle handle = GCHandle.Alloc(ms, GCHandleType.Pinned);
        // If Length > int.MaxValue this will throw
        checked
        {
            pfc.AddMemoryFont(
                handle.AddrOfPinnedObject(), (int)ms.Length); 
        }
        var font = new Font(pfc.Families[0],12);

        // use your font here
    }
}

One last note. The PFC stores the font as a GDI+ font. These aren't compatible with some forms controls. From the docs:

最后一点。 PFC将字体存储为GDI +字体。这些与某些表单控件不兼容。来自文档:

To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.

要使用内存字体,必须使用GDI +呈现控件上的文本。使用SetCompatibleTextRenderingDefault方法,传递true,通过将控件的UseCompatibleTextRendering属性设置为true,在应用程序或单个控件上设置GDI +呈现。某些控件无法使用GDI +呈现。

#4


it might not be the best way but couldn't you just include the font with your resources and then copy it to the font's folder on the windows dir?

它可能不是最好的方法,但你不能只用你的资源包含字体,然后将其复制到windows目录上的字体文件夹?