2014-07-14 6 views
8

dato due tele con la stessa dimensione di pixel, dove canvas1 contiene un'immagine arbitraria (jpg, png o simile) e canvas2 contiene pixel neri e non neri.Unisci immagine tela e maschera alpha canvas in dataurl generata png

quello che voglio achive: utilizzando un terzo canvas3 voglio clonare canvas1 ed avere ogni pixel canvas2 nero (può tra cui una soglia di oscurità) essere trasparenti in canvas3

ho già una soluzione di lavoro come questo:

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 
} 

il problema con il codice di cui sopra (pseudo) è, che è lento quindi la mia domanda è: chiunque può condividere un idea di come accelerare questo in modo significativo? Ho pensato a webgl ma non ho mai lavorato con esso - quindi non ho idea degli shader o degli strumenti o dei termini necessari per questo. un'altra idea era che forse avrei potuto convertire canvas2 in bianco & bianco in qualche modo molto veloce (non solo modifieng ogni pixel in un ciclo come sopra) e lavorare con i metodi di fusione per generare i pixel trasparenti

ogni aiuto è molto apprezzato

+0

Un altro problema con l'iterazione dei pixel è che la lettura dei dati delle immagini su tela potrebbe incorrere nel problema dell'origine incrociata. –

risposta

7

rispondendo alla mia domanda, fornisco una soluzione per l'unione di un'immagine arbitraria con un'immagine bianca & nera. ciò che ancora manca è come impostare il canale alfa per un solo colore di una tela.

I separare la domanda in pezzi e rispondere a ciascuno di essi.

Domanda 1: come convertire una tela in scala di grigi, senza l'iterazione ogni pixel?

Risposta: disegnare l'immagine su una tela bianca con metodo di fusione 'luminosità'

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

Domanda 2: Come convertire una tela in scala di grigi in bianco & bianco, senza l'iterazione ogni pixel?

Risposta: due volte colore Dodge metodo di fusione con #FEFEFE colore farà il lavoro

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

Nota: questa funzione presuppone che si desidera aree nere lasciate in bianco e ogni pixel non-nero diventare bianco! quindi un'immagine in scala di grigi che non ha pixel neri diventerà completamente bianca il motivo per cui scelgo questa operazione è che ha funzionato meglio nel mio caso e usando solo due operazioni di fusione significa che è piuttosto veloce - se vuoi che più pixel scuri vengano lasciati neri e più pixel bianchi diventano bianchi è possibile utilizzare il ciclo commentato per scurire l'immagine in anticipo. quindi il pixel scuro diventerà nero e il pixel più luminoso diventerà più scuro. come si aumenta la quantità di pixel nero del usando il colore-Dodge di nuovo fare il resto del lavoro

Domanda 3: Come unire un nero & tela bianca con un'altra tela senza l'iterazione ogni pixel?

Risposta: uso 'moltiplica' metodo di fusione

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

Domanda 4: Come invertire un Black & Bianco tela senza l'iterazione ogni pixel?

Risposta: modalità uso blend 'differenza'

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

ora a 'merge' un canvasimage con un canvasmask si può fare

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

riguardo alle prestazioni: ovviamente quelli metodi di fusione sono molto più veloci di modificare ogni pixel e per ottenere un po 'più veloce è possibile riunire tutte le funzioni insieme in una sola funzione e riciclare solo un tmpcanvas - ma questo è lasciato alla eader ^^

come sidenote: i testato come la dimensione del png risultante è diverso quando si confrontano sopra è risultato getBlendedImageWithBlackNWhite con la stessa immagine ma le aree nere sono fatti trasparente mediante iterazione ogni pixel e impostazione del canale alfa la differenza in dimensioni è quasi nulla e quindi se non hai davvero bisogno della maschera alfa l'informazione che ogni pixel nero è destinato a essere trasparente può essere sufficiente per l'ulteriore elaborazione

nota: si può invertire il significato di bianco e nero utilizzando il Funzione invertCanvas()

se si desidera sapere più del motivo per cui utilizzo le modalità di fusione o il metodo di fusione des funziona davvero si dovrebbe verificare la matematica dietro di loro - imho non siete in grado di sviluppare tali funzioni ya se non sai come funzionano veramente: math behind blend modes canvas composition standard including a bit math

bisogno di un esempio - individuare la differenza: http://jsfiddle.net/C3fp4/1/

+0

Grandi cose. Nota alcuni di questi filtri GlobalCompositeOperation non funzionano ancora in Safari. – Mulhoon