AS3 Font embedding masterclass
One of the people I follow on Twitter, Jesse Freeman, twitted that he was having some problems getting embedded fonts working properly in Flash. As the problem sounded immediately familiar (the amount of time you spend cursing out something in Flash is inversly proportional to the amount of time it takes to remember what it was), I chimed in with what turned out to be the solution. Long story short, if you're having problems embedding fonts in AS3, try setting
embedAsCFF = "false" in your embed code.
Simply finishing this post at that doesn't really satisfy my need to have mountains of text on the internet and thus look like I know what I'm talking about, so I figured to share the info I gathered up about a year ago when I hit the same problem. So why is embedded fonts in AS3 such a Pain In The Ass™ ?
There are 3 main ways to embed a font in a SWF:
This is probably the most common for Flash game devs looking to embed a specific font for their game. For this, we're using the
// to embed a font file that's relative to your project [Embed(source="../someFont.ttf", fontName = "myFont", mimeType = "application/x-font", fontWeight="normal", fontStyle="normal", unicodeRange="englishRange", advancedAntiAliasing="true", embedAsCFF="false")] private var myEmbeddedFont:Class; // to embed a system font [Embed(systemFont="Arial", fontName = "myFont", mimeType = "application/x-font", fontWeight="normal", fontStyle="normal", unicodeRange="englishRange", advancedAntiAliasing="true", embedAsCFF="false")] private var myEmbeddedFont:Class;
It doesn't matter what you call the variable under the
Embed tag as you don't use it. You also don't need all of these parameters, but I'll explain each one briefly.
sourceif you're embedding a font file that's relative to your file (the .as file, not the SWF). Use
systemFontto embed a font from your computer's Fonts folder. In this case, you pass the name of the font (e.g. "Arial", "Trebuchet Ms" etc.)
This is the name you supply to your font. It can be anything you want, though if you use
source, then it shouldn't be the same name as the font (the compiler should throw a warning). This is what you supply to the
fontparameter of your
The mimeType in which to embed the font. I didn't notice much difference between using
"application/x-font-truetype". Perhaps one is for OpenType fonts and the other's for TrueType fonts. In any case, Flex should pick the right one for you, so you can pretty much ignore this. See http://livedocs.adobe.com/flex/3/html/help.html?content=embed_3.html#176407 for more info on the
"heavy". This will embed only that specific weight for the font. If you specify
"bold", but your
TextFormat/TextFieldis set up for normal text, it will display bolded, and vice versa. The default is
"oblique". Works in the same manner as
unicodeRange(Optional but recommended)
If you don't want to embed the full font (probably a smart move on your part), you can specify a range of characters to embed. This can be in the form of
"U+0030-0039,U+002E"(for numbers), or a language range set in the Flex config file (if you're the sort of loser that doesn't know unicode ranges by heart). There's a list of language ranges defined in flash-unicode-table.xml (found in PATH_TO_FLEX_SDK/frameworks), that you can copy over to flex-config.xml (same folder - scroll down until you see the
<fonts>tag, and you should see a commented-out example). Finding the right place to put them should be obvious. Useful ones include "Numerals", "Basic Latin" and "englishRange".
NOTE: If you're using AIR, note that it reads from air-config.xml/airmobile-config.xml depending, not flex-config.xml, so make sure you copy over your ranges to here as well.
Can be either
"false". When set to
true, additional information is added that lets the fonts display clearer and sharper at smaller font sizes. However, this can increase your memory usage. Embedding 4 or 5 fonts with
advancedAntiAliasingcan increase your memory by a few MB or so. It's set to true by default.
embedAsCFF(Optional but recommended)
With Flex 4, font embedding has changed, with fonts coming in as
embeddedCFFor Compact Font Format. This is to work with the new Flash Text Engine (FTE), but unless you're using Flex Spark components, you probably don't care. Without going into too much detail (see the links at the bottom of the page), setting this to
"false"means that you can actually use your font with the Flex 4 SDK. An alternative to this is to specify that you're using the Adobe Font Manager rather than the default BatikFontManager, by compiling with the line
-manager=flash.fonts.AFEFontManagerin the compiler options of your project. If you're not changing your font manager, then setting this is important, as Flash can tell you that your font is embedded, but you won't be able to use it. By default (under Flex 4),
embedAsCFFis true, or you can set the
3.0to set the default to
Using an embedded font
To use this in your project, you first set up a
TextFormat object with the
font parameter set to the
fontName that you specified in your
Embed statement. Also make sure to specify
embedFonts = true; on your TextField otherwise you won't use them/it won't show up. To easily know if your
TextField is using the embedded fonts, just rotate your
TextField slightly, as only embedded fonts can be rotated.
// create our TextFormat var tf:TextFormat = new TextFormat( "myFont", 20 ); var t:TextField = new TextField; t.embedFonts = true; // very important to set t.autoSize = TextFieldAutoSize.LEFT; t.defaultTextFormat = tf; t.text = "Hello World"; this.addChild( t );
Embedding using a SWF
Embedding fonts using a SWF is somewhat easier. If you've ever created a game in Flash and used the Flash IDE to produce graphics, you've probably done everything you need to before.
- Create a new FLA file and create a
TextFieldon the stage.
- Keep it as static and type some text if you want a very specifc set of characters. Otherwise, set it to dynamic.
- If you want to used advanced anti-aliasing, make sure that the Anti-Alias for Readability or Custom Anti-Alias is the selected anti-alias mode. Any other option and Flash won't include anti-aliasing information for the font in the SWF file.
- If your
TextFieldis a dynamic one, in the Properties panel, click the Embed button, and embed whichever characters you want.
- Create any other
TextFields as needed (different fonts, bold, italic, etc.)
- Export your SWF
Here, I've created two
TextFields, one static and one dynamic. The static
TextField is using the Futura Md font, while the dynamic
TextField is using the Courier New font and embedded with the characters for Basic Latin.
If you're using FlashDevelop, then you can see what fonts are embedded in a SWF, including the number of characters:
As you can see, there's two fonts available for me to use. There's only 11 characters for Futura Md, as that
TextField was static, so Flash only includes the characters used.
For our AS code, we change the
Embed call to:
[Embed(source="../assets/test.swf", fontName="Courier New" )] private var myEmbeddedFont:Class;
Note that the
fontName is the name of the font that you used in Flash. If you embedded a bold/italic version, then you'll also have to set
fontWeight = "bold" or
fontStyle = "italic".
NOTE: If you use a static
TextField you MUST set it as selectable, otherwise you won't be able to access the font.
// create our TextFormat var tf:TextFormat = new TextFormat( "Courier New", 20 ); // create the TextField the same as above
Embedding using a font symbol
Finally, we can embed fonts using a font symbol in Flash.
- In your library, create a new font symbol by right-clicking or using the small down arrow in the upper right corner.
- Give the font symbol a name (can be anything), select the font that you want and its properties (bold, italic...). Don't set the symbol name to the same as the font name - this is just to make it clearer, it won't stop the code from working.
- Right-click on the font symbol and select Linkage. Select Export for Actionscript. Add an identifier for the symbol, or just use the default (the name of the font symbol in the library).
- Export your SWF.
Here, I added a font symbol for the Times New Roman font and gave it an export linkage name of "myFontSymbol":
You'll notice that there's 243 characters in our font symbol. That's because there's no way (at least that I've found in CS3; it might be different in CS5) to say that you only want to export a specific set of glyphs.
In our AS code, we make a change to the
Embed code like this:
[Embed(source="../assets/test.swf", symbol="myFontSymbol" )] private var myEmbeddedFont:Class;
As we're embedding a symbol here, don't set the
fontStyle etc. or the compiler will throw an Error along the lines of
Error: transcoding parameters 'symbol' and 'fontStyle' are incompatible. For the
font property of your
TextFormat object, we change it to the name of the font, not the font symbol name, or the symbol linkage name.
// create our TextFormat var tf:TextFormat = new TextFormat( "Times New Roman", 20 ); // create the TextField the same as above
TextField fonts still look ugly, even though the font is embedded!"
Make sure you've set the
embedFonts property to
true. To make sure that you're using an embedded font, set the
rotation property to a value other than 0, as only embedded fonts will show when the
TextField is rotated.
"Flash says my font is embedded but I can't get it to work!"
When you're embedding your font, set
embedAsCFF to false, or compile with
-manager=flash.fonts.AFEFontManager to use the Adobe Font Manager, or compile with
compatibility-version set to
3.0, where the default value for
"I get an 'unable to transcode' error!"
Check the embed path to your font. Make sure it's relative to the file that's doing the embedding, not your project root or the SWF file.
"I get a 'transcoding parameters 'x' and 'y' are incompatible' error!"
You're probably trying to embed a symbol and not a font. See the Embedding using a font symbol section.
"I get an 'unable to build font' error!"
Try using the Adobe Font Manager by compiling with
"I get an 'invalid Unicode range 'ENGLISHRANGE'' error! (or similar)
If you're hardcore, and entering unicode ranges by hand, make sure it's actually valid. They should be in the form
unicodeRange="U+0041-U+005A,U+0061-U+007A" (upper- and lower-case a-z) and you can find a list of the ranges online.
If you're using named ranges, make sure they're defined in the right config file (all found in PATH_TO_FLEX_SDK/frameworks): flex-config.xml for AS3/Flex, air-config.xml or airmobile-config.xml for AIR - scroll down until you see the
<fonts> tag and you'll find a commented-out example. You can find a handy list of them in flash-unicode-table.xml.
"Only some of my characters are showing up!
This is a bit of a hairy bug, but it's probably this. Basically it can happen when you embed the same font in two different SWFs/SWCs that are used in one project. Say you have SWF A and SWF B that you include in your main project. SWF A embeds Arial and the characters a, b and c. SWF B embeds the full Arial font (same weight as the font in SWF A). If SWF A is compiled in your project first, then Flash will only take those glyphs (i.e. a, b, and c), ignoring those in SWF B. This is why only some characters in your
TextFields are showing up. Take note that static
TextFields also count towards embedded text. If you code in FlashDevelop you can click the [+] beside the SWF, and again on the font so see how many glyphs have been embedded.
As this bug doesn't look like it's going to get fixed, there's a few solutions you can employ:
- Embed the same glyphs in both SWFs/SWCs. Can be an upkeep nightmare.
- Embed each font under a different name so there's no conflict. Requires foreknowledge of the use of the SWF (not ideal for shared libs).
- Create a separate "module" SWF that has the font, and use that SWF in all SWFs that need it.
- Remove the font entirely from SWF A and SWF B and put it in your main SWF. Sometimes not possible to do entirely (static
- Embed each font under a different weight (i.e. SWF A embeds as "normal", while SWF B embeds as "bold").
I found all of these links useful when digging into this. The first two are manadatory reading, the rest explain the subject a bit better.
- Using embedded fonts (Flex3): http://livedocs.adobe.com/flex/3/html/help.html?content=fonts_04.html#133099
- Using embedded fonts (Flex4): http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7f5f.html
- Syntax for embedding assets (Flex3): http://livedocs.adobe.com/flex/3/html/help.html?content=embed_3.html#176407
- Syntax for embedding assets (Flex4): http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf60546-7ffb.html
- "Flex loves Flash" - A Grant Skinner talk: http://www.gskinner.com/talks/flexlovesflash/
- Embedding metadata with Flash (comment links): http://www.adobe.com/devnet/flash/articles/embed_metadata.html
- AS3 Font Managers (Flex3): http://livedocs.adobe.com/flex/3/html/help.html?content=fonts_06.html
- AS3 Font Managers (Flex4): http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7e09.html
I've created a project that includes everything I talked about here. It has the code and Flash files necessary to to just about all the types of font embedding you could wish for. You can download it here.