Fade la canvas di canapa da scala di grigi a colore

Ho 2 elementi – video e canvas. Nell'evento di riproduzione video, le funzioni disegnano lo stesso video sulla scala di grigi solo su canvas. Poi ho un bottone che dovrebbe sfumare il video delle telecamere dal grigio scuro al colore. Finora sono riuscito a tornare sui colors del clic del button, ma ho bisogno di svanire – dalla scala dei grigi al colore, non solo mostrare immediatamente il colore.

Qualche idea su come potrei realizzare questo? Oppure è anche ansible?

Ecco il codice:

function grey() { if (!stop) { bgContext.drawImage(video, 0, 0, w, h); var pixelData = bgContext.getImageData(0, 0, w, h); for (var i = 0; i < pixelData.data.length; i += 4 ) { var r = pixelData.data[i]; var g = pixelData.data[i+1]; var b = pixelData.data[i+2]; var averageColour = (r + g + b) / 3; pixelData.data[i] = averageColour; pixelData.data[i+1] = averageColour; pixelData.data[i+2] = averageColour; } context.putImageData(pixelData, 0, 0); } } function color() { bgContext.drawImage(video, 0, 0, w, h); var pixelData = bgContext.getImageData(0, 0, w, h); for (var i = 0; i < pixelData.data.length; i += 4 ) { var r = pixelData.data[i]; var g = pixelData.data[i+1]; var b = pixelData.data[i+2]; pixelData.data[i] = r; pixelData.data[i+1] = g; pixelData.data[i+2] = b; } context.putImageData(pixelData, 0, 0); } video.addEventListener('play', function() { setInterval("grey()", 0); }, false); button.addEventListener('click', function() { stop = true; setInterval("color()", 0); }, false); 

Filtri canvas per video / animation in tempo reale.

Filtro bianco e nero

Per fare un filter in bianco e nero è facile.

  // mixAmount is a value from 0 - 1 0 = no mix 1 = full FX // video is the video ctx.drawImage(video,0,0); // draw the video // set up filter ctx.fillStyle = "#888"; // gray colour ctx.globalAlpha = mixAmount; // amount of FX ctx.globalCompositeOperation = "color"; // The comp setting to do BLACK/WHITE ctx.fillRect(0,0,video.width,video.height); // Draw gray over the video ctx.globalAlpha = 1; // reset alpha ctx.globalCompositeOperation = "source-over"; // reset comp 

Oppure puoi rendere il video su se stesso per get un altro FX, la demo mostra il filter Bianco e Nero e altri ancora semplicemente usando il codice precedente e alcuni livelli extra.

Ulteriori informazioni

Per ulteriori informazioni sulla visualizzazione di un video, vedere Visualizzazione del video all'interno della canvas di canale. Ulteriori informazioni possono essere trovate anche nel caricamento di base e nella riproduzione di un video sulla canvas


dimostrazione

La dimostrazione mostra come fare in bianco e nero e qualche altro FX mentre io sono a questo.

Come usare.

Vedere il titolo del video per l'attribuzione. FX a sinistra da cima a fondo "Illuminazione", "Bianco e nero", "Sepia", "Saturato" e "Negativo"

Vedere il titolo del video per l'attribuzione. FX a sinistra dall'alto verso il basso "Schiarisci", "Bianco e Nero", "Sepia", "Saturato" e "Negativo".

Il demo ha il seguente FX Lighter, Darken, Black / White, Negativo, Saturato, Sepia, B & W negativo e altro ancora.

Il Javascript

Il codice relativo alla questione è tutto in alto e marcato. Il resto è carico UI, ecc.

Ogni FX è una function che chiamerà addMix o addOverlay per applicare il filter come mostrato nello snippet di cui sopra. La function addMix è leggermente diversa in quanto disegna il video sul video per get il FX piuttosto che un riempimento.

Le istruzioni sono sulla demo.

Si prega di notare che non tutti i browser supportno tutti i modi comp (perchè chi sa !! :() Né c'è un modo per essere sicuro al 100% se un browser support una modalità o less. tutti gli altri browser migliori di fortuna ..

 //========================================================================== // All the mix function are in this section var FXMix = 1; var addOverlay = function(type){ if(FXMix > 0){ ctx.globalCompositeOperation = type; ctx.globalAlpha = FXMix; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.globalAlpha = 1; ctx.globalCompositeOperation = "source-over"; } } var addMix = function(type,video){ if(FXMix > 0){ ctx.globalCompositeOperation = type; ctx.globalAlpha = FXMix; ctx.drawImage(video,0, 0, canvas.width, canvas.height); ctx.globalAlpha = 1; ctx.globalCompositeOperation = "source-over"; } } var fill = function(style){ ctx.globalAlpha = FXMix; ctx.fillStyle = style; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.globalAlpha = 1; } var FX = { } var FXList = []; var currentFX = ""; var addFX = function(name,func){ FXList.push(name); FX[name] = func; currentFX = name; } // multiply,screen,overlay,color-dodge,color-burn,hard-light,soft-light,difference,exclusion,hue,saturation,color,luminosity addFX("Ligher",(vid)=>{ addMix("lighter",vid);} ); addFX("BlackWhite",(vid)=>{ ctx.fillStyle = "#888"; addOverlay("color");} ); addFX("Negative",(vid)=>{ ctx.fillStyle = "#FFF"; addOverlay("difference");} ); addFX("Sepia",(vid)=>{ fill("#F94"); addMix("luminosity",vid); ;} ); addFX("B&W Negative",(vid)=>{ ctx.fillStyle = "#FFF"; addOverlay("difference");ctx.fillStyle = "#888"; addOverlay("color");} ); addFX("Ligher+",(vid)=>{ addMix("lighter",vid);addMix("lighter",vid);addMix("lighter",vid);} ); addFX("B&W Lighten",(vid)=>{ addMix("lighter",vid);ctx.fillStyle = "#888"; addOverlay("color");} ); addFX("Darken+",(vid)=>{ addMix("multiply",vid);addMix("multiply",vid);addMix("multiply",vid);} ); addFX("Darken",(vid)=>{ addMix("multiply",vid);} ); addFX("Saturate",()=>{ ctx.fillStyle = "#F00";addOverlay("saturation");}); addFX("None",()=>{}); // end of FX mixing //========================================================================== var mediaSource = "http://video.webmfiles.org/big-buck-bunny_trailer.webm"; var mediaSource = "http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"; var muted = true; var canvas = document.getElementById("myCanvas"); // get the canvas from the page var ctx = canvas.getContext("2d"); var videoContainer; // object to hold video and associated info var video = document.createElement("video"); // create a video element video.src = mediaSource; // the video will now begin to load. // As some additional info is needed we will place the video in a // containing object for convenience video.autoPlay = false; // ensure that the video does not auto play video.loop = true; // set the video to loop. video.muted = muted; videoContainer = { // we will add properties as needed video : video, ready : false, }; // To handle errors. This is not part of the example at the moment. Just fixing for Edge that did not like the ogv format video video.onerror = function(e){ document.body.removeChild(canvas); document.body.innerHTML += "<h2>There is a problem loading the video</h2><br>"; document.body.innerHTML += "Users of IE9+ , the browser does not support WebM videos used by this demo"; document.body.innerHTML += "<br><a href='https://tools.google.com/dlpage/webmmf/'> Download IE9+ WebM support</a> from tools.google.com<br> this includes Edge and Windows 10"; } video.oncanplay = readyToPlayVideo; // set the event to the play function that // can be found below function readyToPlayVideo(event){ // this is a referance to the video // the video may not match the canvas size so find a scale to fit videoContainer.scale = Math.min( canvas.width / this.videoWidth, canvas.height / this.videoHeight); videoContainer.ready = true; // the video can be played so hand it off to the display function requestAnimationFrame(updateCanvas); // add instruction document.getElementById("playPause").textContent = "Click video to play/pause."; document.querySelector(".mute").textContent = "Mute"; } var playClick = false; function updateCanvas(){ ctx.clearRect(0,0,canvas.width,canvas.height); // only draw if loaded and ready if(videoContainer !== undefined && videoContainer.ready){ // find the top left of the video on the canvas video.muted = muted; var scale = videoContainer.scale; var vidH = videoContainer.video.videoHeight; var vidW = videoContainer.video.videoWidth; var top = canvas.height / 2 - (vidH /2 ) * scale; var left = canvas.width / 2 - (vidW /2 ) * scale; // now just draw the video the correct size ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale); FX[currentFX](videoContainer.video); if(videoContainer.video.paused){ // if not playing show the paused screen drawPayIcon(); } overUI = false; cursor = "default"; drawSlider(); drawList(); if(mouse.over){ if(!overUI){ if((mouse.button&1)===1){ // bit field playClick = true; } if((mouse.button&1)===0 && playClick){ // bit field playClick = false; playPauseClick(); } cursor = "pointer"; } } if(showFXName > 0){ showFXName = Math.max(0,showFXName - 0.05); ctx.globalAlpha = Math.min(1,showFXName); ctx.font = "32px Arial"; ctx.textAlign = "center"; ctx.textbaseLine = "middle"; ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.lineJoin = "round" ctx.strokeText(currentFX,canvas.width/2,canvas.height/2); ctx.fillText(currentFX,canvas.width/2,canvas.height/2); ctx.globalAlpha = 1; } canvas.style.cursor = cursor; } // all done for display // request the next frame in 1/60th of a second requestAnimationFrame(updateCanvas); } var showFXName = 0; var cursor = "default"; var overUI = false; var sliderAlpha = 1; var listAlpha = 1; var dragging = false; var listWidth = null; function getMaxListWidth(){ ctx.font = "12px arial"; FXList.forEach(text => {listWidth = Math.max(listWidth,ctx.measureText(text).width)}) } function drawList(){ if(listWidth === null){ getMaxListWidth(); listWidth += 10; } if(!overUI && mouse.over && mouse.x > canvas.width - listWidth){ listAlpha = 1; overUI = true; }else{ listAlpha = Math.max(0,listAlpha - 0.05); } if(listAlpha > 0){ ctx.font = "12px arial"; var textH = 14; var border = 10; ctx.textAlign = "right"; ctx.textBaseline = "middle"; ctx.globalAlpha = listAlpha; ctx.fillStyle = "black"; ctx.strokeStyle = "white"; var len = FXList.length; var h = len * textH; var y = canvas.height / 2 - h/2; var x = canvas.width - border * 2; ctx.fillRect(x - listWidth,y - border, listWidth+border,h + border ); ctx.strokeRect(x - listWidth,y - border, listWidth + border,h + border ); ctx.fillStyle = "white" for(var i = 0; i < len; i ++){ var yy = y + i * textH; if(FXList[i] === currentFX){ ctx.fillStyle = "#0FF"; ctx.fillText(FXList[i],x,yy); ctx.fillStyle = "white" }else if(mouse.x > canvas.width - listWidth && mouse.y > yy - textH/2 && mouse.y < yy + textH /2){ ctx.fillStyle = "#0F0"; ctx.fillText(FXList[i],x,yy); ctx.fillStyle = "white" cursor = "pointer"; if((mouse.button & 1) === 1){ currentFX =FXList[i]; showFXName = 4; } }else{ ctx.fillText(FXList[i],x,yy); } } ctx.globalAlpha = 1; } } function drawSlider(){ if(currentFX === "None"){ sliderAlpha = 0; return; } var cw = canvas.width; var ch = canvas.height; var handle = 5; var inset = 10 var x = inset; var w = cw - inset*2; var h = 20; var y = ch - inset - h; var pos = FXMix * w + x;; if(mouse.y > y - h* 2){ cursor = "e-resize"; overUI = true; if((mouse.button&1) && !dragging){ // bit field dragging = true; } }else{ cursor = "pointer"; } if(dragging){ overUI = true; cursor = "e-resize"; sliderAlpha = 1; pos = mouse.x - x; FXMix = Math.min(1,Math.max(0,pos / w)); if( (mouse.button&1) === 0 ){ //bit field dragging = false; } }else{ } if(!dragging && mouse.y > yh*2 && mouse.over){ sliderAlpha = 1; }else{ if(sliderAlpha > 0){ sliderAlpha = Math.max(0,sliderAlpha- 0.05); } } if(sliderAlpha === 0){ return; } ctx.globalAlpha = sliderAlpha; ctx.font = "18px arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; var amount = FXMix; ctx.fillStyle = "black"; ctx.strokeStyle = "white"; ctx.fillRect(x,y,w,h); ctx.strokeRect(x,y,w,h); ctx.fillStyle = "white"; ctx.fillText(currentFX + " "+ (FXMix * 100).toFixed(0)+"%",w/2,y + h / 2); pos = amount * w + x; ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.fillRect(pos-handle*2,y-handle,handle* 4,h + handle * 2); ctx.strokeRect(pos-handle*2,y-handle,handle* 4,h + handle * 2); ctx.strokeRect(pos-1,y-handle * 0.5,2,h + handle); ctx.globalAlpha = 1; } function drawPayIcon(){ // ctx.fillStyle = "black"; // darken display // ctx.globalAlpha = 0.5; // ctx.fillRect(0,0,canvas.width,canvas.height); ctx.fillStyle = "#DDD"; // colour of play icon ctx.globalAlpha = 0.75; // partly transparent ctx.beginPath(); // create the path for the icon var size = (canvas.height / 2) * 0.5; // the size of the icon ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size); ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size); ctx.closePath(); ctx.fill(); ctx.globalAlpha = 1; // restore alpha } mouse = (function(){ var mouse = { x : 0, y : 0, w : 0, button : 0, over : false, bm : [1, 2, 4, 6, 5, 3], active : false, bounds : null, border : {top : 10, left : 10}, mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,contextmenu".split(",") }; var m = mouse; function mouseMove(e) { var t = e.type; m.bounds = m.element.getBoundingClientRect(); mx = e.clientX - m.bounds.left - m.border.left; my = e.clientY - m.bounds.top - m.border.top; if (t === "mousedown") { m.button |= m.bm[e.which-1]; } else if (t === "mouseup") { m.button &= m.bm[e.which + 2]; }else if (t === "mouseout") { m.button = 0; m.over = false; }else if (t === "mouseover") { m.over = true; } e.preventDefault(); } m.start = function (element) { m.element = element; m.mouseEvents.forEach( n => { m.element.addEventListener(n, mouseMove); } ); m.active = true; //m.border.top = Number(element.style.borderTopWidth.replace(/[a-zA-Z]/g,"")); //m.border.left = Number(element.style.borderLeftWidth.replace(/[a-zA-Z]/g,"")); } m.remove = function () { if (m.element !== undefined) { m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); } ); m.active = false; m.element = undefined; } } return mouse; })(); function playPauseClick(){ if(videoContainer !== undefined && videoContainer.ready){ if(videoContainer.video.paused){ videoContainer.video.play(); }else{ videoContainer.video.pause(); } } } function videoMute(){ muted = !muted; if(muted){ document.querySelector(".mute").textContent = "Mute"; }else{ document.querySelector(".mute").textContent= "Sound on"; } } // register the event //canvas.addEventListener("click",playPauseClick); document.querySelector(".mute").addEventListener("click",videoMute) setTimeout(()=>{mouse.start(canvas)},100); 
 body { font :14px arial; text-align : center; background : #36A; } h2 { color : white; } canvas { border : 10px white solid; cursor : pointer; } a { color : #F93; } .mute { cursor : pointer; display: initial; } 
 <h2>Simple video FX via canvas "globalCompositeOperation"</h2> <p>This example show how to use the 2d context "globalCompositeOperation" property to create a variety of FX. Video may take a few moment to load. </p> <p>Play pause video with click. Move to bottom of video to see FX mix slider (Not available if filter None). Move to right to get filter selection and select the filter example. Happy filtering</p> <canvas id="myCanvas" width = "532" height ="300" ></canvas><br> <h3><div id = "playPause">Loading content.</div></h3> <div class="mute"></div><br> 

Il più semplice è impostare un filter css in scala di grigi sulla canvas.

 var video = document.getElementById("myCanvas"); var button = document.getElementById("myButton"); function grey() { video.className += " greyscale"; } function color() { classGreyscale = video.className.indexOf("greyscale"); if (classGreyscale > 0) video.className = video.className.substring(0, video.className.length - 10) } button.addEventListener('click', function() { color(); }); grey(); 
 .greyscale { -webkit-filter: grayscale(100%); filter: grayscale(100%); } .transition { transition: all 1s; -webkit-transition: all 1s; } 
 <div> <img src="https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png" id="myCanvas" class="transition" /> <br/> <button id="myButton">to Colour</button> </div> 

Versione di saturazione con transizione e transizione -webkit: -webkit-filter 10s;

Questo è solo per Safari e Chrome. Il codice è per la navigazione.

Immagino molto simile a @godzsa

L'altro metodo che posso pensare è quello di creare un div con un indice più alto al di sopra del tuo video con un gioco sulla saturazione bianca.

Per il video Youtube, https://jsfiddle.net/yd215t9p/

E per image,

 div { -webkit-filter:saturate(0.0); -webkit-transition: -webkit-filter 10s; /* Safari */ transition: -webkit-filter 10s; } div:hover { -webkit-filter:saturate(1.0); } 
 <div> <img src="https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png" id="myCanvas" class="transition" /> </div>