Monday, July 11, 2011

Dynamic Font Embedding

When You want to load some parts or modules later font is one of thing that is not most important. Sometimes there is some kind of configuration where you or user chooses which font should be used. In those situations font should be embedded dynamically. So here simple instruction step by step:

Firstly we need font packed separately in swf. I made sepataed project to easily maintain it but it can also be module. My code looks like this:


package Arial
{
import flash.display.Sprite;

public class Font_Arial extends Sprite
{
[Embed(source='ARIAL.ttf', fontName="Font_Arial", unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E, U+00A0-U+00FF, U+0100-U+017E, U+20AC')]
public static var Font_Arial:Class;


[Embed(source='ARIALBD.ttf', fontWeight= "bold", fontName="Font_Arial", unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E, U+00A0-U+00FF, U+0100-U+017E, U+20AC')]
public static var Font_ArialBold:Class;

[Embed(source='ARIALI.ttf', fontStyle='italic', fontName="Font_Arial", unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E, U+00A0-U+00FF, U+0100-U+017E, U+20AC')]
public static var Font_ArialItalic:Class;

[Embed(source='ARIALBI.ttf', fontStyle='italic', fontWeight= "bold",fontName="Font_Arial", unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E, U+00A0-U+00FF, U+0100-U+017E, U+20AC')]
public static var Font_ArialBoldItalic:Class;


}
}

Maybe small description of code. I have  got package name. This will be important later.
Class name is something you can sat as you wish. The only thing is that it cannot be named as Font name in system, so if you name it Arial there will be conflict.
As You can see I'm embedding similar files - each one consist different style - there is normal, bold, italic and bold&italic (last one is separated style!). For each one there are describing parameters fontWeight and fontStyle.
FontName for all font styles must be the same and must be same as class name.
Last parameter is unicodeRange. it describes which signs are embedded. You can leave it but then all signs will added which usually is unnecessary and your file will be heavy. For example all glyphs from Arial normal (without bold and italic) weights about 300kB when my file with four styles and only glyphs that are used by my application (latin symbols, numbers, special chars) weights 90kB.

Now let's load it

public function FontLoader():void {
loadFont(_serverPath+"fonts/Arial/Font_Arial.swf");
}


private function loadFont(url:String):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontLoaded);
loader.load(new URLRequest(url));
}

I hope this part is easy and don't need comment


private function fontLoaded(event:Event):void 
{
var FontLibrary:Class = event.target.applicationDomain.getDefinition("Arial.Font_Arial") as Class;


Font.registerFont(FontLibrary['Font_Arial']);
Font.registerFont(FontLibrary['Font_ArialBold']);
Font.registerFont(FontLibrary['Font_ArialItalic']);
Font.registerFont(FontLibrary['Font_ArialBoldItalic']);


drawText();
}

We're extracting data from externall module. Remember my package name Arial? Full class name with package has to be put to getDefinition() method. Remember about package name. I lost some time to figure it out.
When you register font you can use it globally in your app.  Instead of calling similar command four time you can use foreach loop here.
Now we can use our font.

public function drawText():void
{
var tf:TextFormat = hintText.getTextFormat();

tf.font = "Font_Arial";
hintText.embedFonts = true;
hintText.setTextFormat(tf);
hintText.defaultTextFormat = tf;

}

I hope it's clear enough.