Welcome to a tutorial on how to capture photos with a webcam in Javascript. Yes, the Stone Age of the Internet is long over, and it is totally possible to take pictures directly using Javascript.
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
// WEBCAM STREAM TO VIDEO
let v = document.createElement("video");
v.autoplay = true;
v.srcObject = stream;
// CAPTURE VIDEO FRAME TO CANVAS
v.onloadedmetadata = () => {
let cv = document.createElement("canvas"),
cx = cv.getContext("2d");
cv.width = v.videoWidth; cv.height = v.videoHeight;
cx.drawImage(v, 0, 0, v.videoWidth, v.videoHeight);
};
});
That’s the gist of it – Ask the user for permission to access the camera, feed the live stream into a video, then capture a video frame onto a canvas. But how do we “save” the photo? Read on for a detailed example.
TABLE OF CONTENTS
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
EXAMPLE CODE DOWNLOAD
Source code on GitHub Gist | Example on CodePen
Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
JAVASCRIPT WEBCAM CAPTURE
All right, let us now get into the steps and example of how to take a photo with Javascript.
TUTORIAL VIDEO
PART 1) THE HTML
<!-- (A) VIDEO LIVE FEED -->
<video id="cam-live" autoplay></video>
<!-- (B) CONTROLS -->
<div id="cam-controls">
<input type="button" id="cam-take" class="material-icons"
value="photo_camera" onclick="webcam.take()" disabled>
<input type="button" id="cam-save" class="material-icons"
value="download" onclick="webcam.save()" disabled>
<input type="button" id="cam-upload" class="material-icons"
value="upload" onclick="webcam.upload()" disabled>
</div>
<!-- (C) SNAPSHOTS -->
<div id="cam-snaps"></div>
Just a simple HTML interface with only a few components:
<video id="cam-live">
is where we will “live stream” the webcam.- As in the introduction, “taking a photo” is simply capturing a frame of the
<video>
into a<canvas>
. Here are 3 possible ways to deal with “save”.- Simply insert the
<canvas>
into the HTML page. - Force download as an image file.
- Upload the image to the server.
- Simply insert the
- An empty area to insert the
<canvas>
.
PART 2) INITIALIZE WEBCAM
// (A) INITIALIZE - GET USER PERMISSION TO ACCESS CAMERA
hVid : null, hSnaps :null,
init : () => {
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
// (A1) GET HTML ELEMENTS
webcam.hVid = document.getElementById("cam-live"),
webcam.hSnaps = document.getElementById("cam-snaps");
// (A2-1) "LIVE FEED" WEB CAM TO <VIDEO>
webcam.hVid.srcObject = stream;
// (A2-2) ENABLE BUTTONS
document.getElementById("cam-take").disabled = false;
document.getElementById("cam-save").disabled = false;
document.getElementById("cam-upload").disabled = false;
})
.catch(err => console.error(err));
}
window.addEventListener("load", webcam.init);
On window load, webcam.init()
will get the user’s permission to access the webcam – navigator.mediaDevices.getUserMedia({ video : true })
; We proceed to “enable” the app only when permission is granted.
- (A1) Self-explanatory, get the HTML elements.
- (A2) Feed the webcam live stream into the HTML video –
webcam.hVid.srcObject = stream;
- (A3) Enable all the controls.
Take note that getUserMedia()
requires https://
to work properly, http://localhost
is an exception for testing. Also, if the user denies permission, getUserMedia()
will not prompt anymore. You will have to serve your own “how to manually give permission” notice in catch()
.
PART 3) TAKE A SNAPSHOT
// (B) SNAP VIDEO FRAME TO CANVAS
snap : () => {
// (B1) CREATE NEW CANVAS
let cv = document.createElement("canvas"),
cx = cv.getContext("2d");
// (B2) CAPTURE VIDEO FRAME TO CANVAS
cv.width = webcam.hVid.videoWidth;
cv.height = webcam.hVid.videoHeight;
cx.drawImage(webcam.hVid, 0, 0, webcam.hVid.videoWidth, webcam.hVid.videoHeight);
// (B3) DONE
return cv;
},
As in the introduction, this is how we “take a photo” with the webcam.
- Basically, create an HTML canvas –
cv = document.createElement("canvas");
- Get the 2D context –
cx = cv.getContext("2d");
- Draw the current video frame onto the canvas –
cx.drawImage(VIDEO, 0, 0, VID-WIDTH, VID-HEIGHT);
PART 4) “SAVE” THE PHOTO
4A) INSERT INTO HTML PAGE
// (C) PUT SNAPSHOT INTO <DIV> WRAPPER
take : () => webcam.hSnaps.appendChild(webcam.snap()),
This is the easiest way to deal with the snapshot… Just insert it into the HTML page somewhere.
4B) FORCE DOWNLOAD
// (D) FORCE DOWNLOAD SNAPSHOT
save : () => {
// (D1) TAKE A SNAPSHOT, CREATE DOWNLOAD LINK
let cv = webcam.snap(),
a = document.createElement("a");
a.href = cv.toDataURL("image/png");
a.download = "snap.png";
// (D2) "FORCE DOWNLOAD" - MAY NOT ALWAYS WORK!
a.click(); a.remove(); cv.remove();
// (D3) SAFER - LET USERS MANUAL CLICK
// webcam.hSnaps.appendChild(a);
}
Optionally, we can do a “force download” on the snapshot.
- Create an HTML anchor link –
a = document.createElement("a")
. - Attach the canvas data URL into the anchor tag –
a.src = cv.toDataURL("image/png")
. - Finally, a neat trick is to do an
a.click()
to offer “save as”. But take note, this may not always work due to security constraints. - The safer way is to attach the link to the HTML page and let the user manually click to download.
4C) UPLOAD SNAPSHOT
// (E) UPLOAD SNAPSHOT TO SERVER
upload : () => {
// (E1) APPEND SCREENSHOT TO DATA OBJECT
var data = new FormData();
data.append("snap", webcam.snap().toDataURL("image/jpeg", 0.6));
// (E2) UPLOAD SCREENSHOT TO SERVER
fetch("save.php", { method:"post", body:data })
.then(res => res.text())
.then(txt => alert(txt));
}
Finally, upload the snapshot to the server.
// https://netcell.netlify.com/blog/2016/04/image-base64.html
// (A) BASE64 DECODE UPLOADED IMAGE
$data = explode(",", $_POST["snap"]);
$data = base64_decode($data[1]);
// (B) SAVE IMAGE
$file = fopen("snap.jpg", "w");
fwrite($file, $data);
fclose($file);
echo "OK";
On the server, just do a base 64 decode and save the uploaded snapshot. This one is in PHP, but you can pretty much “translate” this into any other language.
EXTRAS
That’s all for this project, and here is a small section on some extras and links that may be useful to you.
COMPATIBILITY CHECKS
- Arrow Functions – CanIUse
- Get User Media – CanIUse
- Set SRC Object – CanIUse
Works well on all “Grade A” major browsers.
LINKS & REFERENCES
- JS Offline Camera Progressive Web App – Code Boxx
- Get User Media – MDN
- Get Context – MDN
- Draw Image – MDN
- To Data URL – MDN
- Canvas to BLOB – MDN
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
This is by far the most excellent tutorial blog I have ever visited. Bookmarked for future visits.
Thanks, bro! ))
Can you please send the code such that the captured screenshot can be shown on one part of the html page as soon as screenshot button will be clicked?
As above,
1-basics.html
.