VB.NET Include a font as an embedded resource in your application

5:09:00 am 1 Comments

 Today I am going to show you how you can take a font file, and include it in your VB.NET WinForms application. This means you can load the font at runtime, and use it on your controls without requiring the user to have the font installed on their system. This can come in handy when you want to use a custom font, but your app needs to run without admin rights (because of ClickOnce or other least privileged requirements). Without admin rights you cannot install fonts on a system. (Note: I have seen some workarounds to this, but they require 3rd party utilities).
This is a pretty simple example, and there is not a ton of code. So lets get right down to it:
First lets see the end result.
Here is what the form looks like when I run it normally
Here is what the form looks like when I click the button and load the custom font (which happens to be a digital clock looking font)
 
The code to do this? Let's take a look. I created a new Windows Forms application, and added a ttf (true type font) file to the resources section of my project. It will be stored under the "files" section of the resources, which means accessing this font in code from the resources will just return a byte array of the file.
I created a module and put all the code needed to load the custom font in there. That way you can make quick calls to it to setup the custom font on your controls.
'Al-Salman Rehman
'2012
'CUSTOM FONT LOADED DYNAMICALLY FROM A RESOURCE

Imports System.Drawing.Text
Imports System.Runtime.InteropServices

Module CustomFont

    'PRIVATE FONT COLLECTION TO HOLD THE DYNAMIC FONT
    Private _pfc As PrivateFontCollection = Nothing


    Public ReadOnly Property GetInstance(ByVal Size As Single, _
                                         ByVal style As FontStyle) As Font
        Get
            'IF THIS IS THE FIRST TIME GETTING AN INSTANCE
            'LOAD THE FONT FROM RESOURCES
            If _pfc Is Nothing Then LoadFont()

            'RETURN A NEW FONT OBJECT BASED ON THE SIZE AND STYLE PASSED IN
            Return New Font(_pfc.Families(0), Size, style)

        End Get
    End Property

    Private Sub LoadFont()
        Try
            'INIT THE FONT COLLECTION
            _pfc = New PrivateFontCollection

            'LOAD MEMORY POINTER FOR FONT RESOURCE
            Dim fontMemPointer As IntPtr = _
                Marshal.AllocCoTaskMem( _
                My.Resources.DIGITALDREAMNARROW.Length)

            'COPY THE DATA TO THE MEMORY LOCATION
            Marshal.Copy(My.Resources.DIGITALDREAMNARROW, _
                         0, fontMemPointer, _
                         My.Resources.DIGITALDREAMNARROW.Length)

            'LOAD THE MEMORY FONT INTO THE PRIVATE FONT COLLECTION
            _pfc.AddMemoryFont(fontMemPointer, _
                               My.Resources.DIGITALDREAMNARROW.Length)

            'FREE UNSAFE MEMORY
            Marshal.FreeCoTaskMem(fontMemPointer)
        Catch ex As Exception
            'ERROR LOADING FONT. HANDLE EXCEPTION HERE
        End Try

    End Sub

End Module
It is pretty straight forward, and the code has comments so you can see what is going on.
Then in the form, when the button is clicked, we make a single call to the module's GetInstance method to return the font.
    Private Sub Button1_Click(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs) _
                              Handles Button1.Click

        Label1.Font = CustomFont.GetInstance(12, FontStyle.Bold)

    End Sub
IMPORTANT: One key thing to note here, is that on the control you want to set this custom font on, you will need to set theUseCompatibleTextRendering property to true (the default is false). If you don't want to do this for some reason, then another method you can do is to use the given controls Paint event and custom draw the text using the custom font. However this is generally less ideal because not all controls fire paint events without tweaking them, and even some that do would put the burden on drawing the entire control in your hands. So setting UseCompatibleTextRendering to true is the easier route to go.
That is all there is to it. You can modify this to meet the specific needs of your application. Below is a link to download the WinForms application (VS2008) that contains the code (and font) used in this article.



Attachment: EmbeddedFontExample.zip

1 comment:

  1. OK, okay, but how to print or display a preview window with a font not installed in the system and the application attached to the project?

    ReplyDelete