如何在WinForms应用程序中嵌入自己的字体?

41

我想在我的WinForms应用程序中嵌入字体,这样我就不用担心它们是否已安装在计算机上。我在MSDN网站上搜索了一些内容,并找到了一些有关使用本地Windows API调用的提示,例如由Scott Hanselman链接到的Michael Caplan的教程。现在,我真的必须费这么大劲吗?我不能只使用我的应用程序的资源部分吗?

如果不行,我可能会选择安装路线。在那种情况下,我能否通过将字体文件复制到Windows \ Fonts文件夹来以编程方式完成?

我意识到有许可问题。


2
你可以这样做,但也要注意,就像软件字体一样,字体也有许可证,你需要确保不违反任何禁止嵌入和部署的许可证。 - Rad
5个回答

65

以下是我在VS 2013中实现的方法,无需使用unsafe块。

嵌入资源

  1. 双击Resources.resx,在设计器工具栏中单击“添加资源/添加现有文件”,然后选择您的.ttf文件。
  2. 在解决方案资源管理器中,右键单击您的.ttf文件(现在在资源文件夹中),并转到属性。将“生成操作”设置为“嵌入的资源”。

将字体加载到内存中

  1. 在Form1.cs文件中添加using System.Drawing.Text;

  2. 在默认构造函数上方和内部添加代码以在内存中创建字体(不使用其他示例中显示的“不安全”方式)。下面是我整个Form1.cs文件:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Reflection;

using System.Drawing.Text;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont,
            IntPtr pdv, [System.Runtime.InteropServices.In] ref uint pcFonts);

        private PrivateFontCollection fonts = new PrivateFontCollection();

        Font myFont;

        public Form1()
        {
            InitializeComponent();

            byte[] fontData = Properties.Resources.MyFontName;
            IntPtr fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length);
            System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
            uint dummy = 0;
            fonts.AddMemoryFont(fontPtr, Properties.Resources.MyFontName.Length);
            AddFontMemResourceEx(fontPtr, (uint)Properties.Resources.MyFontName.Length, IntPtr.Zero, ref dummy);
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr);

            myFont = new Font(fonts.Families[0], 16.0F);
        }
    }
}

使用您的字体

  1. 在主表单中添加标签,并在Form1.cs中添加加载事件来设置字体:

private void Form1_Load(object sender, EventArgs e)
{
    label1.Font = myFont;
}

1
这对我不起作用。我的字体在“Properties.Resources”下没有显示。 - James Donnelly
3
这句话的意思是:“它不应该出现在 Properties.Resources 下。当你导入资源时,在项目根目录下会创建一个名为 Resources 的单独文件夹。”请注意,我已经尽力使翻译更加通俗易懂了,但并没有改变原文的含义。 - Pyroglyph
多个ttf字体文件如常规、粗体和斜体怎么处理? - user3763113
抱歉,我不明白。在哪里可以设置字体名称,以便从资源文件夹中获取文件?字体在那里,但我没有看到提供的代码中调用它的地方。 - Christian Verner
@ChristianVerner 将 MyFontName 替换为您的字体的实际名称。 - Ooker
如何为所有控件使用自定义字体并尊重它们自己的大小? - Ooker

8
// specify embedded resource name
string resource = "embedded_font.PAGAP___.TTF";

// receive resource stream
Stream fontStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource);

// create an unsafe memory block for the font data
System.IntPtr data = Marshal.AllocCoTaskMem((int)fontStream.Length);

// create a buffer to read in to
byte[] fontdata = new byte[fontStream.Length];

// read the font data from the resource
fontStream.Read(fontdata, 0, (int)fontStream.Length);

// copy the bytes to the unsafe memory block
Marshal.Copy(fontdata, 0, data, (int)fontStream.Length);

// pass the font to the font collection
private_fonts.AddMemoryFont(data, (int)fontStream.Length);

// close the resource stream
fontStream.Close();

// free up the unsafe memory
Marshal.FreeCoTaskMem(data);

4
private_fonts 定义在哪里? - MetaFight

7
我将一个随意下载的字体拖放到我的资源中,这样就可以使用了。虽然需要文件,但我猜你也可以用它来安装字体?
public Form1()
{
    string filename = @"C:\lady.gaga";
    File.WriteAllBytes(filename, Resources.KBREINDEERGAMES);
    PrivateFontCollection pfc = new PrivateFontCollection();
    pfc.AddFontFile(filename);

    Label label = new Label();
    label.AutoSize = true;
    label.Font = new Font(pfc.Families[0], 16);
    label.Text = "hello world";
    Controls.Add(label);
}

2

我能不能只使用我的应用程序的资源部分呢?

可以,但需要使用本地资源而不是.NET资源(即使用rc.exe,本地资源编译器)。


-6

我会采用Knighter的嵌入字体方法,但是当涉及到更改字体时,我选择这段代码:

YourLabel.Font = new Font("Arial", 24,FontStyle.Bold);

更多信息请参见:最简单的更改字体和字号的方法


这并没有真正回答问题。 - TylerH
老兄,它解决了更改字体的问题。如果您想要加粗字体,那么您可以轻松地使用我提供的代码进行更改。更改字体大小?使用该代码即可。 - Jebbidan
@Jebbidan - 在我的电脑上,“Heletivica”字体因专利和版税原因被更改为“Arial”,以避免微软公司被起诉。 - fletchsod
1
问题是关于将非标准字体嵌入应用程序中,而不是为现有字体创建Font对象。 - Dave Cousineau
@Jebbidan 兄弟?!要有点礼貌! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接