¿Por qué es el establecimiento de valores CanvasPixelArray de HTML5 ridículamente lento y cómo puedo hacerlo más rápido?

StackOverflow https://stackoverflow.com/questions/2573212

Pregunta

Estoy tratando de hacer algunos efectos visuales dinámicos mediante la manipulación de píxeles los HTML 5 lienzo, pero yo estoy corriendo en un problema en el establecimiento de píxeles en la CanvasPixelArray es ridículamente lento.

Por ejemplo, si tengo un código como:

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);

Perfilado con Chrome revela, se ejecuta 44% más lento que el siguiente código donde no se utiliza CanvasPixelArray.

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);

Mi conjetura es que la razón de esta disminución se debe a la conversión entre los dobles javascript y los números enteros de 8 bits sin signo internos, utilizado por el CanvasPixelArray.

  1. ¿Es esta suposición correcta?
  2. ¿Hay alguna forma de reducir el tiempo dedicado a los valores de ajuste en el CanvasPixelArray?
¿Fue útil?

Solución

Trate de almacenamiento en caché de una referencia a la matriz de píxeles data. Su desaceleración podría ser atribuida a los accesos adicionales a imageData.data. Ver este artículo para más explicación.

por ejemplo. Esto debería ser más rápido que lo que tiene actualmente.

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);

Otros consejos

No sé si esto le ayuda porque se quiere manipular píxeles, pero para mí, en Firefox 3.6.8, sólo la llamada a putImageData era muy, muy lento, sin hacer ningún tipo de manipulación de píxeles. En mi caso, yo sólo quería restaurar una versión anterior de la imagen que había sido guardado con getImageData. Demasiado lento.

En lugar de ello, lo tengo para trabajar bien utilizando toDataUrl / drawImage lugar. Para mí que está funcionando lo suficientemente rápido que puedo llamar dentro de la manipulación de un evento MouseMove:

Para guardar:

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

La restauración a:

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

Parece que estás haciendo algún tipo de "blitting", así que tal vez drawImage o todas a la vez putImageData podría ayudar. Colocando un cuarto de millón de veces para copiar píxeles de forma individual, en lugar de utilizar "blitting" operaciones masivas, tiende a ser mucho más lento - y no sólo en Javascript; -).

Curiosamente, los bucles a través de matrices de objetos 2D son más rápido que un calculadoras array 1d offset y no hay objetos. Formato consecuencia y ver si eso ayuda (en mis pruebas, era 20 veces más rápido).

(mano a mano: este script podría estrellarse su navegador Si lo ejecuta, se sientan apretados durante unos minutos y dejar que haga su cosa) 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;

}

Más información: http: / /discourse.wicg.io/t/why-a-straight-array-for-canvas-getimagedata/1020/6

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top