Flash: Runtime Font Sharing Embedding with only Partial Character sets: How To.

by troy on September 12, 2008

While not planning on it, spent most the day figuring out how to implement runtime shared fonts, while only embedding a fraction off the characters. Holy moly was this a minefield. But happily got a simple solution.

Here's the goal, I'm working on the phase 2.x of a web based application that uses several flavors of a stylish font. However with each flavor weighing in at ~35Kb each we are loading about 200K worth of fonts (bold, italic, bold italic etc), and at present many of the pages have their own copies of the fonts (the typical evil that comes up on projects with no time), so the sight loads far more sluggish than it should. After this and the following are done, the load is down to 54kb, as only the elements needed are loaded once.

In Flash IDE (CS3) and prior selecting partial characters was easy if you only had one swf, just select from the characters in the embed button, in the properties panel. If you have character sets you use often, short cut this by creating custom character sets, with this neat approach, perhaps even with this tool However this is only really good for elements scoped inside the swf with the embedded font, no way to share them between swfs without resorting to traditional runtime shared libraries that have several issues (like bypassing preloaders all together). In AS2.0 there was a nifty hack possible to help,where a embedded font was coerced into sharing by a proxy clip that referenced it as a runtime shared library, at the preloaders convenience, but this (for me) was brittle in having font collisions, e.g. a static textfield on stage having the same font, could render the approach useless (like the font wouln't show up at all!), and AS3 has the exact same issue.

Fflash player appears to load a font in a given swf scope on a first come-first serve only once. Meaning any static or textfield anywhere on the stage (regardless or not if any characters are embedded) will collide with whatever you load in dynamically later, rendering the dynamically loaded useless,...and any references to it. Meaning your dynamic textfields will break...not show up at all!. A possible workaround is having either the placeholder textfields with a sacrificial font (e.g. sans), or renaming the font in the embed created in a few steps to something like (Myriad Pro ->MyriadPro) and adjusting the css/etc.

For reasons unknown to me, adding a Font symbol to the library (either for use with actioncript, or runtime sharing) embeds the whole font.  Needless to say, when on the web, getting every character known to mankind is not going to help your site load fast. This can be the difference of 2kb for only what you need for the preloader, to 2MB for entire international character sets. Also it can grind compile times to a halt, as every publish requires every glyph to be embedded and this is time consuming. Both seem like major oversights on the Flash IDE's design.

So oddly the best way to create fonts is to use the Flex 3.x SDK (download). For this the great and free FlashDevelop (download) will work great (if your on windows).  Just follow the installation instructions, setup a new Actionscript 3, Flex 3 Project.

Create a class like the following in the 'src' directory, and in the righthand tree, right click over it and select 'always compile'

 package {  
 
      import flash.display.Sprite;
   	  import flash.text.Font;
      public class MyriadProFontLib extends Sprite {  
 
           [Embed(source='C:/WINDOWS/Fonts/MyriadPro-Regular.otf', fontName='Myriad Pro', unicodeRange='U+0020-U+0020,U+0021-U+0021,U+0022-U+0022,U+0023-U+0023,U+0024-U+0024,U+0025-U+0025,U+0026-U+0026,U+0027-U+0027,U+0028-U+0028,U+0029-U+0029,U+002A-U+002A,U+002B-U+002B,U+002C-U+002C,U+002D-U+002D,U+002E-U+002E,U+002F-U+002F,U+0030-U+0030,U+0031-U+0031,U+0032-U+0032,U+0033-U+0033,U+0034-U+0034,U+0035-U+0035,U+0036-U+0036,U+0037-U+0037,U+0038-U+0038,U+0039-U+0039,U+003A-U+003A,U+003B-U+003B,U+003C-U+003C,U+003D-U+003D,U+003E-U+003E,U+003F-U+003F,U+0040-U+0040,U+0041-U+0041,U+0042-U+0042,U+0043-U+0043,U+0044-U+0044,U+0045-U+0045,U+0046-U+0046,U+0047-U+0047,U+0048-U+0048,U+0049-U+0049,U+004A-U+004A,U+004B-U+004B,U+004C-U+004C,U+004D-U+004D,U+004E-U+004E,U+004F-U+004F,U+0050-U+0050,U+0051-U+0051,U+0052-U+0052,U+0053-U+0053,U+0054-U+0054,U+0055-U+0055,U+0056-U+0056,U+0057-U+0057,U+0058-U+0058,U+0059-U+0059,U+005A-U+005A,U+005B-U+005B,U+005C-U+005C,U+005D-U+005D,U+005E-U+005E,U+005F-U+005F,U+0060-U+0060,U+0061-U+0061,U+0062-U+0062,U+0063-U+0063,U+0064-U+0064,U+0065-U+0065,U+0066-U+0066,U+0067-U+0067,U+0068-U+0068,U+0069-U+0069,U+006A-U+006A,U+006B-U+006B,U+006C-U+006C,U+006D-U+006D,U+006E-U+006E,U+006F-U+006F,U+0070-U+0070,U+0071-U+0071,U+0072-U+0072,U+0073-U+0073,U+0074-U+0074,U+0075-U+0075,U+0076-U+0076,U+0077-U+0077,U+0078-U+0078,U+0079-U+0079,U+007A-U+007A,U+007B-U+007B,U+007C-U+007C,U+007D-U+007D,U+007E-U+007E,U+00A9-U+00A9,U+00AE-U+00AE,U+00B7-U+00B7,U+02C6-U+02C6,U+02DC-U+02DC,U+2013-U+2013,U+2014-U+2014,U+2018-U+2018,U+2019-U+2019,U+201A-U+201A,U+201C-U+201C,U+201D-U+201D,U+201E-U+201E,U+2020-U+2020,U+2021-U+2021,U+2022-U+2022,U+2026-U+2026,U+2030-U+2030,U+2039-U+2039,U+203A-U+203A,U+20AC-U+20AC,U+2122-U+2122')]  
 
            public static var _MyriadPro:Class;  
 
			public function MyriadProFontLib()
			{
				super();
				 Font.registerFont(_MyriadPro);
			}
      }
 }

Go to the Top Nav's "Project>Properties" and adjust the output file to something like "bin\FontLibs.swf"

Copy the characters you want as Ascii e.g. (missing white space)
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~©®·ˆ˜–—‘’‚“”„†‡•…‰‹›€™

goto this great unicode converter here

top left 'characters' box, then hit convert

select the output from the Unicode U+hex notation box, and paste it into this app's left side.
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Copy the right side and replace the 'unicodeRange=''' in the above class.
In the text box next to the green play looking button make sure that the build text mode says "Release" instead of "Test" or "Debug". Then build the file by pressing the green play looking button. If all goes well you should see the console output

(fcsh)
Build succeeded
Done (0)

and a new FontLibs.swf in the bin folder.

If you don't select Release you will get issues on older versions of the Flash 9(around 9.014) player asking users the locations of the Flash debugger, Not good.

You can use the excellent Action Script Viewer 6 to look at the glyphs embedded into the FontLibs.swf. This is very useful for seeing if the unicode is getting you the characters you think you are putting in. I tried several ascii to unicode convertors, and only the one linked above got it right.

Then using the tool of your choice create this class to load up the fontlib and use a dynamic textfield.

 package {  
 
      import flash.display.Loader;  
 
      import flash.display.Sprite;  
 
      import flash.events.Event;  
 
      import flash.net.URLRequest;  
 
      import flash.text.*;
	import flash.utils.describeType;
 
      public class FontLoader extends Sprite {  
 
           public function FontLoader() {  
 
                loadFont("FontLibs.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 {  
 
                drawText();  
 
           }  
 
           public function drawText():void {  
 
                var tf:TextField = new TextField();  
 
                tf.defaultTextFormat = new TextFormat("Myriad Pro", 16, 0);  
 
				tf.embedFonts = true;  
 
              tf.antiAliasType = AntiAliasType.ADVANCED;  
 
                tf.autoSize = TextFieldAutoSize.LEFT;  
 
                tf.border = true;
                tf.text = "Troy was here\nScott was here too\nblah scott...:;*&amp;^% ";
                tf.rotation = 15;
                addChild(tf);  
 
           }  
 
      }  
 
 }

At this point you might also like to know how to embed multiple fonts into a single library for that see this post.

In decreasing order of relevance, these are some of the posts that I read to get to this point.

If characters that are embedded are funky, and your using Flex 2.0, upgrade to Flex SDK 3.x. I was originally using Flex 2.0...very dated at this point.

If your using OTF (Open Type Fonts) like Myriad Pro make sure your using Flex SDK 3.x else you might have issues...flex 2.0 is very dated at this point. Also consider using a tool like the excellent CrossFont if you're trying to use Mac Fonts.

[1] The one that helped 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 solution here is cleaner.

[2] Flex 3.x Compiler comes with multiple The font transcoder doesn't always work, try another. in particular the (flash.fonts.AFEFontManager);

[3] Runtime Font Sharing For Flash CS3...[Robert's excellent article and followup] [far more verbose] , using the traditional whole-enchilada Font.

[4] Special considerations when using Japanese character sets (a) using (b)

[5] A must read if you want a grand Q&A of embedded fonts and many quirks, (CSS specific)

[6] More details on mime-type for the font, I think this was only relevant in Flex 2.0 than Flex 3.x.

[7 ] Basics with AS3/Flex without using a library

[ 8 ] More rants on Flash CS3's lack of proper embedding, in particular with pixel fonts..Flash CS3 renames them for you.