Extracting vector from SWFs, writing and now drawing with them
******************** Update: ********************
There’s now a google project for this: code.google.com/p/swfvector. I’m going to be updating this so there might be some changes to the how the whole thing works.
I had a lot of positive feedback for my last project that lets you extract font glyphs out of a swf and write text using the flash drawing API or one of the popular 3D engines.
Now, this update fixes a couple of bugs and also adds support for any vector shape on the stage or the library.
Demo:
The syntax is very similar to the the old DynamicText class. The main difference is that for Text, you need to define a fill type and for vectors, the fill type is ignored because vector shapes have their own fill types.
for Vector Shapes
1 2 3 4 | // extract shape from swf VectorShapes.extractFromLibrary(_loader.data, ["woman", "snowman"], VectorShapes.METHOD_CONTINUOUS_POINTS); // draw shape VectorShapes.draw(graphics, "woman"); |
for Vector Text
1 2 3 4 5 | // extract font data from swf VectorText.extractFont(root.loaderInfo.bytes); // draw text graphics.beginFill(0x0000); VectorText.write(graphics, "_Arial", 16, 16, 0, "Hello World", 10, 10); |
IMPORTANT
There are two methods to parse and draw vectors. METHOD_CONTINUOUS_POINTS & METHOD_REGULAR.
METHOD_CONTINUOUS_POINTS (the default method) parses shapes while trying to keep the points continuous. This is the best way but it does not support flat shapes (more on that later)
METHOD_REGULAR parses the data as it is saved in the swf. This supports all vector shapes but is slower in both parsing and rendering.
For best performance and to get data that is easier to work with. Use METHOD_CONTINUOUS_POINTS , but your vector shapes must not be flat. What do I mean by flat? Flat is when you collapse everything into one layer in flash and keep hitting CTRL+B until all groups are killed and everything is merged. The flash then saves this in a very compact way which makes it difficult to break out (more on that later), Anyway, this flatten shape takes a lot more passes to render and it also create a data set that is not that friendly to work with.
The best way to create your vector data is to have each individual shape grouped so that they don’t cut into each other. In the included source, the snowman symbol is the right way and the circles symbol is the wrong way.
ok. more,
This is straight out of the SWF file specs:
“Most vector formats allow only one fill and line style per path. The SWF file format extends
this concept by allowing each edge to have its own line and fill style. This can have
unpredictable results when fill styles change in the middle of a path.”
This is why i have two methods to parse the data. METHOD_CONTINUOUS_POINTS actually does it wrong, because it ignores the two fill style per edge thing. two fills per edges is never used if the shapes don’t intersect. So even though METHOD_CONTINUOUS_POINTS is wrong, it is the preferred and default method.
Another thing worth mentioning is that the flash drawing API DOES NOT support two fill per edge. instead flash saves the shapes as triangles with one common point, I’m using 0,0. It then draws these triangles erasing it’s 0,0 tail by drawing over it again. that’s the short version anyway, the whole version is a lot more complicated and i’m too lazy to go into it.
Source code: code.google.com/p/swfvector
Tags: ActionScript, ByteArray, PV3D

June 27th, 2009 at 2:42 pm
Wow!
Have been looking for ever since I started to mess with as graphics…!
A question:
Replacing the test example fonts to a normal text font works fine (for example replacing the Font1.as systemFont from “Verdana” to “Times New Roman”).
When replacing the font name with some graphic bullet font, for example “Wingdings” or “Webdings”, the output is blank.
Any clue?
Keep up the good work! / Jonas
June 28th, 2009 at 8:49 am
Jonas,
The best way to embed a font is to use the Flash IDE, I added an example called TestLoadFonts in the test package.
The flash IDE font transcoder supports more font types than the Flex SDK. I only used the Flex SDK for the samples because it was something i could do fast, but I normally use the flash IDE to embed the fonts. This would be the best method.
1. create dynamic text fields on the timeline and embed the font ranges via the properties panel
2. export as a swf
3. create a class that extends flash.text.Font like this
package ogilvy.website.fonts {
import flash.text.Font;
[Embed(fontName="DIN-Bold", source="../../../../lib/fontsForFlexSDK.swf", mimeType="application/x-shockwave-flash")]
public class DINBold extends Font {
public function DINBold() {
}
}
}
4. The in your flash project, you can use Font.registerFont(DINBold); to embed your fonts
June 29th, 2009 at 3:54 pm
Ok, I see.. Thanks!
Just wonder why Adobe are bullying us like this?
Regards!
J
July 24th, 2009 at 6:32 am
Hi there,
Impressive work!
I’m trying to use the parser tu draw vector text letter by letter (so I can play at a letter level instead of having a block), but I can’t find a way to get it properly, I miss the spaces and widths/heights of each letter, is there a way to get it back from the parsed font? quite something like it was done in Five3D with a dictionary or something?
Bests.
G.
July 24th, 2009 at 10:33 am
VectorText.getFontDefinition(”FONT NAME”).advances
will return an object containing the “widths” of characters. (it’s actually more than the width, it’s the width + padding before the next character.
for example
var charWidth:Number = VectorText.getFontDefinition(”Arial”).advances["A"];
will get the the width for the character “A”
July 25th, 2009 at 8:37 am
That’s what I figured after posting my question and messing with the classes ^_^
thank you!
G.
August 19th, 2009 at 4:01 am
If its possible to read the fonts in flash.text.Font; I think it will be more flexible if it can read the fonts by Font.enumerateFonts()[i]
November 11th, 2009 at 10:32 am
Hey,
On the googlecode site it is appearently not possible to get the source code or download the project. Is this an error or did you not get around to uploading it yet?
November 11th, 2009 at 10:43 am
Rasmus,
you need an svn client to download the source code. you can find the repository url in the “Source” tab.
November 28th, 2009 at 10:14 am
I was playing around with this code and works nicely, but did come across a bug.
In ShapeRecord.as line 83 should be this
_hasStateNewStyle = _tagType == TagTypes.DEFINE_SHAPE2
|| _tagType == TagTypes.DEFINE_SHAPE3
|| _tagType == TagTypes.DEFINE_SHAPE4;
I had a couple of objects which were Shape4 Type and were not showing up correctly. This fixed sorted it.
But nice code.
December 1st, 2009 at 4:52 pm
Phil,
I made the change to the code. thanks
February 3rd, 2010 at 9:04 pm
This is an excellent work! Congratulations!
I was wondering if you could help me with one thing: I see the library does not yet handle line shapes - I got it working all right with filled shapes, but it just seems to be ignoring line drawings.
I’ve been fiddling around with the code and downloaded the swf specification from Adobe, but it would be great if you could point me in the right direction to get it working for shapes with no fills as well.
I guess it shouldn’t be too difficult, since the drawing commands should be the same in both cases, but now the ShapeRecord for that sort of library items seems to be empty.
Thanks a lot.
February 8th, 2010 at 6:56 am
Leonardo,
Drawing lines has to be done on a separate pass. I decided not to implement it because it was too slow.
Basically you need to create a new array of points (during parsing) and push only those that contain stroke information. Then sort the array to make sure they are in the right order.
March 11th, 2010 at 8:38 pm
Have you considered updating this library for Flash 10?
Doing the actual VectorText.write() takes about as much time as the flash player takes to do the actual rendering.
I’m guessing that if you used the Flash 10 GraphicsPath object for storing the ShapeRecord, instead of the list of Edge classes, it will be much more efficient to transform it during write().
This is because the ShapeRecord has only two vectors — the command and data. The command has the drawTo, curveTo, and moveTo information. This never gets transformed. The data contains a continuous list of x,y co-ordinates, in a Vector.. It is an easy job to iterate over the whole data vector with a scale and offset (and rotation if need be).
Doing this would also greatly reduce the number of objects within the ShapeRecord. The Arial ASCII glyphs that I checked did not use any Fill objects. Therefore the ShapeRecord could consist of only two fields — the bounds, and GraphicsPath for most cases. Only in strange cases would there be an interleaved array of FillStyle and GraphicsPath.
What do you think?