Embedding Fonts in your .Net Application Part 2

by Brian Brewder October 08, 2011 17:41

In my last article I showed a simple, but naive way to embed fonts in your application. The problem with the other approach is that the operating system combines multiple font files into a single font family, each file containing a style (such as bold or italic) that is available. So if you added Arial regular and Arial bold font files to the PrivateFontCollection, you would only have a single FontFamily in the collection.

A better approach is to continue using font family names as strings to create the font. The FontFamily class has a constructor that takes a FontCollection which allows you to send in the PrivateFontCollection that you added your embedded font to.

Here is a better solution for embedding fonts. You can register fonts externally during application startup, then, whenever you need a font, just call FontHelper.Create. This method will create any font, including fonts installed on the system.

public class FontHelper
{
    private static PrivateFontCollection sCustomFonts;
    private static Dictionary<string, FontFamily> sFamilies;

    static FontHelper()
    {
        sCustomFonts = new PrivateFontCollection();
        sFamilies = new Dictionary<string, FontFamily>(
            StringComparer.InvariantCultureIgnoreCase);
    }

    public static void RegisterFont(byte[] font)
    {
        var buffer = Marshal.AllocCoTaskMem(font.Length);
        Marshal.Copy(font, 0, buffer, font.Length);
        sCustomFonts.AddMemoryFont(buffer, font.Length);
    }

    public static void RegisterFont(string fontFilePath)
    {
        sCustomFonts.AddFontFile(fontFilePath);
    }

    public static FontFamily[] GetAllFamilies()
    {
        var families = new List<FontFamily>();
            
        families.AddRange(FontFamily.Families);
        families.AddRange(sCustomFonts.Families);

        families.Sort((f1, f2) => { return f1.Name.CompareTo(f2.Name); });
        return families.ToArray();
    }

    public static FontFamily GetFamily(string family)
    {
        try
        {
            // cache the family in a dictionary for fast lookup.
            if (!sFamilies.ContainsKey(family))
                sFamilies.Add(family, new FontFamily(family, sCustomFonts));
        }
        catch (ArgumentException)
        {
            sFamilies.Add(family, new FontFamily(family));
        }
        return sFamilies[family];
    }

    public static Font Create(
        string family, 
        float emSize, 
        FontStyle style = FontStyle.Regular, 
        GraphicsUnit unit = GraphicsUnit.Pixel)
    {
        var fam = GetFamily(family);
        return new Font(family, emSize, style, unit);
    }

}

You would use this class like this. MyFonts is simply a resource file (.resx) that I added to my project and dragged the font file (.ttf) into.

FontHelper.RegisterFont(MyFonts.Consolas);
using(var font = FontHelper.Create("Consolas", 12))
{
    // Use the font
}

Unfortunately I am not able to use this code for work. One of the requirements we have is that we must embed the fonts into PDF files. As much as I would like to deploy without installing fonts, it is much easier to embed fonts with the PDF library we are using when they are installed on the machine.

Tags:

Powered by BlogEngine.NET 1.6.0.0

About the author

I've been a software developer since 1999 and have been working with .Net since 2002. I love creating software, playing with productivity tools, and improving the process of software development. I hope you enjoy my blog. Please feel free to leave comments or contact me, I would love to hear from you.