How To: Take Webcam Pictures from the Browser and Store them Server-Side

How To: Take Webcam Pictures from the Browser and Store them Server-Side


A project I was working on recently on required the ability to take pictures from the browser via webcam and store them somewhere to be later accessed/displayed. I had more or less no idea how to do any of this, so I turned to the wonderful Google machine for answers. What I found was fragmentary at best; there didn’t appear to be a good front-to-back tutorial on how to:

  1. Access the webcam in-browser via Javascript;
  2. Take a picture via the webcam;
  3. Send the picture data to the server, and finally;
  4. Store the picture data server-side in some reasonable way

After playing around with it for a few hours, I came up with what I think is a sensible end-to-end solution, which I’ll describe here. Hopefully it’ll save you some time if you have a project with similar requirements.


Step 1: Accessing the Webcam

The first step in this process is acquiring access to the user’s webcam from the browser. Just a few years ago, you would have had to resort to something like Flash to achieve this. Nowadays, support for in-browser webcam access is somewhat more standardized than that. The key is a new function, called navigator.getUserMedia, that allows your web application to take control of the user’s webcam (with his/her permission).

Support for getUserMedia is still fragmented, with different browsers providing their own vendor-specific versions of the relevant functionality. In order to standardize across these differences, the first thing you want to do is set up some aliases, like so:

navigator.getUserMedia

navigator.getUserMedia

This will allow us to refer to navigator.getUserMedia in a unified way across the major browsers (Chrome, Firefox, IE)1. Now we can use getUserMedia to request access to the user’s webcam:

Using navigator.getUserMedia

Using navigator.getUserMedia

getUserMedia accepts an options parameter, which we set to { video: true }, and a callback which will fire when the user’s webcam has been acquired. Our logic for using the webcam will go in this callback.

At this point, we have access to the user’s webcam. The next step is to figure out how to do anything useful with it.


Step 2: Taking Pretty Pictures

This is where things get a little funky. Our goal is to use the webcam to take a picture, but what we’ve done so far has actually initialized the camera to start taking video. This is because there is no way to acquire the webcam in “picture mode”; instead, you have to use the webcam as a video device and manually pluck a frame out of the video and use it as your picture.

The steps for doing this are a bit convoluted. In brief, we must:

  1. Send the webcam’s output to an HTML video element
  2. Take a frame from the video and draw it on a canvas element
  3. Do stuff with the image data stored in the canvas (this will be the next section)
  4. The first step is to send the camera’s output to an HTML video element. It doesn’t matter much where this video element comes from: it can either exist explicitly in your HTML, or you can create it on the fly via Javascript. If you want to display the video to the user, the former makes more sense; if you’re only using the video as an intermediate step to taking a picture, then you should go with the latter. It often makes sense to display the video to the user first so that he/she can see what the picture will look like, but this is up to you.

    Let’s assume you’re using an existing video element with its id attribute set to myVideo. In this case, the code to retrieve the element and set it to receive input from the webcam looks like this:

    Using navigator.getUserMedia

    Using navigator.getUserMedia

    An important note here is that, like getUserMedia, window.URL is not supported uniformly across all browsers. In order to safely access it like in the above snippet, you’ll have to set up aliases like we did for getUserMedia, like this: window.URL = (window.URL || window.mozURL || window.webkitURL).

    At this point, your webcam’s video should be streaming real-time into your video element, which is pretty neat. Next, we need to take a frame of the video and send it to a canvas element. Like before, it doesn’t matter where this element comes from. If you want your users to be able to see the picture, use an existing canvas; otherwise, create a hidden one on the fly using Javascript. We’ll assume again that you’re using an existing element, in which case the code to capture the picture looks like this:

    Capturing video frame to canvas

    Capturing video frame to canvas

    The new parts of this function are towards the bottom. The important line is canvas.getContext('2d').drawImage(video, 0, 0). This is where the video frame is sent to the canvas, i.e. where the picture is taken.

    In real-world use, the logic to send video input to a video element and the logic to take a snapshot of this video and send it to a canvas will often be separated. A common situation might be displaying the video input to the user and allowing him/her to click a button to take a snapshot from the video. In this case, the only changes that need to be made to the above code would be to separate the logic in the setTimeout callback into a separate function which would be triggered by a button click. Everything else would work the same way.


    Step 3: Sending the Image to the Server

    Now we have an image stored in a canvas element somewhere in our page. So how do we get it to the server?

    The first step is to extract the image data from the canvas as a string. We do this with the toDataURL function, seen below. Once we have the image data as a string, all that remains is to clean it up a bit (the string contains some extraneous data at the beginning that isn’t useful to us) and then send it to the server using AJAX. The whole process looks like this:

    Extracting image data and sending to server

    Extracting image data and sending to server

    Note a few things here:

    1. The image is formatted as a .PNG file, as specified in canvas.toDataURL("img/png"). Other formats are available too, like "image/jpeg"
    2. The image data is base-64 encoded. We will need to keep this in mind when we use it server-side
    3. We POST the image as a parameter in a JSON-encoded object here, but you could POST the image string directly if you want. It just depends on how your server is looking to receive the data

    And that’s it on the client side! For your convenience, here’s the entirety of the Javascript code, from acquiring the webcam to posting the image data to the server:

    Full example

    Full example


    Step 4: Persisting the Image Server-Side

    Almost done! All that’s left is to receive the image data on the server and store it in some sensible way. The code in this section will be specific to C# and ASP.NET Web API, but the concepts will work for other languages/frameworks as well.

    The first thing we have to do is receive the image data in our controller. Since this isn’t a tutorial about Web API, we won’t go over how to do this here2. Instead, let’s just assume you’ve already received the image data in your controller, and you have it stored in a string variable called imageData.

    In order to use the data sent from the client, we have to first decode it. Remember how canvas.toDataURL returned a base-64 encoded string? Now we have to decode it into an array of bytes so we can store it as an image file. In C#, this is as simple as var bytes = Convert.FromBase64String(imageData). Then we serialize the byte array into a stream so it can be saved as an image file. In C#, the whole process looks like this:

    Serialize image data to stream

    Serialize image data to stream

    And at this point, we’re pretty much done. The image data is serialized into a stream and ready to be written to an image file. The only thing left to do is save it somewhere, and here we’re faced with a choice:

    One way to persist image data would be to save it directly to the server’s file system. Another way would be to store it in the cloud via something like Amazon S3 or Windows Azure. Both schemes have their pros and cons. In either case, I would recommend abstracting the actual persistence logic into some sort of Repository class that handles storing and retrieving the data. This way you can switch between storage schemes without changing the code that accesses the image data. I’ve created both a file-system implementation and an Azure-based implementation in my Repository library which might be useful here, but feel free to implement the persistence logic in any way you see fit.

    Conclusion

    And we’re done! If you follow these steps, you’ll be able to capture images from the browser via webcam and send them to the server to be saved. I hope you find this useful. If you have any questions or feedback, just leave them in the comments or email me and I’ll get back to you as soon as possible.

    And as always, happy coding!



    1: Not all browsers yet support getUserMedia; check here to see which ones do and which ones don’t.
    2: Take a look here to get an idea of how this works if you’re unfamiliar with Web API.

Leave a Reply