Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore.

Well, pulled a few more hairs out today. Hard to believe I have any left. I am working on a multi-lingual application that needs embeded fonts. As most of you know, loading every character in a given fontset equates to one big ass swf. For example, if you want to embed a regular and bold Japanese font you’re looking at approx. 13 megs, and depending on the quality of the font you could be close to 20 megs. That’s a lot of font. In an ideal world the Flash Player would allow for dynamic runtime shared font libraries that allow for only a subset of characters to be embeded.

In AS2 there were a few ways (hacks) to load font libraries at runtime. Unfortunately none of the AS2 hacks work in Flash CS3 using AS3. However, there is an answer. In Flex you can embed fonts at compile time using the [Embed] metadata tag in your Actionscript. And the best part is you can use the unicodeRange attribute to define a subset of characters you want to embed. Below is a class I created that compiles a swf that contains all Latin I characters in the Arial font.

package {     
     import flash.display.Sprite;
     public class _Arial extends Sprite {

          [Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName='_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')]

          public static var _Arial:Class;

     }
}

A couple things to point out here. The fontName attribute value can not be the same name as a device font. If I were to change my code to use fontName=’Arial’ the compiler throws the following warning “the embedded font ‘Arial’ may shadow a device font of the same name. Use fontName to alias the font to a different name”. To get around this I simply added an underscore before the name. From this point on you must reference the _Arial in your TextFormats or CSS. Now if you compile that it will create a swf named _Arial.swf.

Ok, great, now what? Well, now you have to load the font into the application. Here is a sample class that loads in the font and displays some rotated text just to prove that it is embeded.

package {
     import flash.display.Loader;
     import flash.display.Sprite;
     import flash.events.Event;
     import flash.net.URLRequest;
     import flash.text.*;

     public class FontLoader extends Sprite {

          public function FontLoader() {
               loadFont("_Arial.swf");
          }

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

          private function fontLoaded(event:Event):void {
               var FontLibrary:Class = event.target.applicationDomain.getDefinition("_Arial") as Class;
               Font.registerFont(FontLibrary._Arial);
               drawText();
          }

          public function drawText():void {
               var tf:TextField = new TextField();
               tf.defaultTextFormat = new TextFormat("_Arial", 16, 0);
               tf.embedFonts = true;
               tf.antiAliasType = AntiAliasType.ADVANCED;
               tf.autoSize = TextFieldAutoSize.LEFT;
               tf.border = true;
               tf.text = "Scott was herenScott was here toonblah scott...:;*&^% ";
               tf.rotation = 15;

               addChild(tf);
          }
     }
}

And there you have it. Run time embeded fonts. The key lines to look at here are

var FontLibrary:Class = event.target.applicationDomain.getDefinition("_Arial") as Class;

The getDefinition method returns a reference to the _Arial class loaded in through the swf (event.target). The next line:

Font.registerFont(FontLibrary._Arial);

registers the loaded in _Arial font in the global font list. If you were to trace out the results of Font.enumerateFonts() you will now see _Arial at the top of the list.

Now lets say your site was in a few different languages you may add the following line to the FontLoader constructor to load language specific fonts at runtime.

public function FontLoader() {
     var langManager:LanguageManager = LanguageManager.getInstance();
     var langID:String = langManager.getLanguageCode(); //returns jp
     loadFont(langID + "_Arial.swf");
}

Instead of loading in _Arial.swf the application will load in jp_Arial.swf. jp_Arial.swf would be another generated font swf like the _Arial example above but this time the unicodeRange would only include the Japanese fonts you need. All you have to do now is create a CSS file and fonts for each language, store the proper language code somewhere within the application and use that language code when loading your CSS files and fonts.

You may not know this but Adobe has supplied us with sample unicodeRanges in the following file “ApplicationsAdobeFlex Builder 2Flex SDK 2frameworksflash-unicode-table.xml”. You can either use one of the supplied ranges or create your own. You may only need to embed a few characters, if so just list the unicode values of the characters you want each seperated by a comma.

Sounds pretty straight forward eh? Or is it????

In doing this I ran into a huge bug using Flex Builder to generate the font swfs. When I was experimenting with the unicodeRanges my compiled versions did not contain the proper character ranges that I specified. For example I would define a range that only contained Uppercase characters. In my test font loading app I would only see numbers. Only if I removed the unicodeRange attribute would I see all my characters. This led me to believe that Adobe had documented something that really wasn’t part of the compiler. I tried deleting files, I was checking timestamps, nothing. Then I tried to clean my project before compiling (In FlexBuilder select Project > Clean). It worked! The subset of characters I defined in my unicodeRange only loaded into my test app. YAY! Then I tried switching the unicodeRange again. DOH! nothing. Cleaned project again and BINGO!

Lesson learned: Whenever you change your unicodeRange clean your project before you compile or else your change may not be compiled properly.

I haven’t tried this in Flex 3 yet to see if the bug has been addressed. I did look at the Flex 3 bug system and didn’t see it listed. Either it has been fixed or no one has run into this issue yet. It is pretty obscure I guess.

59 Comments

  1. xmpcray

    Interesting, I am working on a similar app and will try this.

    Can you point to similar hack(?!) for AS2…?

    Cheers!

  2. http://sharedfonts.com/eng/index.html

    is one.

    http://www.flashextensions.com/products/fontastic.php

    is another. I know there are others out there but these are the 2 that come to mind.

    Scott Morgan

  3. Thanks for the info, this will undoubtedly come in useful at some point…

    @xmpcray – I did another writeup on dynamically loading fonts into AS2 here:
    http://kelvinluck.com/article/dynamic-shared-fonts-in-flash

  4. Great article Scott. Definitely submit the bug to the bugbase. I submitted an enhancement request the other day and it was quickly assigned to an engineer and properly classified. Doesn’t guarantee they’ll fix it but shows they’re definitely taking community-submitted items seriously.

  5. xmpcray

    Thanks Scott and Kelvin. Very useful info. Immense help :)

  6. Hi,

    here’s some more info about runtime font loading in AS3 and Flash CS3. You may find this useful if you’re compiling with the Flash IDE:
    http://www.betriebsraum.de/blog/2007/06/22/runtime-font-loading-with-as3-flash-cs3-not-flex/

  7. RedB

    Hello Scott,

    Good article, very handy stuff. I find myself with a problem when compiling your stuff in flex 3 beta for eclipse: The swf for the font class does not get created. What are you compiling this with and do i need to create a css and compile it as SWF or should building the project make one from the class automatically? i feel i’m missing something here.

    Cheers

  8. Hi RedB,

    I have not tried this method yet in Flex 3. I used FlexBuilder 2. Make sure you set the font class as a default application and compile it seperatly from the FontLoader class.

  9. RedB

    Ah that did the trick, setup a separate project for font files and output to a font swfs dump. Works like a charm.

    Thanks again for the help.

  10. Hey there, I’m trying to compile the _Arial class. I set up a separate project and imported the path to the _Arial class. but I stop right there because I’m not sure what else I should do. I see you have a static prop, should I call it like any other static prop?

  11. Hi, I want to learn flash. Do you guys know where I can take flash class in bay area?

  12. Hey there,

    Been using this technique since first reading it and its been great. However i recently noticed something i had overlooked before due to the fact that i wasnt reading the content of the text displayed in the embedded font (its just testing stuff right?). Anyways, the problem is that when generating the SWFs with flexbuilder 2.0.1, it seems to create graphic artifacts and deformations depending on the original font file. Following link show an image of some characters being deformed after the embed. Those are for Arial but after testing with multiple fonts its pretty much an acrosse the board thing for most font files i tried. Am i missing something or is this something you noticed too?

    Link to example:
    http://coresplit.com/test.jpg

  13. ooops wrong link. this is right:
    http://coresplit.com/files/test.jpg

  14. Claudia

    Very helpful 411!…Thanks!

    How would you implement a multiple word named font, for ex: Trebuchet MS?

    How would you also implement that font’s bold version, for ex: Trebuchet MS Bold?

    Thanks again!

  15. Heh, tnx.

    I searching for this for while.

  16. Scotter

    Great article on runtime embedding fonts!
    I’m creating an “online logo-maker” application.
    I want to (a) have a “library” of bitmap & vector objects a user can drag onto the “work area”; and (b) have user-specific libraries. I’m planning on using PhP or ASP for the user to be able to upload bitmap & vector images to the server (they will be converted on the fly to WMF). I want the Flash (cs3) application to be able to reference that folder of images so the user can also drag those onto his “work area”. Is this a runtime possibility? I don’t even know where to get started so if you have ideas, please share!
    Thanks!

  17. I have run into an issue with embedding fonts that are “extra bold” or “black” rather than just simply “bold” or “italic”. When it goes to compile, mxmlc reports that it can’t find the font with the properties specified. I fixed it by modifying the TrueType subfamily name to “Normal” using a Perl script. It’s a bad hack but it works. Now I can load my font even if it doesn’t match a “standard” weight or style.

  18. Adam Miles

    I am having trouble at this line

    var FontLibrary:Class = event.target.applicationDomain.getDefinition(“_Arial”) as Class;

    I can’t seem to get a swf file with the font embedded in it. could you post or send the flex / flash files?

    Thanks so much

    Adam

  19. I’m having the exact same problem as Adam above, it falls over with:

    ReferenceError: Error #1065: Variable _Arial is not defined.
    at flash.system::ApplicationDomain/getDefinition()
    at net.xerode.test::FontTest/fontLoaded()

    I’m using CS3 to publish and not Flex, would this be an issue?

  20. Hey,

    I get “VerifyError: Error #1014: Class IFlexAsset could not be found” just as soon as the font file created by the above method finishes loading :-(

    Any ideas?

  21. Scott,

    I like where you’re going with this, but from a design stand-point, I have suggestion.

    If you set up an interface to your _Arial class like IFontFactory, you can set it up like this:

    interface IFontFactory{
    function getRegularFontClass():Class;
    function getBoldFontClass():Class;
    function getItalicsFontClass():Class;
    }

    Then you can change your fontLoaded method to look more like this:
    var FontLibrary:Class = IFontFactory(evt.target.content).getRegularFontClass();
    Font.registerFont(FontLibrary);

    This way, you can abstract the font registration process.

    Then again…perhaps you could just make the Font.registerFont() call in the constructor of _Arial in the first place? I’ll have to play around with that

  22. For those getting ‘Variable _Arial is not defined’ I had the same error because my _Arial.as file was in a package like com.mydomain.myproject.resources.fonts so when you get the definition it should be like so…

    var FontLibrary:Class = e.target.applicationDomain.getDefinition(“com.mydomain.myproject.resources.fonts._Arial”) as Class;

  23. Well,

    Quite disappointing that you don’t respond to questions from people about the very subjects you so expertly write about.

  24. Jipe

    Works like a charm, thanks!!!

  25. tilda

    I use FlashCS3 and Flex3 . It works only in the debug version of flashplayer

  26. Brian

    Scott,

    Spent the last day or so trying to figure this out. I generated the font swf file using flex builder, but when i load that swf using flash cs3 i get “The SWF file … contains invalid data.” when it tries to register the font. Have you tried publishing using flash cs3 or just flex?

    Cheers.

  27. Brian

    Sigh, nevermind, i figured it out. Thanks for this write up.

  28. jocce

    Hi,

    Sweet stuff.
    But i have ran into a problem when trying to make this dynamical, as im making a multilanguage site and japanees aint the favorit one for embaded fonts. So I’m sending in two variables, the url to the font swf and the font name.

    public class FontLoader extends Sprite {
    var _fontName:String;
    public function FontLoader(fontUrl:String, fontName:String) {
    trace(“FontLoader”);
    _fontName = fontName;
    loadFont(fontUrl);
    }
    … all thigns works fine down to here:..
    private function fontLoaded(event:Event):void {
    var FontLibrary:Class = event.target.applicationDomain.getDefinition(_fontName) as Class;
    trace(typeof(FontLibrary)); // traces object
    trace(typeof(FontLibrary._fontName)); // traces string , should trace object to work i guess.
    Font.registerFont(FontLibrary._fontName); // creates the error: 1067: Implict coercion of a value of type String to an unrelated type Class.
    drawText();
    }

    }

    Btw, I’m kind of new to AS3, so any of you have a solution/suggestion on how to solve this?

  29. jocce

    I think i have solved it now.
    I changed the code in flex 3, so that i registrer the font there and looks like its workin.

    package {
    import flash.display.Sprite;
    import flash.text.Font;

    public class _arial extends Sprite {

    [Embed(source=’C:/WINDOWS/Fonts/ARIAL.TTF’, fontName=’_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’)]

    public static var _arial:Class;

    Font.registerFont(_arial)

    }
    }

    then in my FontLoader.as all i needed in the fontLoaded function is the drawText

    private function fontLoaded(event:Event):void {
    drawText();
    }

    So now i can start trying to load multiple fonts and font variants.

  30. MikeyAction

    Anybody got any thoughts on how to embed a suitcase font using this method?

  31. MikeyAction – extract the individual fonts from the suitcase, there are a bunch of freeware programs that do that.

  32. MikeyAction – extract the individual fonts from the suitcase, there are a bunch of freeware programs that do that.

  33. Guess what your not alone. I’m down to a single hair. No, i’m not kidding. Flex newbies be aware. Its the coaster you can’t get off. I’m just glad flex will never be installed on say a fly by wire system otherwise you may as well just slit your throat before you get on the plane. lol, NOT!

  34. This is issue is also in flex builder 3,
    thanks for solution.

  35. Tehsin

    Hey Scott

    You are still helping me even after leaving Innovasium! :)

    Thanks for the write up…

    For the people asking questions on how to embed multiple fonts.. and btw with CS4, you can do this as well (using the Flex 3 Library Path).

    So for multiple font embedding, you can simply do something like this in your class file

    [Embed(source=”C:/windows/Fonts/HelveticaNeueLTStd-Cn.otf”, fontName=”HelveticaNeueLTStdCn”, mimeType=”application/x-font-opentype”,unicodeRange=”U+0041-U+005A,U+00C0-U+00DE”)]

    public static var HelveticaNeueLTStdCn:Class;

    [Embed(source=”C:/windows/Fonts/HelveticaLTStd-Roman.otf”, fontName=”HelveticaLTStdRoman”, mimeType=”application/x-font-opentype”,unicodeRange=”U+0041-U+005A”)]

    public static var HelveticaLTStdRoman:Class;

    And then register both fonts:

    Font.registerFont(HelveticaNeueLTStdCn);
    Font.registerFont(HelveticaLTStdRoman);

    Thanks again Scott..

    Regards,

    Tehsin

  36. sheetal

    Hello,
    I am doin it in Flex3,and i am using it in an mxml.i mean loading the _Arial.swf in my application.I am getting the same error- Error #1065: Variable _Arial is not defined.
    Also my _Arial class is in the src folder and know more packages.Plz help.

  37. I implemented this as a Flex Component. Check it out.

  38. asja

    Has this changed recently, I added the unicodeRange bit in to my font loader to try to decrease the size and it actually increased!

  39. I chose exactly which character glyphs to compile into my swf by deleting all the unnecessary ones from the TrueType font file using http://www.high-logic.com/fontcreator.html. It cut the swf file size in half.

    Another tip, Flash Optimizer http://www.flashoptimizer.com/ works really well with an embedded font, reducing its size by about 30%. This may make it worth the $99 price tag.

    Hope this info helps someone!

  40. I too was experiencing what #12 was with regards to the glyph errors. I filed a bug with Adobe about it and they suggested that I try compiling my app using a different font manager: http://bugs.adobe.com/jira/browse/SDK-14955

    There is only one thing wrong with this method; they do not support embedding Post Script fonts from Flex/ActionScript/mxmlc… pretty much anything other than Flash CS3/4: http://bugs.adobe.com/jira/browse/SDK-1500

    Otherwise it works great!

  41. Thanks a lot, the need to clean the project bug exists in Flex builder 3 as well. I would have lost a lot of time learning that if I didn’t see your blog.

  42. enrico penzo

    thanks,
    very useful

  43. Hi,

    can u please the send me the sample in Action Script 2.0
    b’coz I am using the AS2.0 only, I seen the “shared fonts manager” and download the (source)zip file, but the source in Action script1.0. Please Help me. Thanx in Advance.

  44. danny

    I am having a problem with this. I can only get it to work when the static var name is the same name as the class name. For example if my class name is _Arial and I embed the Arial font and give the static var a name of _Arial it works great. But if I change the name of the static var to something else (and update my embed code’s fontName accordingly) I don’t get errors on the font register or load but I don’t see any text on screen. Has anyone had this issue? I have seen examples where the name of that var is different from the class and it works fine. Could anyone help???:S

  45. After trying everything I still cant get a single textfield to display both bold and regular characters. Everything is embedded, all fonts are on the stage and wherever I could place them. All variations are embedded, but nothing works.

  46. This was a massive help on a recent project you are a super star thanks for sharing.

  47. easyMind

    Hi, isn’t it possible to use Flash to make the font swfs? I still want to use these fonts in flex, but creating the fonts swfs in flash will reduce the file size since the flex framework is not compiled. But maybe just compiling the framework seperatly has the same result…

  48. easyMind

    Ok, so you want normal, bold and italic also…
    Just add those fonts to your swf class like this:

    [Embed(source=’C:/WINDOWS/Fonts/ARIAL.TTF’, fontName=’_Arial’)]
    public static var _Arial:Class;

    [Embed(source=’C:/WINDOWS/Fonts/ARIALBD.TTF’, fontWeight=’bold’, fontName=’_Arial’)]
    public static var _ArialB:Class;

    [Embed(source=’C:/WINDOWS/Fonts/ARIALI.TTF’, fontStyle=’italic’, fontName=’_Arial’]
    public static var _ArialI:Class;

    [Embed(source=’C:/WINDOWS/Fonts/ARIALBI.TTF’, fontWeight=’bold’, fontStyle=’italic’, fontName=’_Arial’]
    public static var _ArialBI:Class;

    As you can see, you have to set the proper fontstyle and fontweight values. Also keep the same fontName…

    Now when loading the font make sure to register all 4 fonts in your class… I do this like this:
    var FontLibrary:Class = event.target.applicationDomain.getDefinition(‘_Arial’) as Class;
    var fl:Object = ObjectUtil.copy(FontLibrary);
    for(var i:Object in fl)
    Font.registerFont(FontLibrary[i]);

  49. wondeerful post Scott. many thanks, exactly what I needed! :- )

  50. very Nice Tutorial..

  51. This is an awesome tutorial. Got it working in eclipse w/FDT. Very cool! Thanks for sharing.

    Blake

  52. hello,

    thanks for sharing this.
    I’ve managed to get the _Arial font class in my swf and use it. I works fine. Thus, i have some problems: I can’t make my Text Fild to desplay special chars (like È).
    The weird thing is that in Flex I see this chars without any problem (by creating a TextField).
    So I suppose that Flash lose them somehow,
    Have somebody had the same problem or something close?

    Thanks!

  53. john piere jones

    what about on a mac jack?

  54. I’m having trouble with this technique. Specifically, it appears that it is not possible to control advanced anti-aliasing settings (via the TextRenderer class) when fonts are embedded in this way. I was wondering whether anyone else had run into this issue..?

  55. Steef

    Hi there,

    I’am working on dynamic font embedding, and it works fine. But only if the font.swf is standing in the same folder als the app.swf.

    My SWF files with the fonts are on a remote server, so instead of “Arial,swf” i point to “http://myserver/fontCache/Arial.swf”

    If i put Arial.swf in mij app-folder, YEAY, it works. If i point to a remote (or even a c:/blah/arial.swf) it wont work.

    Anyone an idea?

  56. Thanks Scott!

    Very useful hack :)

  57. munkychop

    This Is a great article, but, it is missing one CRUCIAL UPDATE…

    If you are publishing to Flash Player 10+ and using the TextField class then you need to explicitly set the newly added ’embedAsCFF’ property to false, as if you don’t then this method will only work with the new TextLayoutFramework.

    This confused me for hours and hours, so please add it to the article if possible.

    [CODE]
    [Embed(source=’C:/WINDOWS/Fonts/ARIAL.TTF’, fontName=’_Arial’, embedAsCFF=’false’, unicodeRange=’U+0020-U+007E’)]
    [/CODE]

    Hope that helps somebody, some day :)

  58. Ram

    Nice article.. Scott..

    And MunkyChop your tip has helped me this day.

    Thanks,
    Ram

  59. Hubert

    Hi I came across problem as all working great offline , but when I publish online Text after update font do not apperer ,I checked by
    var fontsa:Array = Font.enumerateFonts();
    for each(var font:Font in fontsa){
    listatxt.text = ” + font.fontName; }

    and fonts are embeded !??? – why swf from pc work , but when is online do not !:(

    Thank you for any comment

    Hubert W.

Trackbacks/Pingbacks

  1. tripleaxis.com » Dynamic font loading in AS3 - [...] http://www.betriebsraum.de/…runtime-font-loading-with-as3/ http://www.mikechambers.com/…class-reference-by-class-name/ http://www.scottgmorgan.com/…runtime-font-embedding-in-as3/ [...]
  2. TS Larusso » Blog Archive » Embedding Fonts mit AS3 - [...] Der meißt bequemste Weg geht hier über das [EMBED] Tag der leider nur mit der Flex-Compiler Shell funktioniert. Dieses…
  3. Flash: Runtime Font Sharing Embedding with only Partial Character sets: How To. : TroyWorks - [...] me realize the ability to limit the unicode. The more readable one on the yahoo labs, and the authors…
  4. Runtime font embedding in AS3 « moogtone - [...] 8:19 am Filed under: Actionscript 3 | Tags: AS3, Flash, font Scott Morgan has a nice post about…
  5. Example of Embedding font in an ActionScript project with external XML, CSS and html formatted text | Samuel’s Blog - [...] quite indepth and useful post here about embedding only the glyphs you [...]
  6. Flex/Flash Runtime Fonts with HTML « Here’s how I did it… - [...] out there on how to dynamically load font libraries at runtime in Flex. here are just a few: scottmorgan.com,…
  7. Flash字体嵌入方法总结—(4)进阶篇【转载kevincao】 | Catfly猫脸爬 - [...] Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore. [...]

Leave a Comment

Your email address will not be published. Required fields are marked *