Perché i valori di impostazione CanvasPixelArray di HTML5 incredibilmente lento e come posso farlo più velocemente?

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

Domanda

Sto cercando di fare alcuni effetti visivi dinamici utilizzando la manipolazione dei pixel i HTML 5 tela, ma io sono in esecuzione in un problema in cui l'impostazione pixel nel CanvasPixelArray è incredibilmente lento.

Per esempio, se ho codice come:

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

Profiling con Chrome rivela, viene eseguito il 44% più lento del seguente codice in cui CanvasPixelArray non viene utilizzato.

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

La mia ipotesi è che la ragione di questo rallentamento è dovuto alla conversione tra i doppi javascript e gli interi a 8 bit senza segno interne, utilizzato dal CanvasPixelArray.

  1. È questo ipotesi corretta?
  2. Esiste un modo per ridurre il tempo speso valori di impostazione nella CanvasPixelArray?
È stato utile?

Soluzione

Prova caching un riferimento alla matrice di pixel data. Il tuo rallentamento potrebbe essere attribuito alle ulteriori accessi di proprietà a imageData.data. Vedere questo articolo maggiori spiegazioni.

es. Questo dovrebbe essere più veloce che quello che si ha attualmente.

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

Altri suggerimenti

Non so se questo ti aiuta, perché si vuole manipolare i pixel, ma per me, in Firefox 3.6.8, solo la chiamata alla putImageData era molto, molto lento, senza fare alcuna manipolazione dei pixel. Nel mio caso, ho voluto solo per ripristinare una versione precedente dell'immagine che era stato salvato con getImageData. Troppo lento.

Invece, ho preso a lavorare bene con toDataUrl / drawImage invece. Per me sta funzionando abbastanza veloce che posso chiamare entro la gestione di un evento MouseMove:

Per salvare:

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

La ripristinare:

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

Sembra che tu sia facendo una sorta di "copiarlo sul video", quindi forse drawImage o tutti-at-once putImageData potrebbe aiutare. Looping un quarto di milione di volte per copiare i pixel singolarmente, invece di usare massicce "blitting" operazioni, tende ad essere molto più lento - e non solo in Javascript, -).

Stranamente, passanti attraverso le matrici oggetto 2D sono più veloci di un calcs compensato matrice 1d e oggetti. Formato di conseguenza e vedere se questo aiuta (nel mio test, era 20 volte più veloce).

(testa a testa: questo script potrebbe mandare in crash il browser Se lo si esegue, tenere duro per qualche minuto e lasciar fare la sua 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;

}

Più informazioni: http: / /discourse.wicg.io/t/why-a-straight-array-for-canvas-getimagedata/1020/6

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top