21

我正在尝试使用 HTML 5 画布的像素操作来做一些动态视觉效果,但我遇到了一个问题,即在 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);

使用 Chrome 进行分析显示,它的运行速度比以下未使用 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 双精度数和 CanvasPixelArray 使用的内部无符号 8 位整数之间的转换。

  1. 这个猜测正确吗?
  2. 有没有办法减少在 CanvasPixelArray 中设置值所花费的时间?
4

4 回答 4

12

Try caching a reference to the data pixel array. Your slowdown could be attributed to the additional property accesses to imageData.data. See this article for more explanation.

E.g. This should be faster that what you currently have.

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);
于 2010-06-02T18:11:24.300 回答
4

I don't know if this helps you because you want to manipulate pixels, but for me, in Firefox 3.6.8, just the call to putImageData was very, very slow, without doing any pixel manipulation. In my case, I just wanted to restore a previous version of the image that had been saved with getImageData. Too slow.

Instead, I got it to work well using toDataUrl/drawImage instead. For me it's working fast enough that I can call it within handling a mousemove event:

To save:

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

The to restore:

ctx = canvas.getContext('2d')  
ctx.drawImage(savedImage,0,0)
于 2010-11-26T03:28:55.400 回答
1

Looks like you're doing some kind of "blitting", so maybe drawImage or all-at-once putImageData could help. Looping a quarter million times to copy pixels individually, rather than using massive "blitting" operations, tends to be much slower -- and not just in Javascript;-).

于 2010-04-04T01:43:55.663 回答
1

Oddly, loops through 2d object arrays are faster than a 1d array offset calcs and no objects. Format accordingly and see if that helps (in my tests, it was 20x faster).

(heads up: this script could crash your browser! If you run it, sit tight for few minutes and let it do its thing) 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;

}

More information: http://discourse.wicg.io/t/why-a-straight-array-for-canvas-getimagedata/1020/6

于 2015-09-17T16:19:05.123 回答