Apr 09 2009
Loading embedded fonts on-demand using the uiFonts manager
Why Embed Fonts?
Embedding a font inside a SWF file means that the font does not need to be present on the devices the SWF file eventually plays back on. In order to ensure that text are rendered in the way the Flash application developer originally intended, it is often necessary to embed the fonts used in the application. This is especially so for fonts that are not commonly installed in the target devices. The use of embedded fonts is also mandatory for some features of the Flash Player to work, such as text rotation and transparency (pre-Flash Player version 10).
The Problem
Unfortunately, embedding fonts into the application SWF can seriously bloat the file size. It will also increase compile time significantly, wasting much development time.
The Solution
Using the uiFonts manager from Aspire UI Standard Edition, it is possible to use embedded fonts without compiling them into the main application SWF. Instead, each individual font exists in its own external SWF file which is loaded into the application on-demand during run-time. These font SWF files can be created once for each font and re-used across different applications.
This is especially helpful for applications where the use of embedded fonts is essential, such as an apparel print design or greeting card design application that offers multiple font choices.
Live Demo
The following is a live demo of the uiFonts manager in action (FontsExample.swf):
- The text displaying “The quick brown fox jumps over the lazy dog.” is slightly rotated, so it won’t show up unless it is using embedded fonts.
- The application starts with no embedded font available for usage.
- Clicking the “DejaVu Sans” button loads the “DejaVu_Sans.swf” file from the “assets/fonts/” folder. Once it is loaded, the embedded font will be used automatically. To load the font dynamically during run-time, uiFonts.manager.load(“DejaVu Sans”) is called – the font name is specified, not the font file name.
- Likewise, clicking the “SanaFon” button loads “SanaFon.swf” – uiFonts.manager.load(“SanaFon”) is called.
- A Bold version of the “SanaFon” font does not exists.
FontsExample.as
Here is the source code of the FontsExample.as class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | package { import com.ghostwire.ui.containers.*; import com.ghostwire.ui.controls.*; import com.ghostwire.ui.data.*; import com.ghostwire.ui.events.*; import com.ghostwire.ui.enums.*; import com.ghostwire.ui.managers.*; import flash.display.Sprite; import flash.events.*; import flash.system.Capabilities; public class FontsExample extends Sprite { // ** instances ** private var displayTextA:uiText; private var displayTextB:uiText; private var progressText:uiText; public function FontsExample() { // ** make sure stage is not null ** addEventListener(Event.ADDED_TO_STAGE,init); } private function init(evt:Event):void { // ** let assets preload before starting application ** uiSkins.manager.addEventListener(Event.INIT,main); } private function main(evt:Event):void { // ** topLevelPane ** var topLevelPane:uiPane = new uiPane(); topLevelPane.padding = 4; topLevelPane.setSize(stage.stageWidth,stage.stageHeight); addChild(topLevelPane); var titleText:uiText = new uiText("Aspire UI Components Example"); titleText.alignX = ALIGN.CENTER; titleText.background = {color:0x819A98,cornerRadius:12} titleText.padding = "6,12"; titleText.textStyle = "title"; topLevelPane.addChild(titleText); var versionText:uiText = new uiText("Flash Player Version "+Capabilities.version); versionText.alignX = ALIGN.CENTER; versionText.y = topLevelPane.height - 80; topLevelPane.addChild(versionText); var footerText:uiText = new uiText("© 2008-2009 GhostWire Studios") footerText.background = {color:0x819A98}; footerText.padding = 3; footerText.alignX = ALIGN.CENTER; footerText.fillX = true; footerText.textStyle = "footer"; footerText.y = topLevelPane.height - 60; topLevelPane.addChild(footerText); var ghostwireMark:uiImage = new uiImage("GhostWireStudiosMark"); ghostwireMark.alignX = ALIGN.CENTER; ghostwireMark.alignY = ALIGN.BOTTOM; topLevelPane.addChild(ghostwireMark); // ** display text ** displayTextA = new uiText(); displayTextB = new uiText(); displayTextB.rotation = 2; // ** text will not show unless using embedded font ** displayTextA.text = displayTextB.text = "The quick brown fox jumps over the lazy dog."; var txt:uiBox = new uiBox(); txt.vertical = true; txt.alignX = ALIGN.CENTER; txt.y = 60; txt.addChild(displayTextA); txt.addChild(displayTextB); topLevelPane.addChild(txt); // ** end display text ** // ** buttons ** var buttons:uiBox = new uiBox(); buttons.alignX = ALIGN.CENTER; buttons.y = 150; buttons.spacing = 20; var buttonA:uiLabelButton = new uiLabelButton("DejaVu Sans"); var buttonB:uiLabelButton = new uiLabelButton("SanaFon"); buttonA.fillY = true; buttonB.fillY = true; buttonA.data = "styleA"; buttonB.data = "styleB"; buttonA.addEventListener(MouseEvent.CLICK,on_click,false,0,true); buttonB.addEventListener(MouseEvent.CLICK,on_click,false,0,true); buttons.addChild(buttonA); buttons.addChild(buttonB); topLevelPane.addChild(buttons); // ** end buttons ** // ** progress text ** progressText = new uiText(); progressText.alignX = ALIGN.CENTER; progressText.y = 190; topLevelPane.addChild(progressText); // ** end progress text ** // ** end topLevelPane ** // ** create some text styles ** uiTextStyles.manager.setStyle("styleA",{fontFamily:"DejaVu Sans",fontSize:16}); uiTextStyles.manager.setStyle("styleB",{fontFamily:"SanaFon",fontSize:16}); uiTextStyles.manager.setStyle("styleABold",{fontFamily:"DejaVu Sans",fontSize:16,fontWeight:"bold"}); uiTextStyles.manager.setStyle("styleBBold",{fontFamily:"SanaFon",fontSize:16,fontWeight:"bold"}); } /** apply new text style and load external font swf on demand */ private function on_click(evt:MouseEvent):void { displayTextA.textStyle = String(uiLabelButton(evt.target).data); displayTextB.textStyle = displayTextA.textStyle+"Bold"; if (displayTextA.embedFonts) { // ** embedded font already loaded and in use ** progressText.text = ""; } else { // ** begin loading external font swf ** progressText.text = "Loading..."; uiFonts.manager.load(uiLabelButton(evt.target).text); uiFonts.manager.addEventListener(ProgressEvent.PROGRESS,on_loadProgress); } } /** tracks download progress */ private function on_loadProgress(evt:ProgressEvent):void { progressText.text = ((evt.bytesLoaded == evt.bytesTotal) ? "Total: " : "Loading: ")+evt.bytesLoaded+" bytes"; } } } |
- Lines 67-84: This is the display text for “A quick brown fox jumps over the lazy dog”. Notice that the “rotation” property of the containing box is set to 2 – the text will not show unless embedded fonts are used.
- Lines 87-108: These are the buttons that will set the text to the text styles using the respective fonts, and initiate the loading of the external font swf files.
- Lines 111-116: This is the text that shows the loading progress while an external font SWF file is being loaded.
- Lines 121-124: Set some text styles to use the respective fonts.
- Lines 130-146: Event handler when a button is clicked. Notice the “embedFonts” property is queried – this property automatically assume true/false depending on whether the embedded font is available or not.
- Lines 151-155: Event handler for tracking the download progress of external font SWF files.
- Notice that there is no code explicitly asking text fields to use embedded fonts (after the fonts are loaded) – this is not necessary because the uiFonts manager works together with the uiTextStyles manager to invalidate and redraw uiText instances automatically after a font is loaded.
Font SWF Files
For instructions on how to create individual font SWF files, please refer to uiFonts usage notes.
Aspire UI Components
Aspire UI is a library of Actionscript 3.0 (AS3) classes for building flexible and lightweight UI elements in Adobe Flash applications. Key features of the components include easy skinning using PNG image files, automatic tab focus ordering, CSS text styles, and layout management. This is a pure AS3 library with no dependency on the Flex framework. You may experiment with the various features by downloading a trial version.
Other Posts You Might Enjoy:
- Compiling embedded font SWFs with the Flex compiler for use with the uiFonts manager
- Using uiTextStyles: Defining Faux Bold Weights (Embedded Fonts)
- [AS3] Embossed and Engraved Text Effects (Embedded Fonts)
- Using uiTextStyles: Drawing Outline on Text Glyphs
- Using uiWindow: Setting the color and transparency level of the background overlay of modal windows








Embedding fonts in Flex is an attractive feature… but can be a dangerous one from a legal perspective if you haven’t done some homework. Most fonts installed on your computer, included with your OS, purchased from vendors, and etc are licensed to you and only you for the purpose of creating ‘derivative’ works… e.g. creating business cards, a poster, t-shirts, graphics for a website and are not intended for redistribution with a software application.
There are many free fonts on the web – but keep in mind that ignorance is no defense if the ‘free’ font you downloaded turns out to be owned by someone else. Due diligence is always required. It’s always a good idea to get permission in writing where your intended purpose is disclosed in full with verbiage that establishes authorship.
Great post by the way!
I’m working on similar system. The main problem in loading embeded font in external SWF is the huge size when need CJK glyphs. But i found a solution : streaming font for load on demand needed glyphs.
My post about this, but in French yet, sorry:
http://memmie.lenglet.name/?p=33
Direct link to demo:
http://memmie.lenglet.name/documents/lab/fontstream/waterfall_demo.html
@Rick, thanks – those are very valid points you raised. I have updated the uiFonts documentation page to include a reminder that says “Before compiling fonts into SWF files, read the font EULA to see if permission to do so has been granted. If in doubt, contact the font vendor for advice before proceeding.”
Come to think of it, Adobe should probably do it in its documentation too!
@mems
Embedding fonts from Flex like Lee Brimelow (http://gotoandlearn.com/play?id=102) is very nice, I just noticed a very important thing: Remember to add space if you are picking out separate Glyphs. If not the glyphs will space out very strange if you select them or apply bold / italics. Whistespace is a glyph too even if it is not visible. Sorry if this post was a bit offtopic.
@Sunny
Brilliant components!
Does the font manager support the Flex way of embedding them as well using the metaData tag ?
-F
Yes, the uiFonts manager will work just as well with font swfs compiled using the Flex compiler, ie using the [Embed] metatag. In fact, that is the only way (that I know of) should you want to specify unicodeRange.
I should probably post another entry on how the AS3 class used to compile a font swf would look like. Thanks!
Update:
http://ghostwire.com/blog/archives/compiling-embedded-font-swfs-with-the-flex-compiler-for-use-with-the-uifonts-manager/
This is a great script. Dynamically embedding fonts in Flash is a pain!