One thing that seems particularly easy to do in the Flash IDE but difficult to do with code is to outline an organic shape. In the IDE you can just use the inkbucket tool to draw a stroke around something. Using nothing but code it seems much trickier. One method I’ve seen is to add a glow filter to the shape in question and just mess with the strength. But what if i want to only show the outline?
What I’d like to do is to collect all of the points that make up the edge of the shape and then just connect the dots. I’ve actually gotten so far as to collect all of the points with a quick and dirty edge detection script that I wrote. So now I have a Vector of all the points that makeup my shape. How do I connect them in the proper sequence so it actually looks like the original object?
For anyone who is interested here is my edge detection script:
// Create a new sprite which we'll use for our outline
var sp:Sprite = new Sprite();
var radius:int = 50;
sp.graphics.beginFill(0x00FF00, 1);
sp.graphics.drawCircle(0, 0, radius);
sp.graphics.endFill();
sp.x = stage.stageWidth / 2;
sp.y = stage.stageHeight / 2;
// Create a bitmap data object to draw our vector data
var bmd:BitmapData = new BitmapData(sp.width, sp.height, true, 0);
// Use a transform matrix to translate the drawn clip so that none of its
// pixels reside in negative space. The draw method will only draw starting
// at 0,0
var mat:Matrix = new Matrix(1, 0, 0, 1, radius, radius);
bmd.draw(sp, mat);
// Pass the bitmap data to an actual bitmap
var bmp:Bitmap = new Bitmap(bmd);
// Add the bitmap to the stage
addChild(bmp);
// Grab all of the pixel data from the bitmap data object
var pixels:Vector.<uint> = bmd.getVector(bmd.rect);
// Setup a vector to hold our stroke points
var points:Vector.<Point> = new Vector.<Point>;
// Loop through all of the pixels of the bitmap data object and
// create a point instance for each pixel location that isn't
// transparent.
var l:int = pixels.length;
for(var i:int = 0; i < l; ++i)
{
// Check to see if the pixel is transparent
if(pixels[i] != 0)
{
var pt:Point;
// Check to see if the pixel is on the first or last
// row. We'll grab everything from these rows to close the outline
if(i <= bmp.width || i >= (bmp.width * bmp.height) - bmp.width)
{
pt = new Point();
pt.x = int(i % bmp.width);
pt.y = int(i / bmp.width);
points.push(pt);
continue;
}
// Check to see if the current pixel is on either extreme edge
if(int(i % bmp.width) == 0 || int(i % bmp.width) == bmp.width - 1)
{
pt = new Point();
pt.x = int(i % bmp.width);
pt.y = int(i / bmp.width);
points.push(pt);
continue;
}
// Check to see if the previous or next pixel are transparent,
// if so save the current one.
if(i > 0 && i < bmp.width * bmp.height)
{
if(pixels[i - 1] == 0 || pixels[i + 1] == 0)
{
pt = new Point();
pt.x = int(i % bmp.width);
pt.y = int(i / bmp.width);
points.push(pt);
}
}
}
}
Currently it’s not possible to introspect the shape of something you drew at design time (i.e. to find out where the corners of all the lines and fills are), so the only good way to draw an outline around an arbitrary shape is as a bitmap effect. However, the way you’re going about it is probably not going to be fruitful. Flash gives you a couple of ways to process bitmaps, but anything that involves looping over every pixel usually doesn’t wind up being fast enough to use at runtime.
Rather, I’d take one of two approaches: the best and easiest will be to use the built-in filters. As you say, usually when people want to draw an outline, they use a glow filter with a large strength and a short radius. If you want to show only the outline, check the
knockoutproperty. (You can do this in script or in the IDE.) If you don’t like what you’re getting with this, you might try mixing filters – say, adding in a blur before or after the glow. Or you can use code to generate the glow effect into a blank bitmap, and then you can process the result in various ways – for example, withBitmapData.threshold, which I’ve found is very powerful. Anyway, I’d play with this a while, and make sure it’s really not going to solve your problem before you try something else, because it’s by far the easiest solution.The other option is PixelBender. This is a feature that lets you define a custom filter in a C-like language, which you pre-compile and then load into your Flash movie, and apply to the bitmap in question. The process is very similar to programming a photoshop filter. This gives you total control over what kind of processing you want to do to the bitmap, but it requires you to work outside Flash and outside actionscript.
Going your current route and manually processing the pixels is of course a third option, but the question is whether you’re really doing anything you couldn’t do in a normal or a custom filter. If you really want to finish up what you have going, you might try making a new transparent bitmap, and for every point you captured in the code above, draw a white dot (with setPixel32) at that point. That would give you a pixelated outline, which you’d probably then want to blur, or otherwise process. But really, you’re going to wind up with something very similar to what you might have gotten with a normal glow filter, and it will take a lot longer.