使用fillRect绘制像素并不流畅

时间:2014-07-02 08:53:41

标签: html html5 canvas rgb pixel

我的javascript代码用多次混合绘制墙。如果我使用fillRect它更快但不平滑,而且putImageData与它相反,并且需要大约10秒来绘制图像。例如,左边的一个是用fillRect:

创建的

enter image description here

左图中使用的代码;

context_paintLayer.fillStyle = 'rgba(' + pixel.data[0] + ',' + pixel.data[1] + ',' + pixel.data[2] + ',' + pixel.data[3] + ')';
context_paintLayer.fillRect(x, y, 1, 1);    

右图中使用的代码;

context_paintLayer.putImageData(pixel, x, y);

如果您愿意,我可以在此发布完整代码。感谢。

function applyPaint(selectedColor)
{
    var partitionImageData = context_partitionLayer.getImageData(0, 0, width, height);
    var imageData = context_imageLayer.getImageData(0, 0, width, height);
    var selectedColorRGB = selectedColor.split("-");

    for(var y = targetStartY; y < targetEndY; y++) 
    {
        for(var x = targetStartX; x < targetEndX; x++) 
        {
            var index = ((width * y) + x) * 4;

            var r = partitionImageData.data[index];
            var g = partitionImageData.data[index + 1];
            var b = partitionImageData.data[index + 2];
            var a = partitionImageData.data[index + 3];

            pixel.data[0] = (selectedColorRGB[0] * (imageData.data[index]+50)) / 255;
            pixel.data[1] = (selectedColorRGB[1] * (imageData.data[index + 1]+50)) / 255;
            pixel.data[2] = (selectedColorRGB[2] * (imageData.data[index + 2]+50)) / 255;
            pixel.data[3] = (a * (imageData.data[index + 3])) / 255;

            if(isInPart(r, g, b) == 1)
            {
                paint(x, y);
            }
        }
    }
}

function paint(x, y)
{
    context_paintLayer.fillStyle = 'rgba(' + pixel.data[0] + ',' + pixel.data[1] + ',' + pixel.data[2] + ',' + pixel.data[3] + ')';
    context_paintLayer.fillRect(x, y, 1, 1);    
    //context_paintLayer.putImageData(pixel, x, y);
}

function isInPart(r, g, b, targetPart) {

    if ((r >= targetRMin && r <= targetRMax) && (g >= targetGMin && g <= targetGMax) && (b >= targetBMin && b <= targetBMax)) {
        return 1;
    }
    else {
        return 0;
    }
}

1 个答案:

答案 0 :(得分:1)

我建议你画画&#39;在你的循环中直接进入一个imageData,然后在最后做一个单独的puImageData 由于您的画布大小没有变化,您可以缓存数组以避免创建/处理的成本 下面的代码应该更快 我不太了解您的要求,例如,如果图像正在发生变化,因此每次调用都需要getImageDataed(:-)),但您会得到这个想法:

function applyPaint() {
    var partitionImageData = context_partitionLayer.getImageData(0, 0, width, height);
    var partitionData = partitionImageData.data;
    var sourceImageData = context_imageLayer.getImageData(0, 0, width, height);
    var sourceData = sourceImageData.data;
    var destImageData = context_paintLayer.getImageData(0, 0, width, height);
    var destData = destImageData.data;

    applyPaint = function (selectedColor) {
        var selectedColorRGB = selectedColor.split("-");
        var index = 0;
        var selectedR = selectedColorRGB[0];
        var selectedG = selectedColorRGB[1];
        var selectedB = selectedColorRGB[2];
        // cache arrays for speed up
        var _partitionData = partitionData;
        var _sourceData = sourceData ;
        var _destData = destData;

        for (var y = targetStartY; y < targetEndY; y++) {
            for (var x = targetStartX; x < targetEndX; x++) {
                index = ((width * y) + x) << 2;
                var r = _partitionData[index];
                var g = _partitionData[index + 1];
                var b = _partitionData[index + 2];

                if (isInPart(r, g, b) == 1) {
                    var a = _partitionData[index + 3];
                    _destData[index] = (selectedR * (_sourceData[index] + 50)) >> 8;
                    _destData[index + 1] = (selectedG * (_sourceData[index + 1] + 50)) >> 8;
                    _destData[index + 2] = (selectedB * (_sourceData[index + 2] + 50)) >> 8;
                    _destData[index + 3] = (a * (_sourceData[index + 3])) >> 8;
                }
            }
        }
        context_paintLayer.putImageData(destImageData, 0, 0);
    }
    return applyPaint.apply(this, arguments);
}

编辑:如果您计划每次更新整个图像,可以将两个for循环简化为:

  var pixelCount = width*height;
  var index = 0;
  while (pixelCount--) {

    // process index 
    // ...

    index+=4;
  }

编辑2:

对于给定图像,这是一种获得实时重新着色的方法(意味着图像速率> 60 fps)。 我们的想法是通过使用复合模式/混合模式为您计算gpu。

http://dev.w3.org/fxtf/compositing-1/

第1步) 重新处理分区图像以获取分区掩码画布,该画布将包含全白色 适用于符合条件的像素,黑色适用于不匹配的像素。

它将像

一样构建
• build new canvas to store the partition mask.
• for each pixel of the partition image : 
         if (condition on the partition data r,g,b )
             partitionMaskImageData[ ...r and g and b and a ] = 255  
         else
             partitionMaskImageData[ ...r and g and b and a ] = 0  

现在,为您的操作构建一个静态临时画布 每次你想改变颜色:

   1) clear the temp canvas.  
    2) draw the partition mask on the temp canvas.  
    3) draw the image on the temp canvas using mode 'destination-in'.   
    4) add 50 to all rgb : draw a rect  of color 'rgb(50,50,50) using mode 'lighter'.    
    5) fill a rect with your selected color using mode 'multiply'  
        --> now the temp canvas is ready.
    6) draw the original image on destination canvas   
    7) draw the temp canvas on the destination canvas.  

这里没有什么麻烦,并非所有浏览器都支持&#39;乘以&#39;,但正如你在这里看到的那样http://caniuse.com/#feat=canvas-blending

我仍然认为更新将花费不到1毫秒(在桌面上)。