I embedded a .ttf font file ("Amatic Bold", specifically) in my resources and I'm using this code below to get the Font. I tried the code fom this post: How do I Embed a font with my C# application? (using Visual Studio 2005)
This is my implementation:
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);
}
Im using it like that:
Font font = GetCustomFont(Properties.MainResources.Amatic_Bold, 25, System.Drawing.FontStyle.Bold);
The font should look like:
The problem is the font is loading but not correctly showing when used; it looks like an "Arial" or other standard font instead of what it should be. If I install the font in Windows, it works (I suppose is obvious...)
I searched for an existing answer but could'nt find my exact problem...
Any help will be appreciated. Thanks in advance.
Well, then... I think I got it!
I'll explain what I've "discovered" (whether it can be obvious or not):
First: Application.SetCompatibleTextRenderingDefault
must be set to true for Memory fonts to be rendered in the controls.
(Also Control.UseCompatibleTextRendering
can be used)
It's perfectly specified in Microsoft documentation but I've missed that :-(
Second: PrivateFontCollection.Families
return an array of added fonts, but.. Surprise! It's alphabetically ordered!
No matter what's the order you add the fonts or the method you use (AddMemoryFont
/AddFontFile
), you'll get it alphabetically ordered!
So if you're adding more than one font and then trying to get the last font you've added, you'll probably getting the wrong one.
Third: I've also tried doing FreeCoTaskMem()
after adding the font in the collection or doing it on form closing. Both were working for me!
I don't know the exact implications of this...
This is my final code:
//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);
}
As you can see, I've decided to create an exclusive PrivateFontCollection for each font, then store it to a List for a final disposal on application end.
This was tested in 3 different PC's (both with Windows 7, 32 and 64 bits) and 3 different .ttf fonts.
An example of the result:
I don't know if my approach is good enough, but I expect it could be useful for others!
One more detail: Unlike what I expected, AddMemoryFont is slower then AddFontFile (21ms vs. 15 ms)
Again, thanks to all comments!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With