为什么设置HTML5的CanvasPixelArray值的速度非常慢,我该如何更快地做到这一点?

问题描述:

我想使用HTML 5画布的像素操作来做一些动态的视觉效果,但我遇到了一个问题,在CanvasPixelArray中设置像素的速度非常慢。为什么设置HTML5的CanvasPixelArray值的速度非常慢,我该如何更快地做到这一点?

例如,如果我有这样的代码:

imageData = ctx.getImageData(0, 0, 500, 500); 

for (var i = 0; i < imageData.length; i += 4){ 
    imageData.data[i] = buffer[i]; 
    imageData.data[i + 1] = buffer[i + 1]; 
    imageData.data[i + 2] = buffer[i + 2]; 
} 

ctx.putImageData(imageData, 0, 0); 

绘制与铬揭示,它的运行速度比下面的代码在不使用CanvasPixelArray慢44%。

tempArray = new Array(500 * 500 * 4); 
imageData = ctx.getImageData(0, 0, 500, 500); 

for (var i = 0; i < imageData.length; i += 4){ 
    tempArray[i] = buffer[i]; 
    tempArray[i + 1] = buffer[i + 1]; 
    tempArray[i + 2] = buffer[i + 2]; 
} 

ctx.putImageData(imageData, 0, 0); 

我的猜测是,这种放缓的原因是由于JavaScript的双打和内部8位无符号整数,由CanvasPixelArray使用之间的转换。

  1. 这个猜测是否正确?
  2. 是否有减少在CanvasPixelArray中设置值的时间?
+0

老问题并且可能过时了,在你的第二个例子中,你似乎没有对'imageData'做任何事情(例如,你没有将'tempArray'的值设置为'imageData')? – ZachB 2015-07-29 18:53:41

+0

@ZachB示例正确。它不使用当时似乎是瓶颈的CanvasPixelArray。请参阅下面的解决问题的一些重要答案。 – Nixuz 2015-07-31 00:41:52

+0

哈,我误解了你的问题。 :) – ZachB 2015-07-31 00:47:05

尝试缓存对data像素阵列的引用。您的减速可能归因于对imageData.data的额外财产访问。有关更多说明,请参阅this article

E.g.这应该比你现在拥有的更快。

var imageData = ctx.getImageData(0, 0, 500, 500), 
    data = imageData.data, 
    len = data.length; 

for (var i = 0; i < len; i += 4){ 
data[i] = buffer[i]; 
data[i + 1] = buffer[i + 1]; 
data[i + 2] = buffer[i + 2]; 
} 

ctx.putImageData(imageData, 0, 0); 
+0

您还会在上述ajaxian文章中找到参考,并有更多评论表明它是参考访问的问题。 http://ajaxian.com/archives/canvas-image-data-optimization-tip – 2010-06-03 09:52:54

+0

我不明白什么是缓冲区,你的意思是imageData? – kilianc 2012-01-25 17:34:25

+0

这是Nixuz想要复制到图像中的数据 - 定义在其他地方。它不是imageData,因为“数据”变量是图像数据 - 尝试将其复制到自身是没有意义的。 – jimr 2012-02-02 05:48:11

看起来你正在做某种“blitting”,所以也许drawImage或一次putImageData可以提供帮助。循环利用25万次来单独拷贝像素,而不是使用大量的“blitting”操作,往往会慢得多 - 而不仅仅是Javascript ;-)。

+1

当调用putImageData时,实际绘图会一次全部发生。通过循环遍历每个“像素”(缓冲器中的块)并且对它们中的每一个执行一些预先操作来处理缓冲器数据的方法相当快,至少比所描述的基本上旨在将数据取得到的方法快得多屏幕。我感到震惊的是,处理数据需要很少的时间,然后将其复制到canvasPixelArray中进行绘制。 – Nixuz 2010-04-04 01:59:11

我不知道是否是因为要处理的像素这可以帮助你,但对我来说,在Firefox 3.6.8,只需调用putImageData是非常,非常缓慢的,没有做任何像素处理。就我而言,我只是想恢复使用getImageData保存的以前版本的图像。太慢了。

取而代之的是,我使用toDataUrl/drawImage代替了它。对我来说,它的工作速度不够快,我可以在处理mousemove事件称之为:

为了节省:

savedImage = new Image() 
savedImage.src = canvas.toDataURL("image/png") 

的恢复:

ctx = canvas.getContext('2d') 
ctx.drawImage(savedImage,0,0) 

奇怪的是,遍历2D对象数组快于1d数组偏移量计算并且没有对象。格式相应,看看是否有帮助(在我的测试中,它快20倍)。

(请注意:这个脚本可能崩溃您的浏览器如果你运行它,坐稳几分钟,让它做它的事!) http://jsfiddle.net/hc52jx04/16/

function arrangeImageData (target) { 

var imageCapture = target.context.getImageData(0, 0, target.width, target.height); 
var imageData = { 
    data: [] 
}; 
imageData.data[0] = []; 
var x = 0; 
var y = 0; 
var imageLimit = imageCapture.data.length; 

for (var index = 0; index < imageLimit; index += 4) { 

    if (x == target.width) { 
     y++; 
     imageData.data[y] = []; 
     x = 0; 
    } 

    imageData.data[y][x] = { 
     red: imageCapture.data[index], 
     green: imageCapture.data[index + 1], 
     blue: imageCapture.data[index + 2], 
     alpha: imageCapture.data[index + 3] 
    }; 
    x++; 
} 
return imageData; 

} 


function codifyImageData (target, data) { 

var imageData = data.data; 

var index = 0; 
var codedImage = target.context.createImageData(target.width, target.height); 

for (var y = 0; y < target.height; y++) { 

    for (var x = 0; x < target.width; x++) { 

     codedImage.data[index] = imageData[y][x].red; 
     index++; 
     codedImage.data[index] = imageData[y][x].green; 
     index++; 
     codedImage.data[index] = imageData[y][x].blue; 
     index++; 
     codedImage.data[index] = imageData[y][x].alpha; 
     index++; 
    } 

} 

return codedImage; 

} 

的更多信息:http://discourse.wicg.io/t/why-a-straight-array-for-canvas-getimagedata/1020/6