Create a Browser-Based Photobooth with JavaScript, PHP and Twilio

March 27, 2015
Written by

h&r-3 (2)

On one of the first dates I went on with my wife Hannah we stopped at a photobooth and snapped a collection of silly pictures. Those pictures are still some of my favorites we’ve taken together. Eight years later and we still try to stop at photobooths whenever we see them. But I always have one feature request when I use a photobooth, I wish they could deliver the pictures directly to my phone. Thankfully, we live in a world where the power to create new user experiences is quickly shifting to software people and it is no different with photobooths. We’re going to build a browser based photobooth that implements the one feature I’ve always wanted – it will deliver photos to our phone via MMS. All thanks to the power of JavaScript, PHP and Twilio. You can see the final product in action here.

Prerequisites

There are couple things we’ll need to set up before we start building our application:

We’ll be using a handful of other technologies as we build our application but we’ll walk you through setting up each one throughout this post:

  • getUserMedia – this will allow us to capture the camera stream from our browser.
  • Google’s Adapter.js
  • Bootstrap – To make things a little prettier.
  • jQuery
  • Twilio-php library – to easily send our MMS from PHP.

Mirror Mirror On The Wall

Before we start building, let’s talk a bit about WebRTC. WebRTC (Web Real-Time Communication) makes it easy for developers to build peer-to-peer native browser video, audio and data applications using JavaScript APIs. Since we’re not connecting peers in the application we’re building today wouldn’t be considered a WebRTC application. But we’ll be using the getUserMedia JavaScript API which is one of the building blocks of WebRTC.

Now the party starts and it’s time to build our app. Make a new directory on your PHP server called photobooth. We’ll be writing all of our code in the photobooth directory. Let’s start by building out our initial HTML in index.html:

<!doctype html>
<html>
 <head>
   <title>Photobooth</title>
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
 </head>
 <body>
   <div>
     <h1>Photobooth</h1>
     <video autoplay></video>
   </div>
 <body>
</html>

You’ll notice we’re keeping it basic at first. In the head we add bootstrap so that our page can be a bit prettier. Then in the body we just have three elements:

  • a
    with the class “container” which will help things style nicely
  • an

    so people know they’re visiting our WebRTC powered Photobooth

  • A element that will house the stream from our webcam.

At the end of the body we can add the JavaScript files we’ll be using initially:


 <body>
   <div>
     <h1>Photobooth</h1>
     <video id="webcam-video" autoplay></video>
   </div>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
   <script src="app.js"></script>
 <body>

Now let’s create our app.js and write the code to stream the video to the browser:

var PhotoBooth = {
 onMediaStream: function (stream) {
   PhotoBooth.localVideo = $('video')[0];
   PhotoBooth.localVideo.src = window.URL.createObjectURL(stream);
 },
 noStream: function() {
   console.log('oh no!');
 }
};

getUserMedia(
 {video: true},
 PhotoBooth.onMediaStream,
 PhotoBooth.noStream
);

We’re using the getUserMedia WebRTC API to get our video stream. When we successfully get the media we’re setting the source of our video element to a URL related to that stream. We’re namespacing things to PhotoBooth to avoid polluting the global namespace.

Before we can view this page, we need to add Google’s adapter.js to our project. Download the file and put it in your photobooth directory.

Now we can add it at the bottom of our HTML right before we import our app.js:


   <script src="adapter.js"></script>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
   <script src="app.js"></script>
 <body>

Now that we’ve got everything in place, open up your browser (Chrome, Opera or Firefox since we’re using WebRTC) and load up the webpage in your browser. You’ll be prompted to give this page permissions to use your camera. In chrome the prompt will look like this:

In Firefox it will look like this:

If you’re running this page via HTTPS users will have the opportunity to remember this permission. Once you grant permissions, you should be seeing your beautiful face.

Pictures of You and I, They Always Make Me Smile

Now that we’re streaming the video to our page, we need to add the code that captures an image still from this stream. In index.html add a


     <video id="webcam-video" autoplay></video>
     <div style="float: right; display: none;" id="preview">
       <canvas></canvas><br />
     </div><br />
     <button id="takePicture">Take Picture</button>

In order to take our picture, we need to add few pieces of code to app.js. First, we need to get our canvas element and context in our onMediaStream function:


 onMediaStream: function (stream) {
   PhotoBooth.canvas = $('canvas')[0];
   PhotoBooth.context = PhotoBooth.canvas.getContext('2d');

   PhotoBooth.localVideo = $('video')[0];
   PhotoBooth.localVideo.src = window.URL.createObjectURL(stream);
 }

Next we’ll write the function that actually takes our picture when we click the takePicture button:

$('#takePicture').click( function() {
   PhotoBooth.context.drawImage(PhotoBooth.localVideo, 0, 0, 200, 150);
   $('#preview').show();
});

Now that we have our code in place you can hop back to your browser, refresh the page and say “cheese!”.

You may have noticed this picture ended up capturing an awkward moment of when you click the button. This is the image it grabbed for me[link]. In true photobooth fashion, let’s add a simple 3 second countdown so the picture isn’t taken immediately. Add a new div to our HTML to contain our countdown:


 <body>
    <div class="countdown">
    </div>
    <div class="container">

We’ll need to add a few styles to make our countdown display correctly. To help keep our code clean let’s add an app.css stylesheet:


<head>
<title>Photobooth</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<link rel="stylesheet" href="app.css">
</head>

Now create app.css and add the following styles for countdown:

.countdown {
  display: none;
  width: 100%;
  height: 100%;
  position: absolute;
  background-color: rgba(0,0,0,0.5);
  text-align: center;
  vertical-align: middle;
  color: white;
  font-size:120px;
}

Now we can go into our app.js file, write the countdown function and add it to takePicture


function countdown(seconds) {
  var countdownDiv = $('.countdown');
  if(seconds == 0) {
    countdownDiv.hide();
    return;
  }

  countdownDiv.html(seconds);
  seconds--;
  setTimeout(function() { countdown(seconds) }, 1000);
}

$('#takePicture').click( function() {
  $('.countdown').show();
  countdown(3);

  setTimeout(function() {
    PhotoBooth.context.drawImage(PhotoBooth.localVideo, 0, 0, 200, 150);
    $('#preview').show();
  }, 3000);
});

Test it again! Ah, what a beautiful countdown.

Sharing is Caring

We’re now getting the video stream from our webcam, capturing a still image from it. The last piece of the puzzle is to send this image to a phone number via MMS using Twilio. Let’s start by updating our front-end to have a for phone number and a


<div style="float: right; display: none;" id="preview">
  <canvas></canvas><br />
  Phone Number: <input id="phoneNumber"></input><br />
  <button id="sharePicture">Share Picture</button>
</div><br />

Now in app.js we can write the code that will make an AJAX request to our our server (share.php) with our phone number and the image data when someone clicks our sharePicture button:

$('#sharePicture').click( function() {
  var dataURL = PhotoBooth.canvas.toDataURL();
  var data = {
    phoneNumber: $('#phoneNumber').val(),
    image: dataURL
  };
  $.post(
    'share.php',
    data,
    function(resp, status) {
      alert("You should receive your picture in a few minutes");
  });
});

Before we start writing our backend code to save this image and send it in an MMS, we need to create an /images directory so we have someplace to save our images:

mkdir images

Now we can create share.php and write the code that saves our image to that directory:

<?php

define('UPLOAD_DIR', 'images/');
$img = $_POST['image'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);

Let’s test this. Go back to your browser, refresh your page and give your share picture button a click. Now take a look in your images directory to ensure the image has been saved. If it hasn’t, make sure your web server has permissions to write to the images folder.

Now that we’ve got our button wired up and we’re saving our file we’re ready to send our MMS. Let’s download the twilio-php helper library and put it in the same directory as our website.

Require the library in share.php, instantiate our client and call sendMessage function to send our message:


<?php

require_once('twilio-php-master/Services/Twilio.php');

define('UPLOAD_DIR', 'images/');
$img = $_POST['image'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);

$url = 'http://yourdomain.com/' . $file;

$AccountSid = "YOURTWILIOACCOUNTSID";
$AuthToken = "YOURTWILIOAUTHTOKEN";

$client = new Services_Twilio($AccountSid, $AuthToken);

$sms = $client->account->messages->sendMessage(
  "+15555555555", // Your Twilio number
  $_POST['phoneNumber'],
  "When it's time to party we will party hard!",
  $url
);

?>

Make sure to plug in your Twilio Account SID and Auth Token (you can find these on your Twilio account dashboard), Twilio phone number and the url for your application. It’s important to note that the image URL has to be publicly accessible. If you’re running your app on localhost make sure to use a tool like ngrok to expose it to the outside world.

Go back to your web page, refresh and give it one more try. This time after you take the picture, punch in your phone number and share the picture to your phone. Within just a couple minutes you should get an MMS with your picture!

When It’s Time To Party We Will Party Hard

The one feature I’ve been wanting for years! We now have a browser based photobooth where everyone can get their pictures immediately via MMS. You can find the final version of this code on github and debut it at your next party.

Now that you’ve learned about getUserMedia you’re ready to dive into WebRTC. Check out this blog post from my colleague Phil Nash that shows you how to build a peer to peer video chat application with WebRTC. Or join us at our conference, Signal, in May where we’ll be talking about modern software development (including WebRTC!). Use promo code ROBINETT20 for 20% off your ticket.

Have questions or want to share something rad you’ve built with Twilio? Holler at me on twitter (@rickyrobinett) or e-mail (ricky@twilio.com)