views:

406

answers:

2

Hi guys, I'm trying to write my own floodfill function in ActionScript3, because the one provided by Adobe isn't flexible enough (you can only give one target color, I would like to give a range of target colours.)

So, the terrible code I came up with so far is this:

private function beginAlgortime(xx:int,yy:int):void
{
    if (bmp.bitmapData.getPixel(xx, yy) != 0x333333) {

        bmp.bitmapData.setPixel(xx, yy, 0x333333);

        beginAlgortime(xx + 1, yy);
        beginAlgortime(xx + 1, yy+1);
        beginAlgortime(xx + 1, yy - 1);

        beginAlgortime(xx , yy+1);
        beginAlgortime(xx , yy - 1);

        beginAlgortime(xx - 1, yy);
        beginAlgortime(xx - 1, yy+1);
        beginAlgortime(xx - 1, yy-1);
    }
}

a pretty basic recursive function.. But obviously using this method, flash player craps out on me :) Anyone got a solution for this ? cheers!

+2  A: 

there's no need to recurse to diagonals directly, because the vertical and horizontal recursion will hit those pixels anyway.

what exactly do you mean by floodfill? and what do you mean by "range of colors"?

the routine you provided will fill the whole bitmap with 0x333333. and it won't terminate, since you never check whether you leave the bitmaps bounds.

greetz

back2dos

back2dos
yes. @Jaaq Have a look over the algorithms here http://www.cs.nps.navy.mil/people/faculty/capps/iap/class1/fill/fill.html Boundary fill will result in a stackoverflow (got about 3/4 of filling an image before it happened)
Allan
I found a nice solution for floodFilling:http://www.multimediacollege.be/2010/04/optimizing-the-floodfill-method/
Jaaq
A: 

You could try converting it from a recursive function to an iterative function that uses an array instead of the program stack.

Here's an iterative implementation of FloodFill as described in the article Allan mentioned:

function floodFill(bmpData:BitmapData, startX:int, startY:int, fill:uint, old:uint):void
{
    var queue:Array = new Array();

    queue.push(new Point(startX, startY));

    var iterations:uint = 0;
    var bmpWidth:int = bmpData.width;
    var bmpHeight:int = bmpData.height;

    var searchBmp:BitmapData = new BitmapData(bmpData.width, bmpData.height);
    var currPoint:Point, newPoint:Point;
    while (queue.length > 0)
    {
        currPoint = queue.shift();
        ++iterations;

        if (currPoint.x < 0 || currPoint.x >= bmpWidth) continue;
        if (currPoint.y < 0 || currPoint.y >= bmpHeight) continue;

        searchBmp.setPixel(currPoint.x, currPoint.y, 0x00);

        if (bmpData.getPixel(currPoint.x, currPoint.y) == old)
        {
            bmpData.setPixel(currPoint.x, currPoint.y, fill);

            if (searchBmp.getPixel(currPoint.x + 1, currPoint.y) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x + 1, currPoint.y));
            }
            if (searchBmp.getPixel(currPoint.x, currPoint.y + 1) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x, currPoint.y + 1));
            }
            if (searchBmp.getPixel(currPoint.x - 1, currPoint.y) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x - 1, currPoint.y));
            }
            if (searchBmp.getPixel(currPoint.x, currPoint.y - 1) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x, currPoint.y - 1));
            }
        }

    }       
    trace("iterations: " + iterations);
}

Edit: After trying a couple of ways to keep track of which pixels have already been searched, I realized that using a second BitmapData instance works really well. I've updated the code accordingly.

This code fills a 2000x1400 bitmap in ~14 seconds on my computer. For a better user experience, you should break up the fill processing over multiple frames, so the user doesn't have to stare at a waiting icon.

Oh, and this still only affects one color, but it should be easy to modify it to take multiple colors, or a color threshold, or similar.

Edit to add: The Flood fill article on Wikipedia has several algorithm suggestions.

Selene