• warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 2 to gmap_gmap() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.
  • warning: Parameter 1 to tac_lite_node_grants() expected to be a reference, value given in /home/rbezemer/softwarebyrichard.com/includes/module.inc on line 483.

Embedding fonts in Flex 4

One thing that seems to be always required on most flex project I've been a part of is the ability to dynamically embed fonts the the project. It just comes with the territory of creating dynamic content generators where you want the user to be able to have as many fonts as they can, but don't want the overhead of loading 100+ fonts at load time.

 

Compared to Flex 3, I found the process in Flex 4 to be much simpler than in previous versions. It took me a while to work out the exact steps since nothing I could find online explained it in exactly the way I wanted to use it.

 

The easiest method I found was to create run time pre-compiled css files, and the process is as follows:

  1. Create a subdirectory in your project to hold the font files (I usually use assets/fonts)
  2. Create a subdirectory in the above called ttf.
  3. Put any ttf font resources in that directory. FontSquirrel or Google Fonts are great resources for this. It works best if you use fonts that have normal, bold, bolditalic and italic stylings available
  4. create a css file for each font int assets/fonts
  5. Inside that css you can put the following:
    1. /* CSS file */
    2. @namespace s "library://ns.adobe.com/flex/spark";
    3. @namespace mx "library://ns.adobe.com/flex/mx";
    4.  
    5. @font-face {
    6. src: url("assets/fonts/ttf/MyFont_normal.ttf");
    7. fontFamily: "MyFont";
    8. embedAsCFF: true;
    9. }
    10. @font-face {
    11. src: url("assets/fonts/ttf/MyFont_bold.ttf");
    12. fontFamily: "MyFont";
    13. fontWeight: "bold";
    14. embedAsCFF: true;
    15. }
    16. @font-face {
    17. src: url("assets/fonts/ttf/MyFont_bolditalic.ttf");
    18. fontFamily: "MyFont";
    19. fontWeight: "bold";
    20. fontStyle: "italic";
    21. embedAsCFF: true;
    22. }
    23. @font-face {
    24. src: url("assets/fonts/ttf/MyFont_italic.ttf");
    25. fontFamily: "MyFont";
    26. fontStyle: "italic";
    27. embedAsCFF: true;
    28. }
  6. Save the css file.
  7. In FlashBuilder, right click on the font css file, and check off "Compile CSS to SWF". compile css to swf previewThis will ensure that when you compile your project the css file will be compiled to a loadable swf file in your bin directory.
  8. Next you will need to tell you application to load the font at runtime. The easiest way to do this is to use the stylemanager class like so:
    1. private function selectFont(fontXML:XML):void {
    2. var path:String = fontXML.@source;
    3. var myEvent:IEventDispatcher = styleManager.loadStyleDeclarations(FlexGlobals.topLevelApplication.url.substring(0,FlexGlobals.topLevelApplication.url.lastIndexOf("/"))+"/"+path);
    4. myEvent.addEventListener(StyleEvent.COMPLETE, fontLoaded);
    5. }
    6.  
    7. private function fontLoaded(event:StyleEvent):void{
    8. item.setStyle("fontFamily", fontXML.@name);
    9. }
  9. And that is it, you can check to see if your font is loaded by enumerating the fonts loaded into the flex application:
    1. var fontList:Array = Font.enumerateFonts(false);
    2. for (var i:uint=0; i<fontList.length; i++) {
    3. trace(fontList[i].fontName)
    4. }

The next tricky part is displaying these fonts in an UI so that the user can see what the font looks like and select it to use in their application. What I usually do is create an xml file that list the font name, path to the compiled css file, and path to a png of a sample of the font (since loading the font to preview would kind of defeat the purpose of having a dynamically loaded font).

Once this xml file is loaded into the application it's trivial to create a quick dropdown combo box that lists all the fonts availalbe. Here's the basics to get you going and tie everything together:
the combobox mxml:

  1. <s:ComboBox
  2. id="_fontChooser"
  3. labelField="@name"
  4. dataProvider="{_fontListXML}"
  5. itemRenderer="FontListRenderer"
  6. change="fontFamilyChange()"
  7. />

The FontListRenderer:
  1. <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
  2. xmlns:s="library://ns.adobe.com/flex/spark"
  3. xmlns:mx="library://ns.adobe.com/flex/mx"
  4. autoDrawBackground="true">
  5. <fx:Script>
  6. <![CDATA[
  7. import mx.controls.Image;
  8. import mx.core.FlexGlobals;
  9. import mx.managers.PopUpManager;
  10.  
  11. import spark.components.BorderContainer;
  12. private var _fontPreview:BorderContainer;
  13.  
  14. private function fontPreview_complete(evt:Event):void {
  15. var img:Image = evt.currentTarget as Image;
  16. img.percentWidth = 100;
  17. img.percentHeight = 100;
  18.  
  19. }
  20.  
  21.  
  22. private function onMouseOver(event:MouseEvent):void {
  23. _fontPreview = new BorderContainer();
  24. var Img:Image = new Image();
  25. Img.addEventListener(Event.COMPLETE, fontPreview_complete);
  26.  
  27. Img.load(FlexGlobals.topLevelApplication.url.substring(0,FlexGlobals.topLevelApplication.url.lastIndexOf("/"))+"/"+data.@preview.toString());
  28. _fontPreview.addElement(Img);
  29. _fontPreview.setStyle("cornerRadius", 5);
  30. _fontPreview.width = 140;
  31. _fontPreview.height = 40;
  32. var p:Point = new Point(this.width+5, - 15);
  33. p = this.localToGlobal(p);
  34. _fontPreview.x = p.x;
  35. _fontPreview.y = p.y;
  36. PopUpManager.addPopUp(_fontPreview , this, false);
  37. }
  38. private function onMouseOut(event:MouseEvent):void {
  39. PopUpManager.removePopUp(_fontPreview);
  40. _fontPreview = null;
  41. }
  42. ]]>
  43. </fx:Script>
  44.  
  45. <s:Label text="{data.@name}" mouseOver="onMouseOver(event)" mouseOut="onMouseOut(event)"/>
  46. </s:ItemRenderer>

the actionscript:
  1. private function fontFamilyChange():void {
  2. var fontList:Array = Font.enumerateFonts(false);
  3. var fontFound:Boolean = false;
  4. for (var i:uint=0; i<fontList.length; i++) {
  5. if(fontList[i].fontName == (this._fontChooser.selectedItem as XML).@name.toString()) {
  6. fontFound = true;
  7. }
  8. }
  9. if(fontFound) {
  10. item.setStyle("fontFamily", (this._fontChooser.selectedItem as XML).@name);
  11. }
  12. else {
  13. var path:String = (this._fontChooser.selectedItem as XML).@source;
  14. var myEvent:IEventDispatcher = styleManager.loadStyleDeclarations(FlexGlobals.topLevelApplication.url.substring(0,FlexGlobals.topLevelApplication.url.lastIndexOf("/"))+"/"+path);
  15. myEvent.addEventListener(StyleEvent.COMPLETE, fontLoaded);
  16. }
  17.  
  18. }
  19. private function fontLoaded(event:StyleEvent):void{
  20. item.setStyle("fontFamily", (this._fontChooser.selectedItem as XML).@name);
  21. }

And I guess as one final thing that would be good to show is some of the example xml I use for font loading:

  1. <fonts>
  2. <font name="Anonymous Pro" source="assets/fonts/AnonymousPro.swf" preview="assets/fonts/AnonymousPro.png" />
  3. <font name="ActionMan" source="assets/fonts/ActionMan.swf" preview="assets/fonts/ActionMan.png" />
  4. <font name="Blackout" source="assets/fonts/Blackout.swf" preview="assets/fonts/Blackout.png" />
  5. <font name="Candela" source="assets/fonts/Candela.swf" preview="assets/fonts/Candela.png" />
  6. <font name="Deja Vu" source="assets/fonts/DejaVu.swf" preview="assets/fonts/DejaVu.png" />
  7. <font name="Latin Mono" source="assets/fonts/LatinMono.swf" preview="assets/fonts/Latin.png" />
  8. <font name="Impact" source="assets/fonts/Impact.swf" preview="assets/fonts/Impact.png" />
  9. <font name="Plasma Drip" source="assets/fonts/PlasmaDrip.swf" preview="assets/fonts/Plasma.png" />
  10. <font name="PineWood" source="assets/fonts/PineWood.swf" preview="assets/fonts/PineWood.png" />
  11. </fonts>

One important thing to note is that name must match the fontFamily name you gave the font in the precompiled css file, otherwise the stylemanger won't have a clue what font you are talking about.

Trackback URL for this post:

http://softwarebyrichard.com/trackback/118
AttachmentSize
compilecss.png4.94 KB
Your rating: None Average: 3.2 (125 votes)