After a lot of digging around, and coming up empty on this (including the drive-by downvote on this question which still puzzles me), I have found a solution to this problem which it seems many have faced and have also come up empty-handed resorting to just installing the font as a file on the users system. As I thought, this is not required at all and you CAN embed the font in a simple way which allows it to be used on any control including TextBox, ComboBox, etc. Whatever your heart desires.
I will write this as a step by-step guide on how to embed a font into your project AND have it display properly on any control you desire.
Step 1 - Choosing your victim (the font choice)
For demonstration purposes (and popular demand), I will be using the FontAwesome font (v 4.1 at the time of writing this)
- Inside your project, go to
Project > <your project name> Properties
- Click
Resources
(should be on the left side)
- Click the dropdown arrow to the right of the
Add Resource
button, and select Add Existing File
.
- Make sure the
All Files (*.*)
is selected from the drop down and then browse to where the font file is your wish to embed, select it, and click the [Open] button.
You should now see something like the following :
- Press [CTRL]+[S] to save the project.
Step 2 - Diving into the code
Copy the following code and save it as 'MemoryFonts.cs' then add it to your project
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;
}
}
Step 3 - Making it pretty (using the font)
On the main form, add a TextBox control from your toolbox
Inside the form_Load
event, put the following code (in my case the resource is fontawesome_webfont
. change that to whatever your font resource is named)
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" );
}
The end result
You may or may not have noticed that I made this method keeping in mind that you may wish to add multiple embedded fonts. In which case, you just call AddMemoryFont()
for each of the fonts you want to add, and then use the appropriate index value (zero based) when using GetFont()
Contrary to the document regarding PrivateFontCollection.AddMemoryFont()'s documentation from Microsoft, you DO NOT NEED to use UseCompatibleTextRendering
or SetCompatibleTextRenderingDefault
at all. The method I outlined above allows for natural rendering of the font in objects/controls.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…