Runtime font loading with AS3 / Flash CS3 (not Flex!)
June 22, 2007
If I never really got something in Flash it was font embedding and runtime font loading. The bad news is: We have ActionScript 3.0 now and Flash CS3 and I still haven’t completely understood it yet. The good news is: It works – somehow – if you keep in mind some things. After all articles about this topic I’ve read until now I have the feeling that nobody really understands what’s going on with fonts in different use cases. Trial and error…
As the headline suggests this article deals with font embedding in Flash CS3 and not in Flex. With Flex and mxmlc there’s the embed metatag where you can even define font character ranges which should be embedded. You don’t have this option if compile with the Flash IDE…
[UPDATE (16.11.2007)
You can define character sets in the Flash Authoring Tool (however you can’t set them via ActionScript!):
There’s a UnicodeTable.xml in the Adobe Flash CS3\(language)\First Run\FontEmbedding\ folder that you can copy and modify. For more information see the flash help (Creating custom character sets) and Renzo’s Flash unicode table generator page.]
As we needed runtime font loading in our current project I tried out a few solutions. Our concrete requirements were the following:
- Textfields get their content from an XML file
- Text in the XML is wrapped in a CData-Tag and formated with CSS styles
- The CSS styles are defined in an external file
- Fonts are all in a a separate fla / swf file and loaded at runtime
- Some textfields have embedded fonts (e.g. headlines), some use device fonts (continuous text)
- Sometimes there are different font styles / variants in a single textfield with embedded fonts
When you’re working with embedded fonts it’s important to always test your project on a different machine where they aren’t installed or disable them in some font managing tool. Otherwise you don’t know if everything works and is really embedded.
In Flash CS3 there’s still the font symbol, i.e. you can create a font symbol in the library, give it a name, set the font, font size and variant and export it for ActionScript. The difference to Flash 8 is that you have to specify a class (same as with MovieClips, Bitmaps etc. in ActionScript 3.0) instead of a linkage id. With fonts the class must extend the Font class and this is automatically set for you when you export the font: flash.text.Font. The Font class in AS3 is an abstract class which means that it can’t be instantiated – so you can’t create a new one by calling new Font()…
The font class has a few properties (fontName, fontStyle and fontType) and two static methods which seem to be interesting:
Font.enumerateFonts() and Font.registerFont(). Unfortunately the help for registerFont (at least the German help) only says that it registers a font in the global font list and that it expects a parameter of type Class. What that means is that you can call Font.registerFont(MyFontClass) (MyFontClass is the class that you can set in the export dialog – name doesn’t matter) and then trace(Font.enumerateFonts()) and your font is listed…
With that you successfully registered a font in the global list and can use it everywhere in your code now. One option for setting a font in a textfield is to create a new TextFormat() and set the font property. The font property must be a String (the font name). You can’t use myTextFormat.font = “MyFontClass” und you can’t use myTextFormat.font = “MyFontPropertyName” (“MyFontPropertyName” is the name that you set in the font symbols properties. Don’t confuse it with the class name in the export dialog). myTextFormat.font expects the real font name:
If you set the font to “standard 07_57” in the properties dialog you have to write myTextFormat.font = “standard 07_57”. That’s bad if you want to switch your font in the library but don’t want to modify your code. Another solution is to instantiate the symbol directly and use its fontName property: myTextFormat.font = new MyFontClass().fontName. Works. So that seems to be the golden font rule #1:
Always use the real font name (if you use an external css file use the real font name as the font-family)!
The example above would also work if you didn’t call Font.registerFont(MyFontClass) before (when your font symbol is in the same fla / swf there’s no need to register it). What about loading your font symbols from another swf?
Create them in an extra fla file: Create the symbol in the library, set the font in the properties (name doesn’t matter, size dosen’t matter, variant DOES matter – if you want to use the bold version you have to create another font symbol), export for ActionScript, set a class name and compile. Now you can load those fonts once and reuse them in all your swfs. There are at least two ways how you can do that:
1. Check on “Export for runtime sharing” for all fonts in your library file, enter the correct swf path and drag them into the target fla where you want to use them (“import for runtime sharing” is automatically checked on). That worked in previous flash versions and the size of the target file isn’t increased. Additionally it’s a good idea to preload your library to make sure it’s completely loaded when your target swf uses the fonts. Apart from having to place all fonts in your target fla, there are some more disadvantages and workarounds (relative paths, force shared library to be really used etc.) using this approach.
2. Do not check on “Export for runtime sharing” but load the library swf with the Loader class, use the Loader’s applicationDomain to get all the class definitions and register them in the global font list (further explained below). This is the preferred way as you don’t need any font symbols in your target fla. Furthermore you can create different library files for different languages with different fonts (different character sets etc.).
For this purpose you could use some kind of FontManager class:
package de.betriebsraum.utils { import flash.display.*; import flash.events.*; import flash.text.*; import flash.errors.*; import flash.system.*; public class FontManager extends EventDispatcher { private static var INSTANCE:FontManager; private var _fontsDomain:ApplicationDomain; private var _styleSheet:StyleSheet; public function FontManager(enforcer:SingletonEnforcer) { super(); } public static function getInstance():FontManager { if (INSTANCE == null) { INSTANCE = new FontManager(new SingletonEnforcer()); } return INSTANCE; } public function initialize(fontsDomain:ApplicationDomain, styles:StyleSheet):void { if (_fontsDomain == null) { _fontsDomain = fontsDomain; _styleSheet = styles; } else { throw new IllegalOperationError("FontManager already initialized!"); } } public function registerFonts(fontList:Array):void { for (var i:int = 0; i < fontList.length; i++) { Font.registerFont(getFontClass(fontList[i])); } } public function getFontClass(id:String):Class { return _fontsDomain.getDefinition(id) as Class; } public function getFont(id:String):Font { var fontClass:Class = getFontClass(id); return new fontClass as Font; } public function getStyleSheet():StyleSheet { return _styleSheet; } } } class SingletonEnforcer { } |
As you can see the FontManager class does not load the library file itself.
The reason is that in our case the files are loaded at application startup in a loader queue (which also loads other stuff) and then just passed to the FontManager but you can add in the loading functionality for the fonts file and a stylesheet easily: Just create a Loader and load the swf…and when the Loader is finished create a URLLoader and load the stylesheet. The initialize method accepts an ApplicationDomain and a StyleSheet which are both stored in instance variables.
The ApplicationDomain parameter would be myLoader.contentLoaderInfo.applicationDomain and the StyleSheet is an instance of the StyleSheet class (with parseCSS() called before to parse the external css file). After calling the initialize method you would call registerFonts and pass an array with font class names that you want to register in the global list, for example: fontManagerInstance.registerFonts([“Standard57”]). This registers the font with a class name of Standard57 (Standard57 is the class set in the symbol linkage, not the symbol name and not the real font name!). In the CSS file, the font is defined with font-family: standard 07_57 (use the real name here!). Also make sure to set just one font in the font-family style! The following didn’t work:
font-family: standard 07_57, _sans
The registerFonts method uses the applicationDomain’s getDefinition method to get the font class definition by a string. This is a great feature in AS3: You can load in a swf with some symbols, get their class definitions (the applicationDomain is some kind of »storage« for the class definitions in a swf) and use them to create new instances.
If you now place a textfield onto the stage and write:
myTextField.styleSheet = fontManagerInstance.getStyleSheet(); myTextField.embedFonts = true; myTextField.htmlText = "<h1>This is the headline</h1>"; |
everything should work (provided there’s a h1 style in the css with the correct font-family set and a font symbol in the library swf). If the textfield is manually placed onto the stage it’s important to set a different font for the textfield itself (in the property inspector) than the one that is defined in the CSS file (simply select _sans, for example). Don’t embed it in the property inspector as the file size would be increased then (set embedFonts in your code instead). What’s really strange:
If you additionally place a static textfield onto the stage with the same font, the text in the dynamic textfield isn’t shown anymore. Don’t really understand why…but it’s probably the same problem as if you set the same font in the dynamic textfield (maybe a »font collision«?). A workaround is to create the font symbol in the fla and select it (the one with *) in the property inspector.
If you know more about Font.registerFonts() and the above problems please leave a comment.
Filed under: Flex/AS3
I have not read complete post of yours but just wanted to confirm, it’s totally possible to load fonts (swfs) on runtime and update text-field to show the text in loaded font.
-abdul
Yes, as I described above, it’s possible but you have to keep a few things in mind…
It will be nice if you put sources to download.
You can do it in Flash 7/8 AS2 too. It took me ages to work it out but here’s a brief expanation…
Embed the font into an external swf and call that swf with loadMovie or loadClip. That way you can build a preloader to allow for the download.
The key to understanding remote fonts is that the font is connected to the loaded movie, not below it (_root) or sideways of it.
So if you have a swf called futura.swf and load it into the root and call it “font_mc” you’ll have a mc at _root.font_mc.
You can now create TextFields on _root.font_mc and they’ll use the embedded fonts (remember to create a TextFormat and use the same name for the font as it has set in the library of the futura.fla and to set embedFonts to true after formatting the text).
@john: I see if I can post example files in the next days…
@asjb: Weird, I haven’t tried that. At least it’s much cleaner now in AS3 to get the class definitions of a loaded library by calling getDefinition()…
[…] Runtime Font Loading with AS3 Flash CS3 Betriebsraum wrote: […]
Just wanted to let you know that the flashenabled.wordpress.com blog (which looks like it did a trackback) seems to be in the business of copy/pasting entire blog entries in order to get pagerank. It’s attributed but not original.
Hi Josh,
I’ve already mailed the guy. Normal trackbacks and links are ok but copying the whole content isn’t ok. I don’t think he’s doing anybody a favour with that…
Hiya,
I’m not sure if anyone else has tried this as well, at least I have yet to see anyone else try it exactly. I put together a quick demo of loading embedded fonts at runtime that is a bit cleaner than using the applicationDomain and getDefinition(). Let me know what you think.
http://www.harmfultohumans.net/DynamicFontDemo/
Take care.
Hello.
Could someone post an example of dynamic font loading from an SWF file of 2 different fonts along with their bold and italic styles?
All the examples I’ve seen so far only address the loading of one font either in regular weight or bold but not more than one fonts and more than one weight at the same time.
Thanks a lot!
again, another impossible to follow tutorial on embedding fonts in flash cs3… when will it end?!
sorry, but this wasn’t actually supposed to be a “tutorial”…
Works really good!! Super solution.
Many thanks.
Wow, that works a treat! Thanks for those handy CS3 hints! :)
It works for a string like “ajjo” or “tom”. But for a string like “4545” or “8888” nothing displays. i.e. it reverts to a device font. Its weird and funny. And I have no clue why this is happening. I noticed that hasGlyph() returns false for “4545” and “8888” and true for “ajjo” and “tom”.
Help………………..
Here’s a little experiment with loading fonts dynamically at runtime. So what’s this good for? Well let’s say you have a flash application where you want to allow users to customize the text formatting for some text box. Typically you would provide a small set of fonts which would all get embedded into the swf but this isn’t very flexible or ideal. Changing font’s or adding new one’s require rebuilding the swf. Also if only one or two fonts get used then all the other extra fonts do nothing but bloat the swf size. For this situation, it would be ideal to externalize the fonts and only load in the one’s needed. Flash never supported this feature but some developer’s found ways around it. In particular, there was Shared Fonts Manager. However the author’s approach, although very impressive and useful, was a hack and not the easiest to use. With the major changes in flash 9, I got curious if runtime font loading was easier to do now and fortunately it is.
This is great felix. Thanks for sharing. I too built something very similar for a large application we’re currently building. Ran into that same issue you encountered and haven’t been able to find a fix. Have you figured it out yet (without including the font in the library?)
Issue:
“If you additionally place a static textfield onto the stage with the same font the text in the dynamic textfield isn’t shown anymore.”
Hi Imran,
I haven’t tried it since then. I’ll post it here as soon as I find out anything…
Hi,
I have troubles using bold and regular font faces in the same textfield and use CSS to switch between bold and reg. If I embed the fonts (both bold and reg) – to be precise it´s Eurostile- and try to CSS-format the textfield´s contents, the switch StyleObj.fontWeight = “bold” doesn´t do anything. Now, in a different case where I didn´t use CSS it was no problem to have bold and reg in the same field… You have a suggestion?
Hi
If you embed the font in the library then flash automatically embeds all available characters (?). Is there a way to select just a subset of the characters to be embedded while still using using the above technique, ie loading the font from an external swf?
@mathias: Using bold and regular styles in the same textfield does work. Just use html/css tags to mark the specific areas with css classes in the text string.
@Joe: As far as I know there’s no way to embed just a subset of characters with font symbols in flash. If you want to do that you have to use flex with meta/embed tags or use the flash ide and embed the characters manually in the textfields (property panel).
Gah.. I don’t get it.. it doesn’t work for me! My small application is inside a single .fla. I created a new font symbol, selected the DIN font from the drop-down. I called symbol ‘DIN’. Does size matter here btw?
Then I clicked linkage on that symbol and wrote DIN_cls in the class. I selected ‘export for actionscript’ and ‘export in first frame’.
Then inside my .fla I create a new
var myFormat:TextFormat = new TextFormat();
and then apply my font :
myFormat.font = “DIN”;
And that should work right? I haven’t forgotten anything? I tried it on another computer that doesn’t have DIN installed and it doesn’t show it. My swf file is definately bigger than it was before.
I also tried doing the Font.registerFont(DIN_cls); but you said that isn’t neccessary and that didn’t help anyway…
What am I doing wrong … ?? ;=\
P.S. Can I still change the size with AS3?
Thanks…
Ok.. well I got it to work now. It seems you might have omitted a few important lines… I am new at AS3 so maybe these are supposed to be obvious.. Anyway I got mine to work perfectly after adding these 3 lines :
var DIN:Font = new DIN_cls();
myTextField.embedFonts = true; <– important
myFormat.font = DIN.fontName;
Glad you found the solution! (Have a look at the code examples…I did mention embedFonts = true)
Hello, just wanted to say, very nice article. I have done extensive testing, research, and implementation with shared font libraries in ActionScript 2 and Flash 8 Professional. I am in the process of writing an in-depth article on the subject. I ran into may pitfalls, issues, and work arounds with the project I was working on. Here is a link to some of my findings,
http://blog.nothinggrinder.com/flash-and-japanese-fonts
I hope it can help supplement this article. I noticed you did not deal too much with preloading external fonts. This was one of the largest issues I ran into. I was also working with Asian fonts. That created a whole new set of issues all dealing with character encoding, and URL escaping.
useful article. tnx. I tried fontManager, and it did work. BUT. I tryed to embed Arial (and any of its variants) font and failed. Text is only shown in movie where font instance is defined, but not in other movies. if to change font to Gigi for example everything works fine. What is a problem? I chaked all the names an linkage ids many times.
[…] the load-time with unused fonts. I could not find much help on this topic… Luckily I found betriebsraum and with that I was able to hack up something that worked for me. So here is what i […]
Hello,
I have a couple of questions regarding .net website with flash used on 3 pages.
1. Is the loaded font available to other swf throughtout a web site or just the page the font was loaded on.
2. Does the font load in the flash cache or the browser cache?
Thank You
John
[…] trying out various different guides, I settled on this http://www.betriebsraum.de/blog/2007…-cs3-not-flex/ here, and have made a class somewhat similar to […]
Anyone been able to get _fontsDomain.getDefinition(id) working cross domain?
I’ve set up the crossdomain.xml, added Security.allowDomain and Security.loadPolicyFile; but the fonts always fail to register. The same code works fine when everything’s on the same domain.
Looks like I’ll have to go back to the old flash 8 linked symbol hack…
[…] Runtime Font Sharing For Flash CS3…[Robert’s excellent article and followup] [far more verbose] , using the traditional whole-enchilda […]
[…] If we working with external fonts in Actionscript 3.0, the external font must have a class definition for allowing the Font class and ApplicationDomain to detect and register it. We can produce class definition for the external font with embed tag in Flex or Font symbol in Flash library. In Flash CS3 you can create a font symbol in the library, and export it for ActionScript. But with this way if you embed the font in the library then flash automatically embeds all available characters. So the compiled external font swf size will increased and bloated the load-time with unused fonts. This was the largest issues especially if we working with Asian fonts. You can find more informations about it in this nice article […]
Is their anyway to tell flash to use CFF compression on an open type font as it is imported?
Well done… for those looking to see if this works, it absolutely does! The singleton does fine, you cool write another function within that class that parses through each style from the stylesheet and return an array for the registerFontsList using the fonts only from the CSS. In any case, take the 10 mins to read this post through and you will get fonts loaded at runtime through an external swf.
Thanks for the post!
Thanks for your efforts!
But one issue remains unsolved: What about embedding advanced character sets, e.g. if you want to use German umlauts and such? I haven’t found a way to make the font symbol embedding more glyphs than the basic ones. Any hints on that matter would be highly appreciated!
[…] Flash IDE scratching about for clues. The original post from which I gathered this solution is at http://www.betriebsraum.de/blog/2007/06/22/runtime-font-loading-with-as3-flash-cs3-not-flex/, kudos to […]
[…] Runtime font loading with AS3 / Flash CS3 (not Flex!) […]
Hi,
thanks for the great insights, some of them saved me lots of against-the-wall-headbashing.
You should also check the Flex [Embed..] tag support in Flash (in case you haven’t heard yet).
Here some links:
http://bryanlangdon.com/blog/2007/03/22/loading-fonts-dynamically-in-actionscript-2-and-3/
http://www.gskinner.com/talks/flexlovesflash/
Best
Mike
This along with the laughable css and ridiculous html support is why I have such a hard time convincing my bosses that we should be developing more flash rich internet applications.
[…] We needed a external font library for a project that we did. Here are two links to useful information: (Runtime font loading with AS3 / Flash CS3 (not Flex!)) http://blog.sitedaniel.com/2008/10/fontcontrol-class-external-font-library/ http://www.betriebsraum.de/blog/2007/06/22/runtime-font-loading-with-as3-flash-cs3-not-flex/ […]
[…] http://www.betriebsraum.de/blog/2007/06/22/runtime-font-loading-with-as3-flash-cs3-not-flex/ […]
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!
there is a way to register the fonts without setting a class name in the swf. then you dont need a fonts object. you just use the original name in the textfield.
Thanks for this, it has been very helpful.
I have found one issue. This works great on formatting text within tags like , but it does not seem to work when using tags with a class parameter, like .
Any ideas?
Thanks
Great it does not display the code. let me try again:
This works great on formatting text within tags like <h1>, but it does not seem to work when using tags with a class parameter, like <p class="bodyText">
Any Ideas?
Thanks
Hi Chris,
are you sure you’ve correctly declared your styles in the css file?
pretty sure
.bodyText{font-family: Verdana;
font-size: 14px;
color:#000000;
}
Ah Ha!
I read “If you additionally place a static textfield onto the stage with the same font, the text in the dynamic textfield isn’t shown anymore.” to mean you cannot have them on stage at the same time, on the same keyframe. It really means anywhere in the movie! And not just static textfields, don’t select the same font as the one you are embedding for any type field. If you have to place a dynamic text field on the stage manually instead of using AS to create, make sure to select a font that is not being embedded. Then in AS apply the style sheet.
For other things, like UI components, say the label on a radio button,
the work-around for I found is to use the transform method of the styleSheet and then the setStyle or setTextFormat method depending on where the text is (in a UI component or a textfield).
var style:Object = sheet.getStyle(“.myStyle”);//note the .
var cssFormat = sheet.transform(style);
myRadioButton.setStyle(“disabledTextFormat”, cssFormat);