2013-01-01 8 views
6

Ich bemerkte ein seltsames Problem mit getImageData; Transparenz des Bildes scheint ignoriert zu werden, wenn die Bilddaten abgerufen werden.Transparenz verloren mit getImageData - HTML5 2d Kontext

Da jedes Bild auf eine canvas gezeichnet werden muss, bevor seine Bilddaten erhalten werden können, ging ich davon aus, dass dies ein Problem mit der fraglichen canvas undurchsichtig war. Aber ich lag falsch, da die Verwendung der canvas als Argument in drawImage Transparenz bewahrt.

Hier ist, wie ich das Bild geladen habe;

var load_image = function(name, url, holder, callback) { 
    var img = new Image(); 
    img.src = url; 

    img.addEventListener('load', function(e) { 
     var canvas = make_canvas(e.target.width, e.target.height); 
     var ctx = canvas.getContext('2d'); 

     ctx.clearRect(0, 0, canvas.width, canvas.height); 
     ctx.drawImage(e.target, 0, 0); 

     holder[name] = {canvas: canvas, ctx: ctx}; 

     delete e.target; 

     callback.call(); 
    }, false); 
}; 

Die callback ist einfach die Ziehfunktion, die draw_image um das Bild zu zeichnen aufruft.

Die übliche Version;

var draw_image = function(ctx, img, sx, sy, w, h, dx, dy) { 
    ctx.drawImage(img.canvas, sx, sy, w, h, dx, dy, w, h); 
}; 

Es nimmt einfach die Leinwand als Argument für drawImage, und das Ergebnis ist wie mit Transparenz aufrechterhalten sollte. Example.

Die Bilddatenversion;

var draw_image = function(ctx, img, sx, sy, w, h, dx, dy) { 
    var imagedata = img.ctx.getImageData(sx, sy, w, h); 
    ctx.putImageData(imagedata, dx, dy); 
}; 

Dieses erhält man die Bilddaten des gewünschten Rechtecks ​​aus derselben Leinwand wie die in der üblichen Version verwendet wird, und stellt die Bilddaten auf der Leinwand I zeichnen möchten. Ich glaube, Transparenz sollte beibehalten werden, aber das ist nicht so. Example. (Dies ist ein Dropbox-Link wegen des Flags origin-clean.)

Bin ich falsch bei der Annahme, dass die Transparenz mit getImageData beibehalten werden sollte? Oder verwende ich es nur falsch?

In jedem Fall würde Hilfe wirklich geschätzt werden.

Antwort

7

Ich glaube, Ihr Problem ist, dass putImageData kein verwendet, um die Quell- und Zielbilddaten zu mischen. Stattdessen werden die Kanäle rot, grün, blau, und alpha direkt in die Zeichenfläche geschrieben. Für vollständig transparente Pixel bedeutet dies, dass sie möglicherweise in der von Ihnen erwarteten Farbe erscheinen.

Stattdessen können Sie ein intermediäres Canvas-Element erstellen, dazu zeichnen und dann drawImage() verwenden, um es mit der entsprechenden globalCompositeOperation auf Ihr Ziel-Canvas zu rendern. Mask for putImageData with HTML5 canvas? diskutiert dieses Problem ausführlicher.

Update: Sie können überprüfen, dass die Daten, die Sie in Ihr "gebrochenes" Beispiel schreiben, tatsächlich transparente Daten darin haben, indem Sie ctx.getImageData(230,50,1,1).data tun. Das Ergebnis ist [0,0,0,0] - d. H. Ein vollständig transparentes Pixel.

+1

Ich sehe, das erklärt es! Danke für deine Antwort! Obwohl dies wirklich einen Schraubenschlüssel in den Arbeiten wirft. Ich wollte testen, ob die Vorteile der Verwendung von "Canvas" als "Bilder" in Spielen (Farbmaskierung und perspektivische Transformation ohne Kontext) den Overhead überwiegen oder nicht. Wenn ich ein intermediäres Canvas einführen muss, um das transformierte Bild zu zeichnen, kann ich genauso gut "Image" -Objekte und ein raues "Canvas" zur Bearbeitung verwenden. Danke noch einmal! – Rikonator