使HTML5 canvas floodfill高效

时间:2013-06-26 19:32:58

标签: javascript performance algorithm html5-canvas flood-fill

我正在使用socket.io和canvas创建一个协作图像绘制应用程序。必要时,画布必须经常刷新,目前大约每50毫秒刷新一次。我想在应用程序中添加填充工具,因此我使用了有限的洪水填充知识来创建填充工具。因为必须传输所有这些数据,所以我将每个填充命令存储为一个简单的对象

{
    tool: 'fill',
    coordinate: {
        x: 5,
        y: 5
    }
    fillcolor: '#000'
}

然后每个客户端的画布运行算法并使用“getImageData”和“putImageData”填充每个单独的像素。这是我的实现的(缩写)版本。

function floodfill (start,target_color,fill_color)
{
    var pixelStack = [start]; //the stack of pixels to check

    while (pixelStack.length > 0) 
    {
        var current = pixelStack[pixelStack.length-1]; //check the last pixel of the pixelstack
        pixelStack.pop(); //delete current from stack

        if (isSameColor(current)) //matches our target color
        {
            var mydat = ctx.createImageData(1,1);
            mydat.data = new Array();
            mydat.data[0] = hexToRGB(fill_color).r; //red
            mydat.data[1] = hexToRGB(fill_color).g; //green
            mydat.data[2] = hexToRGB(fill_color).b; //blue
            mydat.data[3] = 255;
            ctx.putImageData(mydat,current.x,current.y);

            pixelStack.push(bit(current.x+1,current.y)); //right
            pixelStack.push(bit(current.x-1,current.y)); //left
            pixelStack.push(bit(current.x,current.y+1)); //up
            pixelStack.push(bit(current.x,current.y-1)); //down
        }
    }

    function isSameColor (pixel)
    {
        var imgdat = ctx.getImageData(pixel.x,pixel.y,1,1).data;
        if (imgdat[0]== hexToRGB(target_color).r && imgdat[1]== hexToRGB(target_color).g, imgdat[2]== hexToRGB(target_color).b)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    function hexToRGB (hex)
    {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16),
            rgb: parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16)
        } : null;
    }
}

不幸的是,一旦算法运行,画布绘图就会非常慢。由于我有所有绘画的鼠标坐标细节,我考虑尝试使用矢量来填充它,但我的数学背景并不足以在没有帮助的情况下完成它。

我申请的缓慢部分是什么?我该如何解决?

编辑:正如我在评论中提到的,我尝试过只使用一个大的putImageData(非常慢),并使用createImageData而不是getImageData(稍微快一点)。

EDIT2:每个画笔笔划都存储为一系列x-y坐标,这些坐标在用户点击和拖动时记录。但是,它们不是封闭的路径。相反,它们被绘制为一系列线条,当用户抬起鼠标时,移动到。

更新代码以反映我当前的实施。

1 个答案:

答案 0 :(得分:2)

我意识到这是一个非常古老的问题,但是如果你还在努力解决这个问题,请暂时在函数的各个部分安排一些代码,以找到它最慢的位置。绝对将对getimagedata和putimagedata的调用拉出循环 - 每次“填充”只调用一次。获得imagedata后,通过它的底层缓冲区获取并设置像素的颜色,并将其视为Uint32Array。

请参阅 https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/