Extracting font glyphs from SWF and Drawing with them

UPDATE: please use newer and improved version at http://wu-media.com/2009/05/extracting-vector-from-swfs-writing-and-now-drawing-with-them/

Drawing text in flash using font glyph information is definitely not new. five3D does it, PV3D uses the five3D files to do it. and Michael Baczynski also did it.

So what’s so different with my approach?

I extract the font glyphs from your SWFs, so you don’t need to go through the extra step of creating a Class that has a bunch of arrays describing your font. You can now embed fonts just as you normally would, and the best part is… you can use the same fonts with regular TextFields which lowers your overall file size.

SWF files store fonts as a bunch of ShapeRecords the same way it does with graphics youd draw on the Stage in the Flash IDE. These ShapeRecords are composed of a bunched of lineTo, moveTo, curveTo and styles instructions. For fonts we only need the first three. since we’ll be doing they styling in code when we’re about to draw text our text.

Now that we’ve extracted these ShapeRecords. I’ve created a DynamicText class that draws on a Graphics target. This target can be

  1. the graphics property of a DisplayObject
  2. the graphics3D property of a Shape3D in five3D
  3. the graphics property of a VectorShape3D in PV3D

Sample code:

1
2
3
4
5
6
7
// extract font information from swf bytes
DynamicText.extractFontInformation(root.loaderInfo.bytes, true);
// set the style
graphics.beginGradientFill(GradientType.LINEAR, [0xff4400, 0x0], [1, 1], [0x00, 0xff], m);
// draw the ext
DynamicText.write(graphics, "Futura Md BT", 20, 20, 0, "Hello World");
graphics.endFill();

Flash DisplayObject.graphics draw sample:

Get Adobe Flash player


Noticed the gradient fill? because we’re using the flash drawing API, we can use beginFill, beginBitmapFill and beginGradientFill when drawing to a DisplayObject.

The DynamicText class has the following features,

  1. Kerning and Leading that use the same values as photoshop which makes it easier to match text styles to comps
  2. TextBlock alignment of TL, T, TR, L, C, R, BL, B, and BR. TLC, LC and BLC provides centering of the text within the text block
  3. Ability to align the text either using it’s baseline or it’s top or bottom edges. baseline alignment provides more accurate alignment, as the text starts from it’s baseline which also happens to be its zero point.

The same code can be use to draw on five3D and PV3D!

five3D Shape3D.graphics3D draw sample:

Get Adobe Flash player

PV3D VectorShape3D.graphics draw sample:

Get Adobe Flash player

Currently, It only works with fonts that were transcoded with the flash IDE. you can still embed the fonts with the [Embed] tag, as long as it’s from a SWF that was published with the flash IDE. embedding TTF directly with the [Embed] tags breaks my parser for some reason.

Source code: Download

Tags: , ,

21 Responses to “Extracting font glyphs from SWF and Drawing with them”

  1. Great work! Anything that makes vector based fonts easier to use in 3D is incredibly helpful. Now how about extruding vector text. Thanks for the great work.

  2. Mem's says:

    I have already made the same a while, but only extract some fonts informations in logs :
    http://memmie.lenglet.name/documents/lab/cadratin/index.html

    But yours is relay more complete :p

  3. aYo says:

    This is brilliant. Nice work

  4. admin says:

    Mem’s

    You were 80% there :)

  5. Terry Corbet says:

    I am using your api in my project in a mode in which there will typically be several Fonts registered concurrently. Thus, based on user interaction, I have a need to get the correct SWFDefineFont upon which to operate. There are probably other use cases where the same logic will be required.

    After adding a private var _flags:uint and getting its value set,. these four getter methods seem to be working properly, and do simplify the ‘matching’ against Font.fontStyle:

    public function get isRegular():Boolean { return ((_flags & 0×06) == 0); }
    public function get isBold():Boolean { return ((_flags & 0×06) == 2); }
    public function get isItalic():Boolean { return ((_flags & 0×06) == 4); }
    public function get isBoldItalic():Boolean { return ((_flags & 0×06) == 6); }

    They are written using the style of the rest of the code, so maybe you will want to add them to your source.

  6. admin says:

    thanks. i’ll add those later today :)

  7. Terry Corbet says:

    When you add them, I imagine you will find my error! After further testing, it seems that the SWF document to which you provide the link is either out of date or just plain wrong with regards to which Flag bits are actually assigned to Italic and Bold. I wrote the code relying on the document’s table saying that information should be in bits 5 and 6, but when I tested, I did not get the correct results. Then, in your commented out code, I noticed that you were testing for Wide in bit 5, while the document would lead you to believe that that information should be in bit 7!

    Evidently you either have a more up-to-date source of information, or you just kept trying combinations as I did until I found that, indeed, Italic and Bold are encoded using bits 6 and 7 respectively. So, at least for me, the actual modification that works is:

    // Based on Wide being at 4 rather than 1 as tested above for kerning.
    public function get isRegular():Boolean { return ((_flags & 0×03) == 0); }
    public function get isBold():Boolean { return ((_flags & 0×03) == 1); }
    public function get isItalic():Boolean { return ((_flags & 0×03) == 2); }
    public function get isBoldItalic():Boolean { return ((_flags & 0×03) == 3); }
    // public function get flag():uint { return (_flags); }

  8. admin says:

    I had actually forgotten to add the properties :)

    I went added and added these

    1
    2
    3
    4
    
    public function get isBold():Boolean { return (_flags & 0x01) != 0; }
    public function get isItalic():Boolean { return (_flags & 0x02) != 0; }
    public function get isBoldItalic():Boolean { return isBold && isItalic; }
    public function get isRegular():Boolean { return !isBold && !isItalic; }

    also, I’m pretty sure we’re looking at the same documentation.

    7. UB[1] Has font metrics/layout information.
    6. UB[1] ShiftJIS encoding.
    5. UB[1] SWF 7 or later: Font is small. Character glyphs are aligned on pixel boundaries for dynamic and input text.
    4. UB[1] ANSI encoding.
    3. UB[1] If 1, uses 32 bit offsets.
    2. UB[1] If 1, font uses 16-bit codes; otherwise font uses 8 bit codes.
    1. UB[1] Italic Font.
    0. UB[1] Bold Font.

    so Bold should be _flags & 0×01 and italic should be _flags & 0×02. I didn’t test these. I’m just assuming is right. let me know if you find it to be flawed.

  9. [...] надежде найти уже готовое решение, обратился к гуглу. Гугл как всегда радует Тут решен вопрос и для graphics, и для graphics3D (Five3d), и для [...]

  10. [...] источник – wu-media lab (Guojian Miguel Wu) использует несколько иной подход. Источником контуров служит загружаемая свфка(swf) в [...]

  11. sakri says:

    Very impressive! Thanks for sharing the code!

  12. Very nice blog, your article is interesting, i have bookmarked it for future referrence

  13. vivoices says:

    I am using VectorText.extractFont( . . . in Away3D in a Flash Builder4 Beta 2 project.

    Would it be possible to extract fonts that are already embedded in the same swf file ( the FB4 output file ) instead of loading a swf for font extraction?
    It would be more memory and load-time efficient to use the same embedded fonts for both regular and 3D text.

  14. admin says:

    VectorText.extractFont takes any ByteArray including the that of the current swf.

    VectorText.extractFont(root.loaderInfo.bytes);

  15. [...] как-то стало неловко и я пошел искать как это делатся) Нашел Тут решен вопрос и для graphics, и для graphics3D (Five3d), Papervision3d [...]

  16. sergey says:

    exelent but doesn’t works with cyrilic

    got this problem:

    TypeError: Error #1010: … terms are not inited or has null value
    at wumedia.text::DynamicText$/measureLines()
    at wumedia.text::DynamicText$/write()
    at TestFive3D/init()
    at TestFive3D()

  17. That is the fitting blog for anyone who needs to seek out out about this topic. You realize so much its nearly laborious to argue with you (not that I actually would need…HaHa). You positively put a new spin on a subject thats been written about for years. Great stuff, simply great!

  18. Hallo daar, ik hou van uw blog. Is er iets wat ik kan doen om updates, zoals een abonnement of een of ander ding te ontvangen? Het spijt me ik ben niet bekend met RSS?

  19. Ayanna says:

    A better magazine theme would make the blog nicer.:)

  20. Keira Bahar says:

    I wish to voice my respect for your kind-heartedness in support of men who absolutely need help with this important idea. Your very own commitment to passing the solution up and down has been unbelievably practical and has continuously enabled others like me to achieve their pursuits. Your personal helpful information signifies a whole lot a person like me and even more to my office workers. Thank you; from everyone of us.