2016-04-07 116 views
2

我在我的资源中嵌入了一个.ttf字体文件(“Amatic Bold”,具体而言),我使用下面的代码获取字体。 我试过代码FOM这个帖子:How do I Embed a font with my C# application? (using Visual Studio 2005)C#中嵌入的资源字体无法正常工作

这是我实现:

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);  

字体应该是这样的: enter image description here

问题是字体正在加载但使用时不能正确显示;它看起来像是一个“Arial”或其他标准字体,而不是它应该是的。 如果我在Windows中安装的字体,它的工作原理(我想是显而易见的......)

我搜索了现有的答案,但could'nt找到我确切的问题...

任何帮助将不胜感激。 在此先感谢。

+1

这个可怕的bug代码就像病毒一样,它非常难以摆脱。您正在被字体保存,它是一种OpenType字体。仅适用于WPF或Direct2D应用程序。字体映射器找到可以在Winforms应用程序中工作的替代品。 –

+0

谢谢,@HansPassant。使用字体而不必安装它有什么好的选择吗? –

+1

当您安装字体时它实际上工作吗?然后修复此代码中的错误。您不能调用Marshal.FreeCoTaskMem(),直到不再使用字体并调用._fontCollection.Dispose()方法为止_fontCollection.Families [0]总是返回第一个字体,而不是最后一个加载的字体。 –

回答

1

那么......我想我明白了!

我会解释我所“发现”(它是否能明显与否):

  • 第一:Application.SetCompatibleTextRenderingDefault必须设置为在被渲染内存的字体控制。 (也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,然后将其存储到一个列表上的应用程序的最终处置结束。

这是在3个不同的PC(都与Windows 7,32和64位)和3个不同的.ttf字体测试。

结果的一个例子:

enter image description here

我不知道我的做法是不够好,但我相信它可能是有用的人!

一个细节: 不像我所期待的,AddMemoryFont慢则AddFontFile(21ms对15毫秒)

再次感谢所有评论!

0

问题可能是因为在使用字体文件时需要指定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); 
+0

谢谢,@Jerin,我会试一试。 –

相关问题