我如何在当前的Windows.Forms应用程序中使用自定义.ttf字体文件?我在某个地方读到说我需要将其用作嵌入资源,但是我该如何设置System.Drawing.Font类型呢?
本文:如何嵌入 True Type 字体,展示了如何在 .NET 中实现所需要的功能。
如何嵌入 True Type 字体
出于美学或特定视觉样式等原因,某些应用程序会嵌入某些不太常见的字体,以确保无论目标系统是否已安装该字体,都可以随时使用。
这里有两个秘诀。首先,需要将字体添加到解决方案并将其标记为嵌入式资源,以便将其放置在资源中。其次,在运行时,通过流加载字体,并将其存储在 PrivateFontCollection 对象中以供后续使用。
此示例使用了一种您的系统很可能没有安装的字体。Alpha Dance 是从免费字体收藏中获取的免费 True Type 字体。将此字体添加到解决方案中,并在属性中选择“嵌入式资源”构建操作即可将其嵌入到应用程序中。
一旦文件已成功包含在资源中,您需要提供一个 PrivateFontCollection 对象来存储它,并提供一种方法将其加载到集合中。最好的位置可能是窗体加载覆盖或事件处理程序。以下代码显示了此过程。请注意如何使用 AddMemoryFont 方法。它需要指向字体保存为字节数组的内存指针。在 C# 中,我们可以使用 unsafe 关键字方便地实现此目的,但 VB 必须使用 Marshal 类的不受管控内存处理功能。当然,后一种选项也适用于不喜欢 unsafe 关键字的 C# 程序员。
PrivateFontCollection pfc = new PrivateFontCollection();
private void Form1_Load(object sender, System.EventArgs e)
{
Stream fontStream = this.GetType().Assembly.GetManifestResourceStream("embedfont.Alphd___.ttf");
byte[] fontdata = new byte[fontStream.Length];
fontStream.Read(fontdata,0,(int)fontStream.Length);
fontStream.Close();
unsafe
{
fixed(byte * pFontData = fontdata)
{
pfc.AddMemoryFont((System.IntPtr)pFontData,fontdata.Length);
}
}
}
字体可能仅提供某些可用的样式,选择不存在的字体样式将会抛出异常。为了解决这个问题,可以查询字体以查看哪些样式可用,并且只使用该字体提供的样式。以下示例演示了如何使用Alpha Dance字体来检查可用的字体样式并显示所有存在的样式。请注意,下划线和删除线样式是由字体渲染引擎构建的伪样式,实际上并没有以字形形式提供。
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
bool bold=false;
bool regular=false;
bool italic=false;
e.Graphics.PageUnit=GraphicsUnit.Point;
SolidBrush b = new SolidBrush(Color.Black);
float y=5;
System.Drawing.Font fn;
foreach(FontFamily ff in pfc.Families)
{
if(ff.IsStyleAvailable(FontStyle.Regular))
{
regular=true;
fn=new Font(ff,18,FontStyle.Regular);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
y+=20;
}
if(ff.IsStyleAvailable(FontStyle.Bold))
{
bold=true;
fn=new Font(ff,18,FontStyle.Bold);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
y+=20;
}
if(ff.IsStyleAvailable(FontStyle.Italic))
{
italic=true;
fn=new Font(ff,18,FontStyle.Italic);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
y+=20;
}
if(bold && italic)
{
fn=new Font(ff,18,FontStyle.Bold | FontStyle.Italic);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
y+=20;
}
fn=new Font(ff,18,FontStyle.Underline);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
y+=20;
fn=new Font(ff,18,FontStyle.Strikeout);
e.Graphics.DrawString(fn.Name,fn,b,5,y,StringFormat.GenericTypographic);
fn.Dispose();
}
b.Dispose();
}
图2展示了应用程序的操作。
请参考Form1_Paint事件处理程序,它具体展示如何设置System.Drawing.Font类型,基于使用System.Drawing.Text.PrivateFontCollection类。
希望这个能有所帮助。
通过p/invoke使用AddFontResourceEx API函数,传递FR_PRIVATE参数以防止安装全局字体。然后,您应该能够像往常一样将字体名称传递给Font构造函数。
编辑:如果您使用PrivateFontCollection并从外部文件加载字体,则甚至不需要这样做。如果您从嵌入的资源加载字体,请使用Ash的解决方案。