.netfontsfallbackconstruction

Hard-coding Fonts in DotNET


I've run into problems on numerous occasions of users not having one of the Windows Core fonts installed on their machine (Courier New, Comic Sans MS, Arial for example). Whenever I try to construct one of these it throws an error rather than falling back onto a related, or really, any other font.

What is the best way to construct a Font if I'd like it to be Courier, but I'm not particularly wedded to it?


Solution

  • You can embed the fonts as resources and use the unsafe keyword (and must be compiled with 'unsafe') to obtain the fonts... Here's an example code that I used to set a user control to the font of type 'OCR':

    private PrivateFontCollection pfc = new PrivateFontCollection();
    private Font _fntOCRFont = null;
    private enum FontEnum{
       OCR = 0
    };
    

    That declares a private collection of fonts...the font 'OCR' is embedded as a resource using the naming convention where 'foo' is a namespace, hence the resource name would be 'foo.ocraext.ttf'...Look at 'InitOCRFont' here which loads the font and adds it to the collection:

    private void InitOCRFont(){
       try{
          System.IO.Stream streamFont = this.GetType().Assembly.GetManifestResourceStream("foo.ocraext.ttf");
          if (streamFont != null){
              byte[] fontData = new byte[streamFont.Length];
              streamFont.Read(fontData, 0, (int)streamFont.Length);
              streamFont.Close();
              unsafe{
                    fixed(byte *pFontData = fontData){
                       this.pfc.AddMemoryFont((System.IntPtr)pFontData, fontData.Length);
                    }
              }
          }else{
              throw new Exception("Error! Could not read built-in Font.");
          }
       }catch(Exception eX){
          throw new Exception("InitOCRFont Method - Exception occurred!\nException was: " + eX.Message);
       }
    }
    

    In here, I set the controls within the User control to set the font to that 'OCR' font by iterating through the collection, see 'InitializeCtlFont', font size is 10 and is a bold 'type-face':

    private void InitializeCtlFont(){
        this._fntOCRFont = new Font(this.pfc.Families[0], 10.0F, System.Drawing.FontStyle.Bold);
        if (this._fntOCRFont != null){
             foreach(Control ctl in this.Controls){
                if (ctl != null && ((ctl is Label) || (ctl is TextBox))){
                            ctl.Font = this._fntOCRFont;
                        }
             }
        }
    }
    

    When the user control gets disposed, it is imperative to free up the resources occupied by the font as shown here in the Dispose method:

    try{
       if (this._fntOCRFont != null) this._fntOCRFont.Dispose();
    }catch{
    }
    try{
       if (this.pfc != null) this.pfc.Dispose();
    }catch{
    }