Flash: Runtime Font Sharing Embedding with only Partial Character sets: How To.
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 website, and we are using several flavors of Myriad Pro to make it look great, plus a few others. 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 could render the approach useless, and I'm pretty sure this doesn't work anymore in AS3. UPDATE. !%!$ AS3 has the exact same issue, flash 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 teh 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.
Copy the right side and replace the 'unicodeRange=''' in the above class.
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.
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...:;*&^% ";
-
tf.rotation = 15;
-
addChild(tf);
-
-
}
-
-
}
-
-
}
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-enchilda Font.
[4] Special considerations when using Japanese character sets (a) usin (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.
FlashDevelop Beta 3.0 hanging? …potential solution.
I had a wierd issue with Flash Develop Beta 3.0.0 Beta 3. When it hung, it would take windows and task manager with it. Admittedly my install of XP is about a year old and likely to start getting bonked.
What I did that seemed to fix it, was uninstall all the java runtimes, repaired the .Net 2.0 framework and uninstall/reinstall .Net 3.0. Then reinstall FlashDevelop. So far it hasn't hung at all.
Compiling AS2.0 Projects with mx.* dependencies in FlashDevelop Beta 3
FlashDevelop Beta3 comes bundled with MTASC, but it by default misses an important configuration option, so building projects with references to mx.* will complain, even with the -mx option set, like:
characters 8-25 : type error class not found : mx.controls.Button
You'll need to add the following to the classpath (preferably global):
C:\Program Files\Adobe\Adobe Flash CS3\en\First Run\Classes
One trick to editing it in FlashDevelop since the file selector doesn't allow you to paste it in directly, opening up a windows Explorer window while the file dialog is open, and pasting the above into the address bar, a neat trick of windows is all windows are listening to the same events, so it will take the FlashDevelop tree browser to the correct spot.
Tools: FDT + Eclipse vrs FlashDevelop
So after another round of flux in my development environment, I resorted to using Eclipse (for coding) AND FlashDevelop (for compiling and quick projects) in tandem (along with SOS for trace debugging). Talk about a lot of desktop space!
This is because FDT+Eclipse, my favorite tool for ActionScript development is still in Beta (still a great code editor!) and in general building requires Ant tasks in Eclipse, which doesn't support the Flex Compiler Shell (huge speed increases), while FlashDevelop is an good editor, but has great compiler support.
About 2 months ago, with significant trepidation. I finally bit the bullet and made the move to AS3. It's been about 2 pretty turbulent months since. Learning the IDE of 2 major tools (Flash CS3, Flex 3.0 beta ), the massive syntax changes, new workflow, starting to get large libraries converted....breaking across the rocks of different paradigms.   Then midway the Flex beta license ran out (30 days is after all reasonable),. It wasn't worth it spending $300-$500 for a license to FlexBuilder 2.0 to keep going.
- I'm going to Max in October, I know 3.0 is out in a few months,
- The code editor is an order of magnitude weaker than FDT, and still quirky enough to make it unuseable at times in the beta, I guess some of my code does some tricky things which causes Flex's language parser to barf.
- I don't plan on using FlexBuilder/Flex on most of my projects...we aren't that data/standard control centric.
This created a window of no reasonable workflow. FlashCS3 does compile AS3 well (I first started having to use it with FlexBuilder 3.0, when running into quirks in it's parser). But the editor isn't much better than a plain text editor, for dealing with large libraries and components. So I started investigating other platforms, Sepy and FlashDevelop...etc. Which is about as motivating as looking at a bicycle after driving an F1,...but admittedly better than walking barefoot or standing still.   I was hoping that in my lack of paying attention that the years since I last reviewed would have some new releases, and while I didn't have time to investigate Sepy, I was pleased with FlashDevelop Beta 3. In a sunday afternoon I got from ground zero to building an AS2, and an AS3 project both using the Flash CS3, and separate the Mxmlc.exe, which nicely prompted me to look for the 'Flex Compiler Shell', which I hadn't heard of before.
http://labs.adobe.com/wiki/index.php/Flex_Compiler_Shell
The compiler shell is designed to startup once then talk with it, telling it to recompile files, typically by getting an id back on the first compile then recompiling. This can amount to huge timesavings. Once installed and incremental compiling is on, It's similar the speed jump to me from using Flash to using MTASC.
YAY!!!!
Incremental compiling has been high on my list of things I've been looking for out of AS3, Java has had this for almost a 8 years, and I grew to depend on it. Java is still way ahead...you can hot fix code running in the VM without restarting...while debugging, even remotely (if allowed)!.
FlashDevelop Beta 3 supports the Flex Compiler Shell without anything special, just drop in and go (very nice!). Sadly for Eclipse/Ant/FDT it won't work well, as the major performance increase is from not having to startup the mxmlc.exe everytime, but ant starts up and closes down as soon as it's finished, and there is no easy way to modify Ant/Eclipse to keep the process/dialog open. But since it's not terribly difficult to have both open, that's what I've done.
The biggest thing that I miss via this is the errors output by the compiler (both the syntax check, and full compile errors) show up in FlashDevelop, which clicking on lets you jump to, when I'd rather do it in Eclipse. Both tools are smart to watch for file changes, so it's possible to edit in both places. If a bit more UI to wrangle than idea;
