C# 中的嵌入式资源字体无法正常工作
Embedded resource font in C# does not work correctly
我在我的资源中嵌入了一个 .ttf 字体文件(特别是 "Amatic Bold"),我正在使用下面的代码获取字体。
我尝试了这个post的代码:How do I Embed a font with my C# application? (using Visual Studio 2005)
这是我的实现:
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollection == null) _fontCollection = new PrivateFontCollection();
IntPtr fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length);
System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
_fontCollection.AddMemoryFont(fontPtr, fontData.Length);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr);
return new Font(_fontCollection.Families[0], size, style);
}
我是这样用的:
Font font = GetCustomFont(Properties.MainResources.Amatic_Bold, 25, System.Drawing.FontStyle.Bold);
字体应如下所示:
问题是字体正在加载,但使用时显示不正确;它看起来像 "Arial" 或其他标准字体,而不是它应该的样子。
如果我在 Windows 中安装字体,它就可以工作(我想这是显而易见的......)
我搜索了现有的答案,但找不到我的确切问题...
如有任何帮助,我们将不胜感激。
提前致谢。
问题可能是因为在使用字体文件时需要指定 fontfamily 确切的字体,编译器切换到默认字体。
您可以通过以下两种方法了解您所缺少的内容。
var fontFile = new FontFamily("pack://application:,,,/Resources/#YourFont");
var typeface = new Typeface(new FontFamily(new Uri("pack://application:,,,/"), "/Resources/#YourFont"), FontStyles.Normal, FontWeights.Regular, FontStretches.Normal);
var cultureinfo = new CultureInfo("en-us");
var ft = new FormattedText("YourText", cultureinfo, FlowDirection.LeftToRight,
typeface, 28, Brushes.White)
dc.DrawText(ft, new Point(0,0));
使用资源路径在客户端系统上安装字体。
PrivateFontCollection yourfont = new PrivateFontCollection();
yourfont.AddFontFile("Your font Path");
label1.Font = new Font(yourfont.Families[0], 16, FontStyle.Regular);
嗯,那...我想我明白了!
我会解释一下我所知道的 "discovered"(无论是否显而易见):
首先:Application.SetCompatibleTextRenderingDefault
必须设置为 true 才能在控件中呈现内存字体。
(也可以用Control.UseCompatibleTextRendering
)
它在 Microsoft 文档中有完美的说明,但我错过了:-(
其次:PrivateFontCollection.Families
return一系列添加的字体,但是..惊喜!它是按字母顺序排列的!
无论您添加字体的顺序是什么或使用什么方法 (AddMemoryFont
/AddFontFile
),您都将按字母顺序获得它!
因此,如果您添加了不止一种字体,然后尝试获取您添加的最后一种字体,您可能会得到错误的字体。
第三:我也尝试过 FreeCoTaskMem()
在集合中添加字体或在关闭表单时执行此操作。两者都在为我工作!
我不知道这个的确切含义...
这是我的最终代码:
//This list is used to properly dispose PrivateFontCollection after usage
static private List<PrivateFontCollection> _fontCollections;
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true); //Mandatory in order to have Memory fonts rendered in the controls.
//Dispose all used PrivateFontCollections when exiting
Application.ApplicationExit += delegate {
if (_fontCollections != null) {
foreach (var fc in _fontCollections) if (fc != null) fc.Dispose();
_fontCollections = null;
}
};
Application.Run(new frmMain());
}
void frmMain_Load(object sender, EventArgs e)
{
Font font1 = GetCustomFont(Properties.Resources.Amatic_Bold, 25, FontStyle.Bold);
//or...
Font font1 = GetCustomFont("Amatic-Bold.ttf", 25, FontStyle.Bold);
labelTestFont1.Font = font1;
Font font2 = GetCustomFont(Properties.Resources.<font_resource>, 25, FontStyle.Bold);
//or...
Font font2 = GetCustomFont("<font_filename>", 25, FontStyle.Bold);
labelTestFont2.Font = font2;
//...
}
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
IntPtr fontPtr = Marshal.AllocCoTaskMem(fontData.Length);
Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
fontCol.AddMemoryFont(fontPtr, fontData.Length);
Marshal.FreeCoTaskMem(fontPtr); //<-- It works!
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
static public Font GetCustomFont (string fontFile, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
fontCol.AddFontFile (fontFile);
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
如您所见,我决定为每种字体创建一个专属的 PrivateFontCollection,然后将其存储到一个列表中,以便在应用程序端进行最终处理。
这已在 3 台不同的 PC(均具有 Windows 7、32 和 64 位)和 3 种不同的 .ttf 字体中进行了测试。
结果示例:
我不知道我的方法是否足够好,但我希望它对其他人有用!
再详细一点:
与我的预期不同,AddMemoryFont 比 AddFontFile 慢(21 毫秒对 15 毫秒)
再次感谢所有评论!
我在我的资源中嵌入了一个 .ttf 字体文件(特别是 "Amatic Bold"),我正在使用下面的代码获取字体。 我尝试了这个post的代码:How do I Embed a font with my C# application? (using Visual Studio 2005)
这是我的实现:
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollection == null) _fontCollection = new PrivateFontCollection();
IntPtr fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length);
System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
_fontCollection.AddMemoryFont(fontPtr, fontData.Length);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr);
return new Font(_fontCollection.Families[0], size, style);
}
我是这样用的:
Font font = GetCustomFont(Properties.MainResources.Amatic_Bold, 25, System.Drawing.FontStyle.Bold);
字体应如下所示:
问题是字体正在加载,但使用时显示不正确;它看起来像 "Arial" 或其他标准字体,而不是它应该的样子。 如果我在 Windows 中安装字体,它就可以工作(我想这是显而易见的......)
我搜索了现有的答案,但找不到我的确切问题...
如有任何帮助,我们将不胜感激。 提前致谢。
问题可能是因为在使用字体文件时需要指定 fontfamily 确切的字体,编译器切换到默认字体。
您可以通过以下两种方法了解您所缺少的内容。
var fontFile = new FontFamily("pack://application:,,,/Resources/#YourFont");
var typeface = new Typeface(new FontFamily(new Uri("pack://application:,,,/"), "/Resources/#YourFont"), FontStyles.Normal, FontWeights.Regular, FontStretches.Normal);
var cultureinfo = new CultureInfo("en-us");
var ft = new FormattedText("YourText", cultureinfo, FlowDirection.LeftToRight,
typeface, 28, Brushes.White)
dc.DrawText(ft, new Point(0,0));
使用资源路径在客户端系统上安装字体。
PrivateFontCollection yourfont = new PrivateFontCollection();
yourfont.AddFontFile("Your font Path");
label1.Font = new Font(yourfont.Families[0], 16, FontStyle.Regular);
嗯,那...我想我明白了!
我会解释一下我所知道的 "discovered"(无论是否显而易见):
首先:
Application.SetCompatibleTextRenderingDefault
必须设置为 true 才能在控件中呈现内存字体。 (也可以用Control.UseCompatibleTextRendering
) 它在 Microsoft 文档中有完美的说明,但我错过了:-(其次:
PrivateFontCollection.Families
return一系列添加的字体,但是..惊喜!它是按字母顺序排列的! 无论您添加字体的顺序是什么或使用什么方法 (AddMemoryFont
/AddFontFile
),您都将按字母顺序获得它! 因此,如果您添加了不止一种字体,然后尝试获取您添加的最后一种字体,您可能会得到错误的字体。第三:我也尝试过
FreeCoTaskMem()
在集合中添加字体或在关闭表单时执行此操作。两者都在为我工作! 我不知道这个的确切含义...
这是我的最终代码:
//This list is used to properly dispose PrivateFontCollection after usage
static private List<PrivateFontCollection> _fontCollections;
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true); //Mandatory in order to have Memory fonts rendered in the controls.
//Dispose all used PrivateFontCollections when exiting
Application.ApplicationExit += delegate {
if (_fontCollections != null) {
foreach (var fc in _fontCollections) if (fc != null) fc.Dispose();
_fontCollections = null;
}
};
Application.Run(new frmMain());
}
void frmMain_Load(object sender, EventArgs e)
{
Font font1 = GetCustomFont(Properties.Resources.Amatic_Bold, 25, FontStyle.Bold);
//or...
Font font1 = GetCustomFont("Amatic-Bold.ttf", 25, FontStyle.Bold);
labelTestFont1.Font = font1;
Font font2 = GetCustomFont(Properties.Resources.<font_resource>, 25, FontStyle.Bold);
//or...
Font font2 = GetCustomFont("<font_filename>", 25, FontStyle.Bold);
labelTestFont2.Font = font2;
//...
}
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
IntPtr fontPtr = Marshal.AllocCoTaskMem(fontData.Length);
Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
fontCol.AddMemoryFont(fontPtr, fontData.Length);
Marshal.FreeCoTaskMem(fontPtr); //<-- It works!
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
static public Font GetCustomFont (string fontFile, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
fontCol.AddFontFile (fontFile);
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
如您所见,我决定为每种字体创建一个专属的 PrivateFontCollection,然后将其存储到一个列表中,以便在应用程序端进行最终处理。
这已在 3 台不同的 PC(均具有 Windows 7、32 和 64 位)和 3 种不同的 .ttf 字体中进行了测试。
结果示例:
我不知道我的方法是否足够好,但我希望它对其他人有用!
再详细一点: 与我的预期不同,AddMemoryFont 比 AddFontFile 慢(21 毫秒对 15 毫秒)
再次感谢所有评论!