2014-07-14 4 views
8

gegeben zwei Leinwand mit der gleichen Pixelgröße, wobei Canvas1 enthält ein beliebiges Bild (jpg, Png oder so) und canvas2 enthält schwarze und nicht-schwarze Pixel.Merge Leinwand Bild und Leinwand Alpha-Maske in Dataurl generiert PNG

was ich will achive: ein drittes canvas3 i canvas1 klonen möchten verwenden und jedes schwarze canvas2 Pixel haben (kann eine Schwelle von Schwärze einschließlich) in canvas3 transparent sein

i bereits eine funktionierende Lösung wie dieses:

canvas3context.drawImage(canvas1,0,0); 
var c3img = canvas3context.getImageData(0,0,canvas3.width,canvas3.height); 
var c2img = canvas2context.getImageData(0,0,canvas2.width,canvas2.height); 
loop(){ 
    if(c2img i-th,i+1-th,i+2-th pixel is lower than threshold) 
     set c3img.data[i]=c3img.data[i+1]=c3img.data[i+2]=c3img.data[i+3]=0 
} 

das Problem mit oben (Pseudo-) Code ist, dass es so meine Frage langsam ist: jeder kann eine Idee, wie teilt dies deutlich zu beschleunigen? Ich dachte über Webgl nach, aber ich habe nie damit gearbeitet - also habe ich keine Ahnung von Shadern oder den dafür benötigten Tools oder Begriffen. ein andere Idee war, dass vielleicht ich canvas2 auf schwarz & weiß irgendwie sehr schnell (und nicht nur modifieng jedes Pixel in einer Schleife wie oben) und arbeitet mit Mischmodi umwandeln könnte das transparente Pixel

jede Hilfe dankbar ist sehr

+0

Ein weiteres Problem bei der Iteration von Pixeln besteht darin, dass das Lesen von Canvas-Bilddaten in das Ursprungsproblem führen kann. –

Antwort

7
zu erzeugen

Beantworte ich meine eigene Frage, biete ich eine Lösung zum Zusammenführen eines beliebigen Bildes mit einem schwarzen & weißen Bild an. Was noch fehlt ist, wie man den Alpha-Kanal für nur eine Farbe einer Leinwand einstellt.

Ich die Frage in Stücke trennen und sie jeweils beantworten.

Frage 1: Wie eine Leinwand in Graustufen jedes Pixel ohne Iterieren konvertieren?

Antwort: das Bild zeichnet auf eine weiße Leinwand mit Mischmodus ‚Leuchtkraft‘

function convertCanvasToGrayscale(canvas){ 
    var tmp = document.createElement('canvas'); 
    tmp.width = canvas.width; 
    tmp.height = canvas.height; 
    var tmpctx = tmp.getContext('2d'); 

    // conversion 
    tmpctx.globalCompositeOperation="source-over"; // default composite value 
    tmpctx.fillStyle="#FFFFFF"; 
    tmpctx.fillRect(0,0,canvas.width,canvas.height); 
    tmpctx.globalCompositeOperation="luminosity"; 
    tmpctx.drawImage(canvas,0,0); 

    // write converted back to canvas 
    ctx = canvas.getContext('2d'); 
    ctx.globalCompositeOperation="source-over"; 
    ctx.drawImage(tmp, 0, 0); 
} 

Frage 2: Wie ein Grau Leinwand in schwarz & weiß konvertieren, ohne Iterieren jedes Pixel?

Antwort: zweimal farb dodge Mischmodus mit Farbe #FEFEFE wird

function convertGrayscaleCanvasToBlackNWhite(canvas){ 
    var ctx = canvas.getContext('2d'); 

    // in case the grayscale conversion is to bulky for ya 
    // darken the canvas bevore further black'nwhite conversion 
    //for(var i=0;i<3;i++){ 
    // ctx.globalCompositeOperation = 'multiply'; 
    // ctx.drawImage(canvas, 0, 0); 
    //} 

    ctx.globalCompositeOperation = 'color-dodge'; 
    ctx.fillStyle = "rgba(253, 253, 253, 1)"; 
    ctx.beginPath(); 
    ctx.fillRect(0, 0, canvas.width, canvas.height); 
    ctx.fill(); 
    ctx.globalCompositeOperation = 'color-dodge'; 
    ctx.fillStyle = "rgba(253, 253, 253, 1)"; 
    ctx.beginPath(); 
    ctx.fillRect(0, 0, canvas.width, canvas.height); 
    ctx.fill(); 
} 

Beachten Sie die Arbeit machen: Diese Funktion setzt voraus, dass Sie schwarze Bereiche links schwarz wollen und jeder nicht-schwarzes Pixel werde weiß! also ein Graustufenbild, das kein schwarzes Pixel hat, wird komplett weiß. Der Grund, warum ich diese Operation gewählt habe, ist, dass es in meinem Fall besser funktioniert und nur zwei Blend-Operationen verwenden bedeutet, dass es ziemlich schnell ist - wenn du willst, dass dunklere Pixel schwarz bleiben mehr weiße Pixel werden weiß Sie können die kommentierte For-Schleife verwenden, um das Bild vorher zu verdunkeln. Auf diese Weise werden dunkle Pixel schwarz und hellere Pixel dunkler. wie Sie die Menge von schwarzem Pixel mit farb ausweichen erhöhen wieder den Rest der Arbeit tun

Frage 3: Wie ohne Iterieren ein Schwarz & Weiß Leinwand mit einer anderen Leinwand jedes Pixel verschmelzen?

Antwort: use 'mehrfach' Mischmodus

function getBlendedImageWithBlackNWhite(canvasimage, canvasbw){ 
    var tmp = document.createElement('canvas'); 
    tmp.width = canvasimage.width; 
    tmp.height = canvasimage.height; 

    var tmpctx = tmp.getContext('2d'); 

    tmpctx.globalCompositeOperation = 'source-over'; 
    tmpctx.drawImage(canvasimage, 0, 0); 

    // multiply means, that every white pixel gets replaced by canvasimage pixel 
    // and every black pixel will be left black 
    tmpctx.globalCompositeOperation = 'multiply'; 
    tmpctx.drawImage(canvasbw, 0, 0); 

    return tmp; 
} 

Frage 4: Wie ohne Iterieren jedes Pixel ein schwarzes & Weiß Leinwand invertieren?

Antwort: Verwendung 'Differenz' Mischmodus

function invertCanvas(canvas){ 
    var ctx = canvas.getContext("2d"); 

    ctx.globalCompositeOperation = 'difference'; 
    ctx.fillStyle = "rgba(255, 255, 255, 1)"; 
    ctx.beginPath(); 
    ctx.fillRect(0, 0, canvas.width, canvas.height); 
    ctx.fill(); 
} 

jetzt zu 'merge' eine canvasimage mit einem canvasmask ein

convertCanvasToGrayscale(canvasmask); 
convertGrayscaleCanvasToBlackNWhite(canvasmask); 
result = getBlendedImageWithBlackNWhite(canvasimage, canvasmask); 

in Bezug auf Leistung tun können: offensichtlich jene Mischmodi sind viel schneller als das Modifizieren jedes Pixels und um ein bisschen schneller zu werden, kann man alle Funktionen nach Bedarf in einer Funktion zusammenfassen und nur einen tmpcanvas recyceln - aber das bleibt dem r überlassen EADER ^^

als Nebenbemerkung: i getestet, wie die Größe des resultierenden png unterscheidet, wenn man oben ist mit dem gleichen Bild getBlendedImageWithBlackNWhite Ergebnis zu vergleichen, aber die schwarzen Flächen jedes Pixel durch Iteration und Einstellen des Alphakanals den Unterschied transparent gemacht In der Größe ist fast nichts und wenn Sie also nicht wirklich die Alpha-Maske brauchen, kann die Information, dass jedes schwarze Pixel transparent sein soll, für die weitere Verarbeitung reichen.

Hinweis: man kann die Bedeutung von schwarz und weiß mit der invertieren invertCanvas() Funktion

Wenn Sie mehr wissen möchten, warum ich diese Mischmodi oder wie blend mo die arbeiten wirklich Sie die Mathematik hinter ihnen überprüfen sollten - imho sind Sie solche Funktionen zu entwickeln, nicht in der Lage, wenn ya nicht wissen, wie sie wirklich funktionieren: math behind blend modes canvas composition standard including a bit math

ein Beispiel benötigen - den Unterschied: http://jsfiddle.net/C3fp4/1/

+0

Großartiges Zeug. Beachten Sie, dass einige dieser globalCompositeOperation-Filter bei Safari noch nicht funktionieren. – Mulhoon