2010-04-04 3 views
20

Ich versuche einige dynamische visuelle Effekte mit der Pixelmanipulation von HTML5 Canvas zu machen, aber ich stoße auf ein Problem, bei dem das Setzen von Pixeln im CanvasPixelArray lächerlich langsam ist.Warum werden die CanvasPixelArray-Werte von HTML5 lächerlich langsam und wie kann ich es schneller machen?

Zum Beispiel, wenn ich Code wie:

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

Profil mit Chrome zeigt, läuft es 44% langsamer als der folgende Code in dem CanvasPixelArray nicht verwendet wird.

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

Meine Vermutung ist, dass der Grund für diese Verlangsamung der Umwandlung zwischen den Javascript verdoppelt und der internen unsigned 8-Bit-Integer, verwendet von der CanvasPixelArray zurückzuführen ist.

  1. Ist diese Annahme richtig?
  2. Gibt es trotzdem eine Reduzierung der Zeitaufwand für das Festlegen von Werten im CanvasPixelArray?
+0

Alte Frage und wahrscheinlich veraltet, in deinem zweiten Beispiel scheinst du nichts zu tun mit 'imageData' (z. B.Sie setzen die Werte nicht von 'tempArray' auf' imageData')? – ZachB

+0

@ZachB Das Beispiel ist korrekt. Es verwendet nicht das CanvasPixelArray, das zu der Zeit der Flaschenhals zu sein schien. Unten finden Sie einige großartige Antworten, die das Problem gelöst haben. – Nixuz

+0

Hah, ich habe deine Frage falsch gelesen. :) – ZachB

Antwort

12

Versuchen Sie, einen Verweis auf das Pixelfeld data zwischenzuspeichern. Ihre Verlangsamung könnte den zusätzlichen Grundstückszugriffen auf imageData.data zugeschrieben werden. Weitere Informationen finden Sie unter this article.

z. Dies sollte schneller sein als das, was Sie gerade haben.

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

Sie finden auch einen Verweis auf den obigen Artikel über Ajaxian, mit weiteren Kommentaren, die darauf hindeuten, dass es sich um ein Problem des Referenzzugriffs handelt. http://ajaxian.com/archives/canvas-image-data-optimization-tip –

+0

Ich kann nicht verstehen, was ist Puffer, meinst du imageData? – kilianc

+0

Es sind die Daten, die Nixuz in das Bild kopieren wollte - woanders definiert. Es ist nicht imageData, da die "data" -Variable die Bilddaten ist - es wäre nicht sinnvoll zu versuchen, sie in sich selbst zu kopieren. – jimr

0

Sieht aus wie Sie eine Art "Blitten" tun, so vielleicht drawImage oder all-at-once putImageData helfen könnte. Eine viertel Million Mal zu kopieren, um einzelne Pixel zu kopieren, anstatt riesige "Blitting" -Operationen zu verwenden, tendiert dazu, viel langsamer zu sein - und nicht nur in Javascript ;-).

+1

Die eigentliche Zeichnung geschieht auf einmal, wenn putImageData aufgerufen wird. Das Verfahren, das die Pufferdaten durch Schleifen über jedes "Pixel" (Block in dem Puffer) verarbeitet und einige Voroperationen an jedem von ihnen ausführt, ist ziemlich schnell, zumindest VIEL schneller als das beschriebene Verfahren, das im Grunde die Daten erhalten soll der Bildschirm. Es schockiert mich, dass die Verarbeitung der Daten viel weniger Zeit in Anspruch nimmt als das Kopieren in das canvasPixelArray zum Zeichnen. – Nixuz

3

Ich weiß nicht, ob dies hilft Ihnen, weil Sie Pixel manipulieren wollen, aber für mich, in Firefox 3.6.8, nur der Aufruf von putImageData war sehr, sehr langsam, ohne jede Pixelmanipulation zu tun. In meinem Fall wollte ich nur eine vorherige Version des Bildes wiederherstellen, das mit getImageData gespeichert wurde. Zu langsam.

Stattdessen habe ich es mit toDataUrl/drawImage stattdessen gut arbeiten. Für mich ist es funktioniert schnell genug, dass ich es im Umgang mit einem mousemove- Ereignis anrufen:

zu speichern:

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

Die wiederherzustellen:

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

Merkwürdig ist, dass eine Schleife durch 2D-Objekt-Arrays schneller als ein 1d-Array-Offset berechnet und keine Objekte. Format entsprechend und sehen, ob das hilft (in meinen Tests war es 20x schneller).

(Heads-up: dieses Skript Ihrem Browser abstürzen könnte, wenn Sie es laufen, für ein paar Minuten sitzen fest und lassen Sie es nicht sein Ding!) 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; 

} 

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

Verwandte Themen