Today I want to show you how you can add filters to the video of your web camera or edit the video with the canvas html element
The first thing we need to do is to display the web camera on a video element and then view frame by frame the video element on canvas element.
I already have written an article on how to Display web camera on canvas element , so lets start coding from there.
First lets add a dropdown with the filters available. All filters available for canvas context are here mdn
Add this block of element at index.html:
<div class="dropdown" id="filterselect">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1"
data-bs-toggle="dropdown" aria-expanded="false">
Filter
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li><a class="dropdown-item" value="none">No filter</a></li>
<li><a class="dropdown-item" value="blur(8px)" >Blur</a></li>
<li><a class="dropdown-item" value="contrast(50%)" >Contrast</a></li>
<li><a class="dropdown-item" value="grayscale(100%)" >Grayscale</a></li>
<li><a class="dropdown-item" value="sepia(100%)" >Sepia</a></li>
</ul>
</div>
We wont use all available filters, only blur , sepia , contrast and grayscale.
Next let's add an eventlistener at index.js
var filter=''
filterselect.addEventListener('click', (event) => {
if(event.target.getAttribute('value')){
filter=event.target.getAttribute('value')
}
});
Code explanation:
A filter variable is defined so it is assigned on filter property of context object. Then the value attribute is being assigned on filter variable.
Next step is to apply the filter in context.
Add ctx.filter=filter to drawimage function:
function drawImage(video) {
ctx.drawImage(video, 0, 0, canvaselement.width, canvaselement.height);
ctx.filter = filter
}
We can also add text to our canvas video.
First lets add an input at input.html element so we can dynamically change the text:
<label for="exampleInput" class="form-label">Text</label>
<input class="form-control" id="exampleInput">
<br>
Edit index.js like this:
var canvastext=''
function drawImage(video) {
ctx.drawImage(video, 0, 0, canvaselement.width, canvaselement.height);
ctx.filter = filter
ctx.font = "50px Arial";
ctx.fillText(canvastext, 50, 50);
}
Then add input event listener on input element:
`
var canvastextinput=document.querySelector("#canvastext")
canvastextinput.addEventListener('input',(event=>{
canvastext=event.target.value
}))
The final files are like this:
index.html
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- Bootstrap CSS --> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" | |
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> | |
<title>Video on canvas</title> | |
</head> | |
<body> | |
<video autoplay playsinline webkit-playsinline muted hidden id="videoelement"></video> | |
<div class="container"> | |
<div class="dropdown" id="filterselect"> | |
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" | |
data-bs-toggle="dropdown" aria-expanded="false"> | |
Filter | |
</button> | |
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1"> | |
<li><a class="dropdown-item" href="#" value="none">No filter</a></li> | |
<li><a class="dropdown-item" href="#" value="blur(8px)">Blur</a></li> | |
<li><a class="dropdown-item" href="#" value="contrast(50%)">Contrast</a></li> | |
<li><a class="dropdown-item" href="#" value="grayscale(100%)">Grayscale</a></li> | |
<li><a class="dropdown-item" href="#" value="sepia(100%)">Sepia</a></li> | |
</ul> | |
</div> | |
<label for="exampleInput" class="form-label">Text</label> | |
<input class="form-control" id="canvastext"> | |
<br> | |
<canvas id="canvaselement" width="1920" height="1080" style="max-width: 100%;height: auto;"></canvas> | |
</div> | |
<script src="index.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" | |
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" | |
crossorigin="anonymous"></script> | |
</body> | |
</html> |
index.js
var videoelement = document.getElementById("videoelement"); | |
var streamContraints = { | |
audio: true, | |
video: { width: 1920, height: 1080 }, | |
}; | |
var canvaselement = document.querySelector('#canvaselement'); | |
var filterselect = document.querySelector('#filterselect') | |
var canvastextinput=document.querySelector("#canvastext") | |
var ctx = canvaselement.getContext('2d', { alpha: false }); | |
var canvasInterval = null; | |
var fps = 60 | |
var filter = '' | |
var canvastext='' | |
if (videoelement) { | |
navigator.mediaDevices | |
.getUserMedia(streamContraints) | |
.then(gotStream) | |
.catch(function (e) { | |
if (confirm("An error with camera occured:(" + e.name + ") Do you want to reload?")) { | |
location.reload(); | |
} | |
}); | |
} | |
//if stream found | |
function gotStream(stream) { | |
videoelement.srcObject = stream | |
videoelement.play() | |
} | |
function drawImage(video) { | |
ctx.drawImage(video, 0, 0, canvaselement.width, canvaselement.height); | |
ctx.filter = filter | |
ctx.font = "50px Arial"; | |
ctx.fillText(canvastext, 50, 50); | |
} | |
canvasInterval = window.setInterval(() => { | |
drawImage(videoelement); | |
}, 1000 / fps); | |
filterselect.addEventListener('click', (event) => { | |
if(event.target.getAttribute('value')){ | |
filter=event.target.getAttribute('value') | |
} | |
}); | |
canvastextinput.addEventListener('input',(event=>{ | |
canvastext=event.target.value | |
})) |
Thanks for your time.
Leave a question or comment below.
Top comments (0)