Por que definir os valores CanvasPixelArray do HTML5 é ridiculamente lento e como posso fazer isso mais rápido?

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

Pergunta

Estou tentando fazer alguns efeitos visuais dinâmicos usando a manipulação de pixels da tela HTML 5, mas estou enfrentando um problema em que a configuração de pixels no CanvasPixelArray é ridiculamente lenta.

Por exemplo, se eu tiver um 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);

A criação de perfil com o Chrome revela que ele é executado 44% mais lentamente do que o código a seguir, onde CanvasPixelArray não é usado.

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

Meu palpite é que o motivo dessa desaceleração se deve à conversão entre as duplicatas do Javascript e os números inteiros internos não assinados de 8 bits, usados ​​pelo CanvasPixelArray.

  1. Esta suposição está correta?
  2. Existe alguma maneira de reduzir o tempo gasto definindo valores no CanvasPixelArray?
Foi útil?

Solução

Tente armazenar em cache uma referência ao data matriz de pixels.Sua desaceleração pode ser atribuída aos acessos adicionais à propriedade para imageData.data.Ver Este artigo para mais explicações.

Por exemplo.Isso deve ser mais rápido do que o que você tem atualmente.

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

Outras dicas

Não sei se isso te ajuda porque você quer manipular pixels, mas para mim, no Firefox 3.6.8, apenas a chamada para putImageData era muito, muito lenta, sem fazer nenhuma manipulação de pixels.No meu caso, eu só queria restaurar uma versão anterior da imagem que foi salva com getImageData.Muito devagar.

Em vez disso, consegui que funcionasse bem usando toDataUrl/drawImage.Para mim, está funcionando rápido o suficiente para que eu possa chamá-lo ao lidar com um evento mousemove:

Salvar:

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

O para restaurar:

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

Parece que você está fazendo algum tipo de "blitting", então talvez desenharImagem ou tudo de uma vez colocarImageData Poderia ajudar.Fazer um loop de um quarto de milhão de vezes para copiar pixels individualmente, em vez de usar operações massivas de "blitting", tende a ser muito mais lento - e não apenas em Javascript ;-).

Estranhamente, os loops através de matrizes de objetos 2D são mais rápidos do que cálculos de deslocamento de matriz 1D e nenhum objeto.Formate adequadamente e veja se isso ajuda (nos meus testes, foi 20x mais rápido).

(Atenção:este script pode travar seu navegador!Se você executá-lo, espere alguns minutos e deixe-o fazer seu trabalho)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;

}

Mais Informações: http://discourse.wicg.io/t/why-a-straight-array-for-canvas-getimagedata/1020/6

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top