如何从 privatefontcollection 内存中渲染字体到可编辑控件
How to render a font from privatefontcollection memory to editable controls
这是
的延续
提供的答案 对于具有 UseCompatibleTextRendering
方法可用的控件来说已经足够了,但是它似乎不适用于其他以文本为主要焦点的常见控件,例如:
- 列表视图
- 文本框
- 富文本框
- 组合框
- ...还有更多...
我尝试了来自 here 的信息,这些信息基本上是在玩弄 Program.cs
中的 Application.SetCompatibleTextRenderingDefault
行(没有人说明默认设置在哪里,所以我在这里记录它).我还玩过 Telerik、DevExpress 和 Infragistics 文本控件,除了 Telerik 之外,所有控件都没有内置兼容文本呈现的能力。Teleriks 控件有这个方法,但是它的效果为零,包括无法将前景色设置为存储的内容在 属性(另一种动物,只是注意到 Telerik radTextBox 控件的故障)。
似乎无论我如何分割它,任何实际对文本有用的控件都不会呈现正确显示方块字符的文本,如上面提到的原始 post 中所述。
总结:
- 字体正在从资源加载到内存中到 PrivateFontCollection
- 应用程序不会崩溃
在标签上成功使用了相同的字体(UseCompatibleTextRendering 适用于它们)- 在相同的表单上,在相同的项目中。
受此(新?)问题影响的控件严格来说是任何可能 'type' 的控件,例如 TextEdit、ListView、RichText、Combo 等
当谈到切换、玩弄或玩耍时——这意味着我已经尝试了提供给我的所述控件 and/or 代码的所有可能组合。例如:Application.SetCompatibleTextRenderingDefault
本身只有 3 种可能的组合。 (true)
(false)
或完全省略。完成这 3 种组合后,我继续(这里是基本故障排除,但我发现有必要解释以涵盖所有基础)添加 Telerik 控件,然后尝试 Telerik 控件中的所有组合,并结合 Application.SetCompatibleTextRenderingDefault
命令。测试的数量是指数级的,即呈现可能性的可能组合数量乘以尝试的控件数量乘以每个控件具有的呈现控件的可能性数量,依此类推。
经过大量的挖掘,并在这个问题上一无所获(包括对这个问题的 drive-by 否决,这仍然让我感到困惑),我找到了这个问题的解决方案,似乎很多人都面临过并且还提出 empty-handed 求助于将字体作为文件安装在用户系统上。正如我所想,这根本不是必需的,您可以以一种简单的方式嵌入字体,这允许它在 any 控件上使用,包括 TextBox、ComboBox 等。随心所欲.
我将把它写成一个步骤 by-step 指南,介绍如何将字体嵌入到您的项目中并使其在您需要的任何控件上正确显示。
第 1 步 - 选择你的受害者(字体选择)
出于演示目的(和大众需求),我将使用 FontAwesome 字体(撰写本文时为 v 4.1)
- 在您的项目中,转到
Project > <your project name> Properties
- 点击
Resources
(应该在左边)
- 单击
Add Resource
按钮右侧的下拉箭头,然后 select Add Existing File
。
- 确保
All Files (*.*)
已从下拉菜单中 select 编辑,然后浏览到您希望嵌入字体文件的位置,select 它,然后单击 [打开] 按钮。
您现在应该会看到如下内容:
- 按 [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()
时使用适当的索引值(从零开始)
与 Microsoft 关于 PrivateFontCollection.AddMemoryFont() 的文档相反,您根本不需要使用 UseCompatibleTextRendering
或 SetCompatibleTextRenderingDefault
。我上面概述的方法允许在 objects/controls.
中自然呈现字体
这是
提供的答案 UseCompatibleTextRendering
方法可用的控件来说已经足够了,但是它似乎不适用于其他以文本为主要焦点的常见控件,例如:
- 列表视图
- 文本框
- 富文本框
- 组合框
- ...还有更多...
我尝试了来自 here 的信息,这些信息基本上是在玩弄 Program.cs
中的 Application.SetCompatibleTextRenderingDefault
行(没有人说明默认设置在哪里,所以我在这里记录它).我还玩过 Telerik、DevExpress 和 Infragistics 文本控件,除了 Telerik 之外,所有控件都没有内置兼容文本呈现的能力。Teleriks 控件有这个方法,但是它的效果为零,包括无法将前景色设置为存储的内容在 属性(另一种动物,只是注意到 Telerik radTextBox 控件的故障)。
似乎无论我如何分割它,任何实际对文本有用的控件都不会呈现正确显示方块字符的文本,如上面提到的原始 post 中所述。
总结:
- 字体正在从资源加载到内存中到 PrivateFontCollection
- 应用程序不会崩溃
在标签上成功使用了相同的字体(UseCompatibleTextRendering 适用于它们)- 在相同的表单上,在相同的项目中。
受此(新?)问题影响的控件严格来说是任何可能 'type' 的控件,例如 TextEdit、ListView、RichText、Combo 等
当谈到切换、玩弄或玩耍时——这意味着我已经尝试了提供给我的所述控件 and/or 代码的所有可能组合。例如:
Application.SetCompatibleTextRenderingDefault
本身只有 3 种可能的组合。(true)
(false)
或完全省略。完成这 3 种组合后,我继续(这里是基本故障排除,但我发现有必要解释以涵盖所有基础)添加 Telerik 控件,然后尝试 Telerik 控件中的所有组合,并结合Application.SetCompatibleTextRenderingDefault
命令。测试的数量是指数级的,即呈现可能性的可能组合数量乘以尝试的控件数量乘以每个控件具有的呈现控件的可能性数量,依此类推。
经过大量的挖掘,并在这个问题上一无所获(包括对这个问题的 drive-by 否决,这仍然让我感到困惑),我找到了这个问题的解决方案,似乎很多人都面临过并且还提出 empty-handed 求助于将字体作为文件安装在用户系统上。正如我所想,这根本不是必需的,您可以以一种简单的方式嵌入字体,这允许它在 any 控件上使用,包括 TextBox、ComboBox 等。随心所欲.
我将把它写成一个步骤 by-step 指南,介绍如何将字体嵌入到您的项目中并使其在您需要的任何控件上正确显示。
第 1 步 - 选择你的受害者(字体选择)
出于演示目的(和大众需求),我将使用 FontAwesome 字体(撰写本文时为 v 4.1)
- 在您的项目中,转到
Project > <your project name> Properties
- 点击
Resources
(应该在左边) - 单击
Add Resource
按钮右侧的下拉箭头,然后 selectAdd Existing File
。
- 确保
All Files (*.*)
已从下拉菜单中 select 编辑,然后浏览到您希望嵌入字体文件的位置,select 它,然后单击 [打开] 按钮。
您现在应该会看到如下内容:
- 按 [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()
与 Microsoft 关于 PrivateFontCollection.AddMemoryFont() 的文档相反,您根本不需要使用 UseCompatibleTextRendering
或 SetCompatibleTextRenderingDefault
。我上面概述的方法允许在 objects/controls.