如何将字体从 privatefontcollection 内存渲染到可编辑控件

Posted

技术标签:

【中文标题】如何将字体从 privatefontcollection 内存渲染到可编辑控件【英文标题】:How to render a font from privatefontcollection memory to editable controls 【发布时间】:2016-01-11 23:36:36 【问题描述】:

这是Loading a font from resources into PrivateFontCollection results in corruption的延续

here 提供的答案对于具有 UseCompatibleTextRendering 方法可用的控件来说已经足够了,但是它似乎不适用于以文本为主要焦点的其他常见控件,例如:

列表视图 文本框 富文本框 组合框 ...还有更多...

我尝试了来自here 的信息,这基本上是在玩弄Program.cs 中的Application.SetCompatibleTextRenderingDefault 行(没有人澄清默认情况下此设置在哪里,所以我在这里记录它)。我也玩过 Telerik、DevExpress 和 Infragistics 文本控件,除了 Telerik 之外的所有文本控件都没有内置兼容文本渲染的能力。 Teleriks 控件有方法,但是它的效果为零,包括未能将前景色设置为存储的内容在属性中(另一种动物,只是注意到 Telerik radTextBox 控件的故障)。

似乎无论我如何对其进行切片,任何对文本实际有用的控件都不会使文本正确地显示方形字符,如上述原始帖子中所述。

总结:

字体正在从资源加载到内存到 PrivateFontCollection 应用程序不会崩溃

在标签上成功使用了相同的字体(UseCompatibleTextRendering 对它们起作用)- 在同一个表单上,在同一个项目中。

受此(新?)问题影响的控件严格来说是任何可以“键入”的控件,例如 TextEdit、ListView、RichText、Combo 等

说到切换、玩弄或玩弄——这意味着我已经尝试了所有可能的上述控件和/或提供给我的代码的组合。例如:Application.SetCompatibleTextRenderingDefault 本身只有 3 种可能的组合。 (true) (false) 或完全省略。完成这 3 种组合后,我继续(此处为基本故障排除,但我发现有必要解释以涵盖所有基础)添加 Telerik 控件,然后尝试 Telerik 控件中的所有组合,以及 @987654330 的所有组合@ 命令。测试的数量是指数的,即呈现可能性的可能组合的数量乘以尝试的控件数量乘以每个控件具有的呈现控件的可能性数量,等等。

【问题讨论】:

【参考方案1】:

经过大量的挖掘,并对此一无所知(包括对这个问题的驾车投票,这仍然让我感到困惑),我找到了解决这个问题的方法,似乎很多人都面临过并且也遇到过空手而归,仅将字体作为文件安装在用户系统上。正如我所想,这根本不是必需的,您可以以简单的方式嵌入字体,使其可以用于任何控件,包括 TextBox、ComboBox 等。无论您想要什么。 p>

我将把它写成一步一步的指南,介绍如何将字体嵌入到您的项目中,并让它在您想要的任何控件上正确显示。

第 1 步 - 选择受害者(字体选择)

出于演示目的(和大众需求),我将使用 FontAwesome 字体(在撰写本文时为 4.1 版)

在您的项目中,转到Project > <your project name> Properties 点击Resources(应该在左侧) 点击Add Resource按钮右侧的下拉箭头,然后选择Add Existing File

确保从下拉列表中选择All Files (*.*),然后浏览到要嵌入字体文件的位置,选择它,然后单击[打开] 按钮。

您现在应该看到如下内容:

按 [CTRL]+[S] 保存项目。

第 2 步 - 深入研究代码

复制以下代码并将其保存为“MemoryFonts.cs”,然后将其添加到您的项目中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Drawing;

public static class MemoryFonts 

    [DllImport( "gdi32.dll" )]
    private static extern IntPtr AddFontMemResourceEx( IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts );
    private static PrivateFontCollection pfc  get; set; 

    static MemoryFonts() 
        if ( pfc==null )  pfc=new PrivateFontCollection(); 
    

    public static void AddMemoryFont(byte[] fontResource) 
        IntPtr p;
        uint c = 0;

        p=Marshal.AllocCoTaskMem( fontResource.Length );
        Marshal.Copy( fontResource, 0, p, fontResource.Length );
        AddFontMemResourceEx( p, (uint)fontResource.Length, IntPtr.Zero, ref c );
        pfc.AddMemoryFont( p, fontResource.Length );
        Marshal.FreeCoTaskMem( p );

        p = IntPtr.Zero;
    

    public static Font GetFont( int fontIndex, float fontSize = 20, FontStyle fontStyle = FontStyle.Regular ) 
        return new Font(pfc.Families[fontIndex], fontSize, fontStyle);
    

    // Useful method for passing a 4 digit hex string to return the unicode character
    // Some fonts like FontAwesome require this conversion in order to access the characters
    public static string UnicodeToChar( string hex ) 
        int code=int.Parse( hex, System.Globalization.NumberStyles.HexNumber );
        string unicodeString=char.ConvertFromUtf32( code );
        return unicodeString;
    


第 3 步 - 让它漂亮(使用字体)

在主窗体上,从您的工具箱中添加一个 TextBox 控件

form_Load 事件中,输入以下代码(在我的情况下,资源是fontawesome_webfont。将其更改为您的字体资源名称)

private void Form1_Load( object sender, EventArgs e ) 
    MemoryFonts.AddMemoryFont( Properties.Resources.fontawesome_webfont );
    textBox1.Font = MemoryFonts.GetFont(
                        // using 0 since this is the first font in the collection
                        0,

                        // this is the size of the font
                        20, 

                        // the font style if any. Bold / Italic / etc
                        FontStyle.Regular
                    );

    // since I am using FontAwesome, I would like to display one of the icons
    // the icon I chose is the Automobile (fa-automobile). Looking up the unicode
    // value using the cheat sheet https://fortawesome.github.io/Font-Awesome/cheatsheet/
    // shows :  fa-automobile (alias) []
    // so I pass 'f1b9' to my UnicodeToChar method which returns the Automobile icon 
    textBox1.Text = MemoryFonts.UnicodeToChar( "f1b9" );

最终结果


您可能注意到,也可能没有注意到我使用此方法时请记住,您可能希望添加多种嵌入字体。在这种情况下,您只需为要添加的每个字体调用AddMemoryFont(),然后在使用GetFont()时使用适当的索引值(从零开始)

与微软关于PrivateFontCollection.AddMemoryFont() 的文档相反,您根本不需要使用UseCompatibleTextRenderingSetCompatibleTextRenderingDefault。我上面概述的方法允许在对象/控件中自然呈现字体。

【讨论】:

以上是关于如何将字体从 privatefontcollection 内存渲染到可编辑控件的主要内容,如果未能解决你的问题,请参考以下文章

在 VB.net/C# 中直接使用资源字体

在 c# (linux) 中找不到 PrivateFontCollection 错误

如何从 C# WPF 中的嵌入字体将字体文件添加到 Stimulsoft 报告

如何配置 BIRT 报告引擎直接从类路径加载字体?

如何从PNG图像制作字体图标?

如何使用ajax请求将印地语字体从客户端传递到服务器