Load a font from disk, stream or byte array

July 3, 2008 at 11:30 AMAndre Loker

A user asked in the Gamedev.net Forums how to load a Font from a Stream or a byte array. An interesting question, I think, because there might be applications that come with their own fonts. The obvious way to make the font available is by installing it to the font collection of the O/S. In that case one could simply use the Font constructor that takes the font family name as its first argument and be happy.

However, there are several good reasons to decide against installing a new font to the O/S:

  • Installing a font requires administrative privileges
  • You don't want to clutter the font collection unnecessarily
  • Your app does not have or need an installer because it's a very simple tool. You neither want to add an installer just for installing the font, nor do you want the user to manually install a font.

Basics: load font from file

Therefore, the first thing we would like is to load a true type font file (ie. a .ttf file) directly from disk, without the need to install it first. To achieve this, the .NET framework provides the class System.Drawing.Text.PrivateFontCollection. The method AddFontFile does just what we want: load a ttf file. The Families property returns an array of all font families that have been loaded so far.

The method below shows a method that loads a font file and returns the first font family:

   1: public static FontFamily LoadFontFamily(string fileName, out PrivateFontCollection fontCollection) {
   2:   fontCollection = new PrivateFontCollection();
   3:   fontCollection.AddFontFile(fileName);
   4:   return fontCollection.Families[0];
   5: }

The returned FontFamily can then be used to construct specific fonts, like this:

   1: PrivateFontCollection fonts;
   2: FontFamily family = LoadFontFamily("TheFont.ttf", out fonts);
   3: Font theFont = new Font(family, 20.0f);
   4: // when done:
   5: theFont.Dispose();
   6: family.Dispose();
   7: family.Dispose();

You can then use the font as usual.

Next level: load font from stream or byte array

If you want to deploy your application as a single .exe you would prefer to load the font from an embedded resource rather than loading it from a separate file. PrivateFontCollection provides a method called AddMemoryFont that we can use for this purpose. Loading a file into memory is a snap, but AddMemoryFont accepts an IntPtr and a length. Therefore we need to do fiddle a bit to get the IntPtr from the byte array. Here's a method that loads a font family from a byte array:

   1: // load font family from byte array
   2: public static FontFamily LoadFontFamily(byte[] buffer, out PrivateFontCollection fontCollection) {
   3:   // pin array so we can get its address
   4:   var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
   5:   try {
   6:     var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
   7:     fontCollection = new PrivateFontCollection();
   8:     fontCollection.AddMemoryFont(ptr, buffer.Length);
   9:     return fontCollection.Families[0];
  10:   } finally {
  11:     // don't forget to unpin the array!
  12:     handle.Free();
  13:   }
  14: }

As you can see, I'm using GCHandle and UnsafeAddrOfPinnedArrayElement to get the IntPtr to the first element in the array. If you prefer to use unsafe blocks, go ahead, it's even shorter:

   1: // load font family from byte array
   2: public static unsafe FontFamily LoadFontFamilyUnsafe(byte[] buffer, out PrivateFontCollection fontCollection) {
   3:   fixed (byte* ptr = buffer) {
   4:     fontCollection = new PrivateFontCollection();
   5:     fontCollection.AddMemoryFont(new IntPtr(ptr), buffer.Length);
   6:     return fontCollection.Families[0];
   7:   }
   8: }

For convenience we provide another overload that accepts a stream:

   1: // Load font family from stream
   2: public static FontFamily LoadFontFamily(Stream stream, out PrivateFontCollection fontCollection) {
   3:   var buffer = new byte[stream.Length];
   4:   stream.Read(buffer, 0, buffer.Length);
   5:   return LoadFontFamily(buffer, out fontCollection);
   6: }

With those methods available we can load a Font for example from an embedded resource:

   1: using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test.TheFont.ttf")) {
   2:   PrivateFontCollection fonts;
   3:   FontFamily family = LoadFontFamily(s, out fonts);
   4:   Font theFont = new Font(family, 20.0f);
   5:   //...
   6: }

Note: the documentation of AddMemoryFont have this to say:

To use the memory font, text on a control must be rendered with GDI+. Use the SetCompatibleTextRenderingDefault method, passing true, to set GDI+ rendering on the application, or on individual controls by setting the control's UseCompatibleTextRendering property to true. Some controls cannot be rendered with GDI+.

While I haven't noticed problems when using memory fonts even when compatible text rendering is deactivated (which is preferable), you might experience problems. In this case you have two options:

  • Enable compatibility mode using SetCompatibleTextRenderingDefault, which is not really desirable as the new GDI text rendering engine is superior to the GDI+ engine.
  • Don't use AddMemoryFont, but extract the font to the temp directory and load it from there using AddFontFile

Update 07/07/2008: It seems that you must not dipose the PrivateFontCollection before you're done with the fonts within it; otherwise your app my crash. I updated the methods above to return the PrivateFontCollection instance. The caller has to dispose the collection after he/she is done using the fonts.

Posted in: Snippets

Tags: ,

Comments (2) -

Such an Excellent Tip!
Just a comment, level 2 is only for VS2008 and is using some unsafe sentences. Things will work for a while, but in a stronger security environment (Vista or 7), surely you could receive lots of warnings or denials. Am I wrong?
Level 1: If you use this code inside a custom control, please declare variables as private class fields instead of constructor variables or you could get an error when loading app.
Best regards!

Great post.  I have code I've used for a few years to create bar codes via fonts.  In the past we just loaded the fonts onto the system but a need has arrisen to embed the fonts as a resource.  Your snippets showing how to do that from a stream were exactly what I was struggling with.  I followed the same process (only with Visual Basic) and it worked like a charm.  Good stuff and thanks for sharing!