Skip navigation
Jo Klappenbach
Currently Being Moderated

How in the World can you embed Fonts?

Jul 21, 2009 6:28 AM

Dear ladies and gents,

 

we have just integrated textflow in rather larger Flex/Flash dynamic Framework. All is working out quite well, except for the embed fonts issue. We spend hours after hours trying to make it work ... no dice.


Could you pretty pretty please describe one more time the best practice to use dynamically loaded fonts with TLF?

 

a) the most practicle way of using dynamic fonts would be to load SWFs at runtime ... am I correct?

 

So we bought newest Flash CS4, hoping to have cff=true  Option with embedding fonts.

  [Embed(source='C:/WINDOWS/Fonts/Arial.ttf', fontName='_Arial',  cff='true')]
  public static var _Arial:Class;

 

--> does not work, Flash tells us: cff not supported by flex2.compiler.media.FontTranscoder'

 

What Flash CS4 has to do with Flex of any compilation escapes me, but you guys probably know, why you did it.

 

b) from lots of tipps in Forums I read, Installing Flex Gumbo might be of help. Tried that, too, including the new SDK (last stable build, then last nightly build) in Flex Compiler 3.2. But it is not the best solution, since Gumbo functions different in quite some ways and we would have to rewrite most of our framework, which we will not manage in short time.

c) we looked through most examples posted ages ago and they partly do not work with current stable and nightly builds any more, since too much has changed.

 

So - I would greatly appreciate your help, with a current and working example or approach of how to do it, since we have to deliver out the new solution and really, not being able to include any fonts at all with TLF is quite a dealbreaker for our customers.

 

See it as desperate cry for help after an incredible amount of frustrating head banging on the issue and wolfing through tons of "help" pages with having only humble abilities in understanding English language.

 
Replies
  • Currently Being Moderated
    Jul 21, 2009 8:50 AM   in reply to Jo Klappenbach

    Hi,

     

    Your concerns about using Flex Gumbo SDK may be addressed on the Flex forum.

     

    Assuming you are unable to use Flex Gumbo SDK for your entire project, you can still use it for font embedding.

     

    1. Create a separate Flex 4 project whose output is a Flash .swf file that embeds the fonts you need.

    2. Use the fonts .swf in a Flex 3 project

     

    These steps are outlined in this blog post: http://blogs.adobe.com/tlf/2008/11/

     

    For now, I would recommend using the Flex Gumbo SDK Beta1 build of a bug introduced in a later build.

     

    Hope this helps,

    Abhishek

     
    |
    Mark as:
  • Currently Being Moderated
    Jan 16, 2010 10:48 PM   in reply to Jo Klappenbach

    Thank u . I am a beginner pls send me th code in flex for loading fonts when loading page(I failed to get th font names from enumerateFont object)

     
    |
    Mark as:
  • Currently Being Moderated
    May 6, 2010 3:05 PM   in reply to Jo Klappenbach

    I, like Abhishekkollam, am still having issues.  I can load the swf containing the font but when I enumerate fonts it doesn't show up.  Here's my app code that loads in the font swf:

     

     

    protected var loader:Loader;
    protected function application1_creationCompleteHandler(event:FlexEvent):void
    {
         loader = new Loader();
         loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontLoadedHandler);
         var request:URLRequest = new URLRequest('http://aaronhardy.com/transfer/Fonter.swf');
         var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
         loader.load(request, loaderContext); 
    }
                   
    protected function fontLoadedHandler(event:Event=null):void
    {
         trace('----------');
         var fonts:Array = Font.enumerateFonts(false);
         trace(fonts); // empty array
         trace('----------');
         //editor.textFlow.flowComposer.swfContext = ISWFContext(editor.getContext('Verdana'));
         editor.textFlow.fontLookup = FontLookup.EMBEDDED_CFF;
         editor.textFlow.renderingMode = RenderingMode.CFF;
         editor.textFlow.fontFamily = 'Verdana';
         editor.textFlow.flowComposer.updateAllControllers();
    }
    

     

    Here's the code of the class containing the font:

     

    package
    {
         import flash.display.Sprite;
         import flash.system.Security;
         import flash.text.Font;
         
         public class Fonter extends Sprite
         {
              [Embed(
                   source="verdana.ttf", 
                   fontFamily="Verdana",
                   embedAsCFF="true"
              )]
              public const Verdana:Class;
              
              public function Fonter():void
              {
                   super();
                   Font.registerFont(Verdana);
                   var fonts:Array = Font.enumerateFonts(false);
                   trace(fonts) // This shows Verdana as a registered font
              }
         }
    }
    

     

    Ideas?  For the life of me I feel like I've tried everything and searched everywhere.

     

    Thanks.

     
    |
    Mark as:
  • Currently Being Moderated
    May 6, 2010 3:25 PM   in reply to Aaronius9er9er


    Here's a suggestion: Can you arrange to call Font.registerFont(Fonter.Verdana) in the parent swf instead of the child?  You'll have to reach into the child swf and get the definition using event.target.applicationDomain.getDefinition in your fontLoadedHandler.

     

    Richard

     
    |
    Mark as:
  • Currently Being Moderated
    May 6, 2010 3:35 PM   in reply to Jo Klappenbach

    I believe embedAsCff is the right tag.  cff is the old one.  At least that's true for Flex 4.

     

    Richard

     
    |
    Mark as:
  • Currently Being Moderated
    May 6, 2010 4:03 PM   in reply to rdermer

    Yes I tried that as well:

     

    var Fonter:Class = event.currentTarget.applicationDomain.getDefinition("Fonter") as Class;
    var VerdanaClass:Class = Fonter.Verdana;
    Font.registerFont(VerdanaClass);
    

     

    When it gets to Font.registerFont it says

     

    ArgumentError: Error #1508: The value specified for argument font is 
    invalid.
        at flash.text::Font$/registerFont()
        at TLFTester/fontLoadedHandler()[C:\Development\TLF\TLFTester\src\TLFTester.mxml:62]
    

     

    But it gets crazier.  So then I figure, well, how about I make my font class that I load in implement ISWFContext and pass that to flowComposer's swfContext property.  There's a great example at the bottom of this page:

     

    http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fla shx/textLayout/compose/ISWFContext.html

     

    So I make the font class implement ISWFContext and then in my app I have the following:

     

    var fonter:Object = loader.content;
    trace(describeType(fonter));
    trace(fonter is ISWFContext);
    editor.textFlow.flowComposer.swfContext = ISWFContext(fonter);
    

     

    On the describeType trace it shows:

     

    <type name="Fonter" base="flash.display::Sprite" isDynamic="false" isFinal="false" isStatic="false">
      <metadata name="__go_to_ctor_definition_help">
        <arg key="file" value="C:\Development\TLF\Fonter\src\Fonter.as"/>
        <arg key="pos" value="371"/>
      </metadata>
      <metadata name="__go_to_definition_help">
        <arg key="file" value="C:\Development\TLF\Fonter\src\Fonter.as"/>
        <arg key="pos" value="169"/>
      </metadata>
      <extendsClass type="flash.display::Sprite"/>
      <extendsClass type="flash.display::DisplayObjectContainer"/>
      <extendsClass type="flash.display::InteractiveObject"/>
      <extendsClass type="flash.display::DisplayObject"/>
      <extendsClass type="flash.events::EventDispatcher"/>
      <extendsClass type="Object"/>
      <implementsInterface type="flash.display::IBitmapDrawable"/>
      <implementsInterface type="flashx.textLayout.compose::ISWFContext"/>
      ...
    

     

    Notice it shows the class as implementing ISWFContext as planned.  But on the next line I trace whether fonter is ISWFContext and it reports false.  On the next line where I attempt to cast it to ISWFContext I get the following error:

     

    TypeError: Error #1034: Type Coercion failed: cannot convert Fonter@a32ce81 to flashx.textLayout.compose.ISWFContext.
         at TLFTester/fontLoadedHandler()[C:\Development\TLF\TLFTester\src\TLFTester.mxml:70]
    

     

    I'm going crazy over here.  The app is built using the flex 3.3 sdk.  The font swf is built using the flex 4 sdk.  The textLayout.swc should be the same (I pulled the textLayout.swc from the flex 4 sdk to use in our flex 3.3 app).

     

    Any other ideas?

     
    |
    Mark as:
  • Currently Being Moderated
    May 6, 2010 4:44 PM   in reply to Aaronius9er9er

    BTW, does Adobe offer some type of official support?  We'd gladly pay some sort of consulting rate as this is a large, expensive project and these types of quirks are holding us back.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 6:27 AM   in reply to Jo Klappenbach

    Ah, this issue creeping up, yet again.

     

    • First, you need to compile your application with the Flex 4 SDK. ISWFContext is not part of SDK 3.3 and was added AFTER the beta 2 release of Flash Builder 4 (final release build unless you are keeping track of the nightlies).
    • You are going to have issues using the TLF framework with Flex 3.3 because the TLF released with the final build of Flash Builder 4 introduces the ISWFContext and the issues around this. To circumvent this, use the TLF build that was released with Flash Builder 4 beta 2, around November of 2009.
    • Second, there is a bug in the framework. Fonts are not properly dealt with in the final Flex 4 SDK.
    • ISWFContext should ONLY be necessary if you do not intend to register the font yourself. The only reason to use ISWFContext is if you are loading, at runtime, the SWF file through Flex and not calling Font.registerFont(). Consider this another bug in the framework
    • If you are using Font.registerFont, you will need to override the GlobalSettings lookup to determine whether or not the font is an embedded font or a dynamic font. This is a hack, at best, because it shouldn't matter because in this case, you are registering the font yourself and you shouldn't need to add it to the registry within the Flex framework. It should just work.
    • GlobalSettings.resolveFontLookup was introduced after FB4 beta 2 so, again, you will need to build against Flex 4 release for this to all work (and it does work but it's still somewhat busted).


    Unfortunately, there is no publically avialable best practice that I've seen to deal with runtime font loading if you are registering the font yourself. Some links below that may help with this issue:

     

    My original post on the topic:

    http://forums.adobe.com/message/2753744#2753744

     

    Another post regarding this:

    http://forums.adobe.com/message/2672002

     

    A reasoning and a potential workaround (if you are using Font.registerFont yourself this is not applicable)

    http://marcel-panse.blogspot.com/2010/03/embedded-fonts-in-tlf-and-swf contexts.html

     

    The related bug in the framework:

    http://bugs.adobe.com/jira/browse/SDK-26187

     

     

    It's pretty maddening if you ask me. While I appreciate Adobe opening this up to the community SDK, it's still a broken issue. Registering fonts manually by yourself is a 100% valid approach to dealing with runtime loaded fonts. It's a native player feature and the Flex 4 SDK breaks this core feature.

     

    The combination of the GlobalSettings.resolveFontLookup override AND setting an ISWFContext (even if one is not even available) will allow for the fonts to work if you use mixed fonts in a spark RichEditableText area (a valid approach). You only need to set one of them - if you use 30 different fonts in the same text area, they'll all magically start working provided they are loaded from the same domain.

     

    Alternately, I've found another potential work around in that if you create a new instance of the font after it's been loaded (in your main.mxml or somewhere) such as myfont = new FontClassYouLoaded() then it will work.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 8:53 AM   in reply to bustback

    Jo, when I attempt to load your font swf (http://www.skycoversum.de/skyco9/test3/Fverdana.swf) I get the following runtime error:

     

    VerifyError: Error #1014: Class mx.core::FontAsset could not be found.

     

    Interestingly enough, I also get the same error when I browse directly to that address in a browser.

     

    ----------------

     

    bustback,

     

    Thanks for the details of the problems you ran into.  I figured I'd run into the same problem with dealing with multiple fonts and only being able to specify a single swf context.  I figured I'd get one working and then worry about getting it to work with multiple.  But, it looks it would be much simpler just to get Font.registerFont working.  So far it's failed me at every avenue.

     

    I've recreated my projects just to make sure I've narrowed down the scope.  I'm also building both the font library (the swf that gets loaded in) and the main app in Flex 3.3. I'm not even worrying about the text flow yet.  I just want to be able to load in a font swf, register the font, then enumerate the fonts and see it listed as an embedded font in the main app.

     

    When calling Font.registerFont(), I get the following error:

     

    ArgumentError: Error #1508: The value specified for argument font is invalid.
        at flash.text::Font$/registerFont()
        at FontApp/completeHandler()[C:\Development\TLF\FontApp\src\FontApp.mxml :24]

     

    Here's my code for the app:

     

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600"
                        creationComplete="application1_creationCompleteHandler(event)">
         <mx:Script>
              <![CDATA[
                   import mx.events.FlexEvent;
              
                   protected var loader:Loader;
                   
                   protected function application1_creationCompleteHandler(event:FlexEvent):void
                   {
                        loader = new Loader();
                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
                        var request:URLRequest = new URLRequest('http://aaronhardy.com/transfer/FontLib.swf');
                        var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
                        loader.load(request, loaderContext);
                   }
                   
                   protected function completeHandler(event:Event):void
                   {
                        var FontLib:Class = event.currentTarget.applicationDomain.getDefinition("FontLib") as Class;
                        var Arial:Class = FontLib.ARIAL_FONT;
                        Font.registerFont(Arial);
                        var fonts:Array = Font.enumerateFonts(false);
                        trace(fonts);               }
              ]]>
         </mx:Script>
    </mx:Application>

     

    and here's the code for the font library:

     

    package
    {
         import flash.display.Sprite;
         import flash.text.Font;
         
         public class FontLib extends Sprite
         {
              [Embed(
                   source="arial.ttf", 
                   fontFamily="Arial"
              )]
              public static const ARIAL_FONT:Class;
              
              public function FontLib()
              {
                   super();
              }
         }
    }
    

     


    I've tried both verdana and arial fonts that I've pulled from my C:\Windows\Fonts folder and it always throws the error.  Once I get this resolved I should be able to get started with the text flow integration.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 9:19 AM   in reply to Jo Klappenbach

    Jo, I see that yours is working, but mine isn't.  I don't know why.  I copy your code word for word and I still get the error when I run the app.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 9:21 AM   in reply to Aaronius9er9er

    Not sure why this is not working for you.


    Couple potential issues in your code:


    • Remove static from the class in the font file. Just use public const.
    • Try Font.registerFont(ARIAL_FONT) within the constructor instead


    Other than that, I've never had to deal with application domain and all that after the font has been loaded up... try event.target.loader.content within the complete handler to reference the loaded class.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 9:22 AM   in reply to Jo Klappenbach

    Jo, I've published my copy of your example app here: http://aaronhardy.com/transfer/ForumApp/ForumApp.html  You can right-click to view the source.

     
    |
    Mark as:
  • Currently Being Moderated
    May 7, 2010 9:32 AM   in reply to bustback

    Yeah, I've tried those variations.  Here's what I get:

     

    Using this code in the font lib:

     

    package
    {
         import flash.display.Sprite;
         import flash.text.Font;
         
         public class FontLib extends Sprite
         {
              [Embed(
                   source="arial.ttf", 
                   fontFamily="Arial"
              )]
              public const ARIAL_FONT:Class;
              
              public function FontLib()
              {
                   super();
                   Font.registerFont(ARIAL_FONT);
                   var fonts:Array = Font.enumerateFonts(false);
                   trace('from lib', fonts);
              }
         }
    }
    

     

    and this code in my main app:

     

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600"
                        creationComplete="application1_creationCompleteHandler(event)">
         <mx:Script>
              <![CDATA[
                   import mx.events.FlexEvent;
              
                   protected var loader:Loader;
                   
                   protected function application1_creationCompleteHandler(event:FlexEvent):void
                   {
                        loader = new Loader();
                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
                        var request:URLRequest = new URLRequest('http://aaronhardy.com/transfer/FontLib.swf');
                        new LoaderContext(true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain);
                        loader.load(request);
                   }
                   
                   protected function completeHandler(event:Event):void
                   {
                        //Font.registerFont(Object(loader.content).ARIAL_FONT);
                        //var FontLib:Class = event.currentTarget.applicationDomain.getDefinition("FontLib") as Class;
                        var fonts:Array = Font.enumerateFonts(false);
                        trace('from main', fonts);
                   }
              ]]>
         </mx:Script>
    </mx:Application>

     

    I get the following output:

     

    from lib [object Font],[object FontLib_ARIAL_FONT]
    from main
    

     

    Notice no embedded font in the main app.

     

    If I use the same code as above but use Font.registerFont(Object(loader.content).ARIAL_FONT); I still get the "The value specified for argument font is invalid." error.

     

    I really appreciate your followups.

     

    Aaron

     
    |
    Mark as:
  • Currently Being Moderated
    May 10, 2010 9:14 AM   in reply to Jo Klappenbach

    Thanks Jo for helping me off-list a bit.  I think I have this wrapped up and working sufficiently.

     

    First of all, I didn't end up using the ISWFContext stuff at all.

     

    Second, I still don't know why I'm getting the "VerifyError: Error #1014: Class mx.core::FontAsset could not be found." with your projects.  I continue to get that error regardless of the sdk I use and where I deploy the swfs.

     

    I figured since I got the "FontAsset could not be found" error both locally and remotely that I'd get "The value specified for argument font is invalid." error locally and remotely as well, but that's not true.  I would get the error when the font swf was on the remote server, the app loading the font swf was running locally (without an http server), AND trying to register the font from the main app.  If I didn't try to register the font from the main app but just tried registering it from the font swf itself, I wouldn't get an error, but the font wouldn't show up as a registered font in the main app, probably because it was being loaded into a different security domain.  In the end, it ended up working with just registering the font from the font swf--no need to register the font from the main app.

     

    I still think it's crazy that, when running the main app locally, I could load the remote font swf, instantiate the class, etc., but when I went to register the font I would get "The value specified for argument font is invalid."  Seems like a very general (misleading?) error for something quite specific.

     

    Thanks for your help!

     

    Aaron

     
    |
    Mark as:
  • Currently Being Moderated
    May 10, 2010 9:40 AM   in reply to Aaronius9er9er

    Just a thought.  You don't have to use mx.core.fontAsset to embed a font.  You can do it like this:

     

    import flash.text.Font;

     

    [Embed(mimeType="application/x-font", exportSymbol="myArial_medium_normal", embedAsCFF="true", source="arial.ttf", fontName="myArial")]
    public class myArial_medium_normal extends Font
    { }

     

    Looking back through the thread it seems like you've been down this path though.

     

    From what I've learned this is an issue of mixing Flex 3 and Flex 4.  No?

     

    Richard

     
    |
    Mark as:
  • Currently Being Moderated
    May 10, 2010 2:50 PM   in reply to Jo Klappenbach

    Hey.  Yeah, that enumeration was just for debugging purposes.  I'm good now.  I couldn't ever get your projects to work, but that's okay.  Mine works if I make sure I upload both the app swf and the font swf to a remote server (or if I load it in as binary and then load the binary into a swfloader).

     

    I really appreciate your willingness to help.  That's very commendable.  Thanks!

     

    Aaron

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points