将资源中的字体加载到 PrivateFontCollection 会导致损坏重新发布

Loading a font from resources into PrivateFontCollection results in corruption repost

我在将字体从资源加载到 PrivateFontCollection 时遇到一些困难。

当我开始这个时,我成功地从一个文件中加载了字体,但是我希望将字体嵌入到我的项目中(这样用户端的文件混乱就会少一些,同时 IO 也会少一些)申请是 运行).

以下代码将加载字体、获取正确的名称并允许缩放,但是 none 的字符会正确显示。

static class Foo {

  public static string FontAwesomeTTF { get; set; }

  public static Font FontAwesome { get; set; }

  public static float Size {  get; set; }

  public static FontStyle Style { get; set; }

  private static PrivateFontCollection pfc { get; set; }

  static Foo() {
    // This was set when loading from a file.
    //  FontAwesomeTTF = "fontawesome-webfont.ttf";
    Style = FontStyle.Regular;
    Size = 20;

    if ( pfc==null ) {
      pfc=new PrivateFontCollection();
      if ( FontAwesomeTTF==null ) {
        var fontBytes=Properties.Resources.fontawesome_webfont;
        var fontData=Marshal.AllocCoTaskMem( fontBytes.Length );
        Marshal.Copy( fontBytes, 0, fontData, fontBytes.Length );
        pfc.AddMemoryFont( fontData, fontBytes.Length );
        Marshal.FreeCoTaskMem( fontData );
      } else {
        pfc.AddFontFile( FontAwesomeTTF );
      }
    }
    FontAwesome = new Font(pfc.Families[0], Size, Style);
  }

  private static string UnicodeToChar( string hex ) {
    int code=int.Parse( hex, System.Globalization.NumberStyles.HexNumber );
    string unicodeString=char.ConvertFromUtf32( code );
    return unicodeString;
  }

  public static string glass { get { return UnicodeToChar("f000"); } }

}

用法示例:

label1.Font = Foo.FontAwesome;
label1.Text = Foo.glass;

这是从内存加载的样子:

这是从文件加载的样子:

我在嵌入式资源和基于文件的测试中都使用了当前的 FontAwesome TTF 文件。似乎当嵌入的东西在翻译中或从嵌入加载时丢失或加扰。我需要帮助才能完成这项工作,以便我可以将字体从嵌入式资源加载到 PrivateFontCollection。

有一些 'solutions' 我在 SO 上看过,但是它们已经过时了,commands/accessors 中的一些或全部在 Visual Studio 2013 年不再可用(文章解决方案是4-5 年前)。一些示例 'solutions' 以及为什么它们不起作用:

Solution #1 - 这不能用作字体 returns null 的访问器字符串。在我的例子中,访问器是 MyProject.Properties.Resources.fontawesome_webfont

Solution #2 - 此解决方案最接近,但用于访问资源的方法同样不再有效。我上面的代码实现了一个收获版本,去掉了将 byte[] 数组传递到内存然后从内存加载的核心概念。由于在我的例子中资源的 get{} 属性 returns 已经是一个 byte[] 数组,所以没有必要 'convert' 它进入字节数组,因此我(看似)通过更新代码以使用较新的访问器,能够安全地删除该部分代码。

无论哪种情况,我都想要一个解决此问题的方法,允许我将字体文件从嵌入式资源加载到 PrivateFontCollection。

AddMemoryFont's remarks section 说:

To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.

我在本地重现了您的问题,并将您的使用示例更改为:

label1.Font = Foo.FontAwesome;
label1.Text = Foo.glass;
label1.UseCompatibleTextRendering = true;

这会为该标签打开 GDI+ 渲染,允许添加 AddMemoryFont 的字体正确渲染。