使 HTML5 画布填充高效

Posted

技术标签:

【中文标题】使 HTML5 画布填充高效【英文标题】:Making HTML5 canvas floodfill efficient 【发布时间】:2013-06-24 02:40:45 【问题描述】:

我正在使用 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;
    

不幸的是,一旦算法运行,画布绘制速度就会慢得离谱。由于我有所有绘画的鼠标坐标细节,我考虑尝试使用矢量来填充它,但我的数学背景还不够强大,无法在没有帮助的情况下完成。

我的应用程序的缓慢部分是什么?我该如何解决?

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

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

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

【问题讨论】:

尝试将getImageDataputImageData 拉出循环。获取整个图像数据以启动、修改它,然后将其全部写回,而不是对每个像素进行读/写循环。 刚刚尝试过。仍然慢得无法使用。 另外,按照这里的建议切换到 createImageData:***.com/questions/4899799/… 仍然很慢,但稍微好一点。 需要其他信息:您说“我有所有绘画的鼠标坐标详细信息”。这是否意味着您可以为需要填充的绘画的任何部分创建画布路径? 有一个高效且多功能的 js 图像处理库FILTER.js 它将在下一次更新中提供快速填充插件(使用扫描线算法)(ps 我是作者) 【参考方案1】:

我意识到这是一个非常古老的问题,但如果您仍在处理此问题,请暂时输入一些代码,对函数的各个部分进行计时,以找到最慢的地方。绝对将 getimagedata 和 putimagedata 的调用拉出循环 - 每个“填充”只调用一次。获得图像数据后,通过其底层缓冲区获取和设置像素的颜色,将其视为 Uint32Array。

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

【讨论】:

以上是关于使 HTML5 画布填充高效的主要内容,如果未能解决你的问题,请参考以下文章

用于游戏的 HTML 5 在画布上高效绘图

HTML5画布Canvas坐标轴转换图案填充渐变与阴影

如何使画布元素根据鼠标位置填充和重新填充

一个jQuery插件,使HTML5画布易于使用。

如何仅使用 HTML5 功能使画布移动?

如何使 HTML5 画布适合动态父/弹性框容器