C#中嵌入的资源字体无法正常工作
我在我的资源中嵌入了一个.ttf字体文件(“特别是Amatic Bold”),我正在使用下面的代码来获取字体。 我试过这篇文章的代码: 这是我的实现:C#中嵌入的资源字体无法正常工作,c#,winforms,fonts,embedded-resource,C#,Winforms,Fonts,Embedded Resource,我在我的资源中嵌入了一个.ttf字体文件(“特别是Amatic Bold”),我正在使用下面的代码来获取字体。 我试过这篇文章的代码: 这是我的实现: static public Font GetCustomFont (byte[] fontData, float size, FontStyle style) { if (_fontCollection == null) _fontCollection = new PrivateFontCollection();
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中安装字体,它会工作(我想很明显…)
我搜索了一个已有的答案,但找不到确切的问题,
任何帮助都将不胜感激。
提前感谢。问题可能是因为在使用fontfile时需要指定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);
那么。。。我想我明白了 我将解释我“发现”的内容(无论是否显而易见):
- 首先:
必须设置为true才能在控件中呈现内存字体。 (也可以使用Application.SetCompatibleTextRenderingDefault
) Microsoft文档中对其进行了完美的指定,但我忽略了以下内容:-(Control.UseCompatibleTextRendering
- 第二:
返回添加的字体数组,但是..出乎意料!它是按字母顺序排列的! 无论您添加字体的顺序或使用的方法是什么(PrivateFontCollection.Families
/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
静态私有列表fontCollections;
[状态线程]
私有静态void Main(字符串[]args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);//必须这样才能在控件中呈现内存字体。
//退出时处置所有使用的PrivateFontCollections
Application.ApplicationExit+=委托{
如果(_fontCollections!=null){
如果(fc!=null)fc.Dispose(),则为foreach(在fontCollections中为var fc);
_fontCollections=null;
}
};
运行(新的frmMain());
}
无效frmMain_加载(对象发送方,事件参数e)
{
Font font1=GetCustomFont(Properties.Resources.Amatic_Bold,25,FontStyle.Bold);
//或者。。。
Font font1=GetCustomFont(“Amatic Bold.ttf”,25,FontStyle.Bold);
labelTestFont1.Font=font1;
Font font2=GetCustomFont(Properties.Resources.,25,FontStyle.Bold);
//或者。。。
Font font2=GetCustomFont(“”,25,FontStyle.Bold);
labelTestFont2.Font=font2;
//...
}
静态公共字体GetCustomFont(字节[]fontData、浮点大小、FontStyle样式)
{
如果(_fontCollections==null)_fontCollections=new List();
PrivateFontCollection fontCol=新PrivateFontCollection();
IntPtr fontPtr=Marshal.alloctaskmem(fontData.Length);
封送处理副本(fontData,0,fontPtr,fontData.Length);
fontCol.AddMemoryFont(fontPtr,fontData.Length);
FreeCoTaskMem元帅(fontPtr);//这种可怕的错误代码就像病毒一样,非常难以清除。你是通过字体保存的,它是OpenType字体。只能在WPF或Direct2D应用程序中使用。字体映射器找到了一种可以在Winforms应用程序中工作的替代品。谢谢,@HansPassant。有没有什么好的替代方法可以不用安装字体它?当您安装字体时,它实际工作吗?然后修复此代码中的错误。在无法再使用字体并且调用了._fontCollection.Dispose()方法和_fontCollection.Families[0]之前,您不能调用Marshal.FreeCoTaskMem()始终返回第一种字体,而不是最后加载的字体。好的,我会尝试。我知道_fontCollection.Families[0]问题,这是我最初计划的行为,尽管我将对其进行修改。再次感谢。Adam,您需要重新组织内存管理,以便创建字体集合,AllocTaskMem
和AddMemoryFont
仅一次,然后仅在窗体/控件不可用时处置字体集合和FreeCoTaskMem
一次姿势。如果您试图在控件上使用字体,则对兼容文本呈现有一些要求-如果这是错误的,则字体将被忽略。谢谢,@Jerin,我会尝试一下。非常感谢,Control.UseCompatibleTextRendering是我在使用AddMemoryFont这么多小时后解决问题的方法!!