Sel2Draw Information

Sel2Draw is a jsfl script that will take a selection in the Flash IDE and convert it to semi compressed data. This data can be used at runtime to display, distort and otherwise modify your original image (using a small built in engine that the jsfl command also creates).
Download sel2draw here - this includes the jsfl file as well as the installer if you like. The code is fairly commented so you might want to look at that too (also a reasonable reference for some nastier jsfl, though this is old by now). Sel2Draw was originally made for a Macromedia DevNet CD, but many people have asked for it so I'm posting it here -- hope this is ok.

AsDraw Information

AsDraw is the 'enhanced version' of sel2draw, and therefor probably less useful. It uses .Net rather than jsfl. To see what it does, you can paste this code into the Flash actionscript window, and you will get the graphic below. The data at the end of that file was generated with this tool.


AsDraw allows you to draw graphics using actionscript rather than embedding them in the swf. This gives you runtime control over the graphic data, something you don't normally have with swf. The swf below contains only actionscript that was generated from an swf graphic. The second copy is the same data after modifying the color table, and skewing the pixel data.

What is it? Where is it? Help!

AsDraw is actually three things. First it is a (somewhat) compressed data format for storing swf drawing data. This data can be written into actionscript directly, or loaded from the server, put in a shared object etc. Secondly, it is an engine that takes this data, parses it, and draws it into a movieclip. Thirdly, it is the companion program that can generate this data from various vector formats, including swf. This program can run standalone on the desktop (requires .Net), or it can run as a server side generator.

An early version (read- sucked interface!) can be found here (also requires the Adobe svg plugin, but as a bonus it can convert swf to svg!). Drag in an swf file, and then click AsDraw to generate the data.


// create one instance per data set
var asd = new AsDraw(dat);
// grab the image - you can optionally
// pass an existing mc into Image()

var mc1 = asd.Image();
// grab the cached image
var mc2 = asd.Image();
mc2._y = 100;
// change some data
asd.Colors[1]=[0x00FF00, 100];
// regenerate the image
var mc3 = asd.Regenerate();
mc3._y = 200;

For better directions, please look at these instructions (courtesy of Andreas Weber)

The Data

The drawing data is loaded into an AsDraw instance via it's constructor. The data is not immediately parsed. You can always access the current graphic data via the Image method. If the data hasn't been parsed, it will automatically happen then. The original data is then discarded, and the real data is loaded into four tables - Colors, Strokes, Paths, and Uses. If you modify these tables, you can Regenerate() the Image.

Fills and Strokes

Colors and Strokes are fairly straight forward - at each index an array is stored that exactly matches the parameters that the corresponding drawingAPI methods expect as parameters. So a solid color is [rgb,a], a stroke is [width, rgb, a], and a gradient is [fillType,colors[],alphas[],ratios[],matrix[abcdefghi]]. The drawing API does not support bitmap fills, though that might be simulatable down the road. Index zero of the color table always means 'no fill', and index zero of the stroke table always means 'no stroke' - regardless of what you put in there.


Paths are stored as edge segments. Because an swf shape is always flat (only groups, symbols or movieclips can overlap), it is only possible for a segment to be used three times - twice for filling (one color on each side), and once for stroking. So paths have been stored as the longest possible section in the graphic that doesn't change either fill, or the stroke. This way they only have to be stored once even if they are used three times. The other advantage is that if you move an edge, you don't have to worry about gaps - both sides of the fill will move together. These path 'sections' are all stored together in the Path table.

Each path section is made up of a series of moveTo, lineTo, and curveTo directives. These are stored in two separate arrays, a curve/line/move array that describes the command, and a second array of pixel data. The first arrays possible values are 0-curve, 1-line, 2-move. Every segment starts with a move (making it easier to relocate sections), which the engine will skip unless it actually changes the current location. While lines and moves can be described with an xy pair of pixels, a curve requires four pixels, so you have to keep track of the second location as you walk along the path section. This ends up being quite a bit quicker, and there are some benefits, such as every odd numbered index in the array will be an x value, and every even numbered index a y value. Thus you can make many node adjustments without having to know if the data belongs to a curve, line or move.


Lastly, there are Uses. These are what construct the actual data. Each Use is made up of three numbers, each an index into one of the other tables. The Uses table is an unbroken sequence of path, fill and stroke indexes, that looks like: [path, fill, stroke, path, fill, stroke, path...]. If the fill or stroke doesn't change, it is still listed, and the drawing engine just skips it. This allows moving uses around without having to worry about dependencies in preceding uses. It also means every third number will be the same type of information. If everyone really hates this, each use (and each path segment) can be parsed into their own arrays, with a small hit on speed - just let me know...

The Compressed Format

The compressed format is basically not very important, but for the curious... It is just an nBits type of compression, where you take the smallest number of bits required to represent a series of numbers, and then write that out as a long sequence, nBits at a time, across bytes. Unfortunately, the data must be stored in flash as 32 bits, which means every fifth byte will be a push marker. It is possible to use 8 bytes per push, but that will probably require bytecode. It is also possible to use strings, though that also requires bytecode, and is slower.

All path data is sent in twips (1/20th pixel), just as in swf, and converted to floats on arrival. Each series starts with a tag describing itself (argb defs, stroke defs etc), then five bits for the nbits (always add 2 to the arriving nBits value), and 11 bits for the count (the number of items in the series, max 2047). After this the data comes in bit chunks, nBits at a time, for 'count' items. This allows reasonably small files that uncompress reasonably fast, using a reasonably small engine. This format isn't compressed in any other way (for speed reasons), though if you put it in an swf file, you can compress that.

Obligatory Silly Example

var asd = new AsDraw(dat);
var mc = asd.Image();
// change colors
for(var i = 0; i < asd._colors.length; i++)
    if(asd._colors[i].length == 2)
        asd._colors[i][0] &= 0xFFFF3F;
        for(var j = 0; j < asd._colors[i][1].length; i++)
        asd._colors[i][1][j] /= 2;
//var mc2 = asd.Image();

// change points
for(var i = 0; i < asd._paths.length; i++)
    var pathdata = asd._paths[i][1];
    for(var j = 0; j < pathdata.length; j+=2)
        pathdata[j] -= pathdata[j+1]/3;
var mc3 = asd.Image();

More to Come

Timelines, movieclips, text