Build an animated gif photo booth with HTML5 and JavaScript

I built an animated gif photobooth for the Indeed July 2013 hackathon.

Screen Shot 2013-07-19 at 2.14.51 PM

We got some good shots.

Gif photobeerhighfive

If you just want to run the app, the source is on GitHub: https://github.com/NickCarneiro/gifbooth. There’s no public demo because the code isn’t terribly secure and the images it produces are about 3mb each. But don’t let that stop you from playing with it.

If you want to implement something like this on your own, avoid Flash-based libraries like “jquery-webcam-plugin” or “scriptcam”. They’re a waste of time. New versions of Chrome let you do everything you want through Canvas and WebRTC’s Stream API.

First, read MDN’s excellent article, Taking webcam photos. They have annotated some JavaScript that shows how to grab a frame from a `<video>` stream, write it to a canvas, and `getImageData()` into the src attribute of an image element to display it on the page for a user.

I put some jQuery on top of their code to capture a bunch of frames in quick succession and POST the base-64 encoded data urls to a Flask backend. The Flask view waits until it receives every frame in the set and stitches them together with ImageMagick.

The ImageMagick part is key. PIL and Pillow are huge timesucks for something this simple. ffmpeg is a nightmare. I dare you to look at its man page. If you ever want to create gifs, just use ImageMagick. It’s by far the easiest option.

Anyway, there are a few big issues with this project that are symptomatic of a hackathon. First, it takes a few CPU-intensive milliseconds in between image captures to load the canvas into a data url. This holds up the one and only thread, temporarily locking up the UI and preventing you from having a buttery smooth framerate. You could probably fix this with Web Workers. The other problem is that uploading 15 base64 strings containing medium-sized images takes longer than sending binary data like you would for a multipart/form-data file upload. You could get around this by writing the images to files with the File API and then uploading them from disk. And finally, the batches of images are grouped only by millisecond timestamp, so a unique identifier should be added if you want to get this ready for prime time.