Scott Morgan

Calgary Flash and Flex Developer

Jun

18

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

By scott

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 here\nScott was here too\nblah 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 “\Applications\Adobe\Flex Builder 2\Flex SDK 2\frameworks\flash-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.

64 Responses so far

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

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

Cheers!

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

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

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.

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

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/

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

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.

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.

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?

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

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

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

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!

Heh, tnx.

I searching for this for while.

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!

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.

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

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?

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?

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

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;

Well,

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

Works like a charm, thanks!!!

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

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.

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

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?

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.

[...] Der meißt bequemste Weg geht hier über das [EMBED] Tag der leider nur mit der Flex-Compiler Shell funktioniert. Dieses Tag ermöglicht es die gewünschte Schrift einfach in die SWF zu compilieren. Die Dateigröße wird dabei zwar beachtlich größer, aber dafür gibt es die Möglichkeit einige UNICODE Sets zu Filtern. Damit nicht der volle Zeichensatz importiert werden muss. [Embed(source='C:/WINDOWS/Fonts/arial.ttf', fontName='_Arial')] public static var _Arial:Class; Scott Morgan hat auf seinen blog ein kleines tutorial geschrieben wie eine erweiterte Klasse das Laden von externen Schriften ermöglicht Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore. [...]

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

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

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

[...] me realize the ability to limit the unicode. The more readable one on the yahoo labs, and the authors blog with many comments. The solution he and others presented didn’t work for me, and I think the [...]

[...] 8:19 am Filed under: Actionscript 3 | Tags: AS3, Flash, font Scott Morgan has a nice post about font embedding at his blog. No Comments so far Leave a comment RSS feed for comments on this post. [...]

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!

[...] quite indepth and useful post here about embedding only the glyphs you [...]

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

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

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.

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

[...] out there on how to dynamically load font libraries at runtime in Flex. here are just a few: scottmorgan.com, undefined-type.com, [...]

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

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!

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!

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.

thanks,
very useful

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.

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

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.

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

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…

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]);

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

very Nice Tutorial..

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

Blake

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!

what about on a mac jack?

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..?

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

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?

Thanks Scott!

Very useful hack :)

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 :)

Leave a comment