我有一个 Windows 窗体应用程序,我正在尝试使用文件中的字体。具体来说是 B612 字体,但我认为这没有任何区别。
我尝试使用 PrivateFontCollection.AddFontFile(string) 方法加载它。字体应该正确加载,因为我没有收到任何异常,并且我还迭代了集合的字体系列并且字体就在那里。不幸的是,这有一个问题:它不起作用。文本使用后备字体呈现。
我什至尝试运行 Microsoft 的这个示例。不安装字体:
安装字体后:
请注意,如果字体文件位于预期目录下。否则程序将无法运行。
上面的内容非常无用,因为我希望用户能够将他们的字体直接放到目录中,因为他们可能没有安装字体的所有管理权限。将字体作为资源嵌入也无济于事,因为它会降低灵活性。
是否可以从文件中加载字体而不安装它? 我正在 .NET Framework 4.8 Windows 10.0.19045 上尝试此操作
是的,我知道我没有发布任何代码。该代码位于我链接的示例中。诚然,互联网上的死链接多于活链接。所以这里是示例的稍微修改版本,其中屏幕截图基于:
public partial class Form1 : Form
{
private FontFamily[] fontFamilies;
public Form1()
{
InitializeComponent();
PrivateFontCollection privateFontCollection = new PrivateFontCollection();
string[] ttfFiles = Directory.GetFiles("C:\\ProgramData\\.darssy 3.2\\Resources\\Fonts", "*.ttf");
foreach (string ttfFile in ttfFiles)
{
privateFontCollection.AddFontFile(ttfFile);
}
fontFamilies = privateFontCollection.Families;
Disposed += (_, _) =>
{
Console.WriteLine("Disposing");
privateFontCollection.Dispose();
};
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
PointF pointF = new PointF(10, 0);
SolidBrush solidBrush = new SolidBrush(Color.Black);
int count = 0;
count = fontFamilies.Length;
for (int j = 0; j < count; ++j)
{
string familyName = fontFamilies[j].Name;
if (fontFamilies[j].IsStyleAvailable(FontStyle.Regular))
{
Font regFont = new Font(
familyName,
16,
FontStyle.Regular,
GraphicsUnit.Pixel);
e.Graphics.DrawString(
$"{familyName} {FontStyle.Regular}",
regFont,
solidBrush,
pointF);
pointF.Y += regFont.Height;
}
//so on and so forth for the rest of the styles
pointF.Y += 10;
}
}
}
我尝试让示例尽可能接近原始示例。我的更改是删除其余字体样式的重复代码,删除说明明显的荒谬注释,并将初始化和处理移至构造函数。
这个例子非常明确:
传递给 Font 构造函数的第一个参数是字体系列名称(不是 FontFamily 对象,与 Font 构造函数的其他变体的情况一样)
(强调我的)
当你阅读它时,你的想法很酷,这就是我正在寻找的!当然,直到您运行该示例并意识到现实与该示例的声明相去甚远。
然后 dr.null 在他们的评论中指出“看看这个问答,看看它是否有效”。在该示例中,直接传递 FontFamily;我尝试了一下,当然成功了。只是这不是我想要的,但我稍后会谈到。
我查看了 FontFamily 代码以及它是如何从字符串创建的。它调用https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-fontfamily-flat,返回结果为 14,映射到“未找到字体系列”。这意味着要么该示例是错误的,要么是 GDI+ 中存在错误。我会犯第一种情况,就像在这个answer中指出的那样:
PrivateFontCollection 在这种情况下可能不太容易使用,因为它不会使字体在您的应用程序中全局可用,但必须用作 Font 的构造函数参数。必须将引用传递给 FontFamily 使其完全不切实际。我正在从 json 配置文件中读取文件。在那里,我将字体系列作为字符串,并依靠 GDI+“魔法”来解析实际的 FontFamily 对象。更改此不变量将对应用程序产生影响,这可能会超过其好处。
这给我们留下了三个选择: