Capturar fotografías con la cámara web

Introducción y demostración

Este es un tutorial rápido de cómo acceder a la cámara de tu laptop y capturar una foto con ella. Puedes observar el código final en acción en este JSFiddle. También existe una versión más avanzada en JavaScript para cargar fotos a imgur disponible como código en GitHub o como demo.

El formato HTML

Lo primero que necesitas para acceder a la cámara web utilizando WebRTC es un elemento <video> y un elemento <canvas> en la página. El elemento de video recibe la secuencia desde WebRTC y el elemento canvas es utilizado para agarrar la imagen desde el video. También añadimos una imagen de relleno que luego será reemplazada con la toma capturada por la cámara web.

html
<video id="video"></video>
<button id="startbutton">Take photo</button>
<canvas id="canvas"></canvas>
<img src="http://placekitten.com/g/320/261" id="photo" alt="photo" />

El script completo

Aquí se muestra completamente el código JavaScript. Más abajo, explicaremos gradualmente cada sección con más detalle.

js
(function () {
  var streaming = false,
    video = document.querySelector("#video"),
    canvas = document.querySelector("#canvas"),
    photo = document.querySelector("#photo"),
    startbutton = document.querySelector("#startbutton"),
    width = 320,
    height = 0;

  navigator.getMedia =
    navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia;

  navigator.getMedia(
    {
      video: true,
      audio: false,
    },
    function (stream) {
      if (navigator.mozGetUserMedia) {
        video.mozSrcObject = stream;
      } else {
        var vendorURL = window.URL || window.webkitURL;
        video.src = vendorURL.createObjectURL(stream);
      }
      video.play();
    },
    function (err) {
      console.log("An error occured! " + err);
    },
  );

  video.addEventListener(
    "canplay",
    function (ev) {
      if (!streaming) {
        height = video.videoHeight / (video.videoWidth / width);
        video.setAttribute("width", width);
        video.setAttribute("height", height);
        canvas.setAttribute("width", width);
        canvas.setAttribute("height", height);
        streaming = true;
      }
    },
    false,
  );

  function takepicture() {
    canvas.width = width;
    canvas.height = height;
    canvas.getContext("2d").drawImage(video, 0, 0, width, height);
    var data = canvas.toDataURL("image/png");
    photo.setAttribute("src", data);
  }

  startbutton.addEventListener(
    "click",
    function (ev) {
      takepicture();
      ev.preventDefault();
    },
    false,
  );
})();

Explicando paso a paso

Entonces, ¿Qué es lo que sucede aquí? Lo analizaremos paso por paso.

Función Anónima

js
(function() {

  var streaming = false,
      video        = document.querySelector('#video'),
      canvas       = document.querySelector('#canvas'),
      photo        = document.querySelector('#photo'),
      startbutton  = document.querySelector('#startbutton'),
      width = 320,
      height = 0;

Empezamos por encerrar el script entero en una función anónima para evitar las variables globales. Tomamos los elementos HTML que necesitamos y definimos el ancho (width) del video a 320 y la altura (height) a 0, ya que calcularemos la altura apropiada posteriormente.

Advertencia: En estos momentos existe una diferencia entre los tamaños de video proporcionados por getUserMedia. Firefox Nightly utiliza una resolución de 352x288 y Opera y Chrome utiliza una resolución de 640x400. Esto cambiará en el futuro, pero cambiando el tamaño con la proporción que usaremos más abajo, nos aseguraremos de no obtener sorpresas desagradables.

Obtener el video

Ahora necesitamos obtener el video desde la cámara web. Actualmente esto está predeterminado para los diferentes navegadores, así que necesitamos comprobar cuál es compatible:

js
navigator.getMedia =
  navigator.getUserMedia ||
  navigator.webkitGetUserMedia ||
  navigator.mozGetUserMedia ||
  navigator.msGetUserMedia;

Le solicitamos al navegador que nos dé un video sin audio y obtenemos una secuencia (stream) en la función de retrollamada:

js
navigator.getMedia(
  {
    video: true,
    audio: false,
  },
  function (stream) {
    if (navigator.mozGetUserMedia) {
      video.mozSrcObject = stream;
    } else {
      var vendorURL = window.URL || window.webkitURL;
      video.src = vendorURL.createObjectURL(stream);
    }
    video.play();
  },
  function (err) {
    console.log("An error occured! " + err);
  },
);

En estos momentos Firefox Nightly necesita que tu configures la propiedad de mozSrcObject del elemento del video con el fin de reproducirlo; para otros navegadores, configura el atributo src. Mientras que Firefox puede utilizar la secuencia de video directamente, Webkit y Opera necesitan crear un objeto URL desde ella. Todo esto será estandarizado en un futuro cercano.

Redefinir el tamaño del video

Luego necesitamos configurar el tamaño del video a las dimensiones deseadas.

js
video.addEventListener(
  "canplay",
  function (ev) {
    if (!streaming) {
      height = video.videoHeight / (video.videoWidth / width);
      video.setAttribute("width", width);
      video.setAttribute("height", height);
      canvas.setAttribute("width", width);
      canvas.setAttribute("height", height);
      streaming = true;
    }
  },
  false,
);

Nos subscribimos al evento canplay del video y leemos sus dimensiones utilizando videoHeight y videoWidth. Estas no están disponible realmente hasta que el evento sea iniciado. Establecemos streaming a verdadero (true) para que compruebe esto solo una vez, mientras que el evento canplay siga en actividad.

Esto es todo lo que se necesita para que inicie el video.

Capturar una imagen

Ahora necesitamos capturar una imagen utilizando un lienzo (canvas). Asignamos un manejador de eventos al botón de inicio para llamar a la función de takepicture.

js
startbutton.addEventListener(
  "click",
  function (ev) {
    takepicture();
    ev.preventDefault();
  },
  false,
);

En esta función, reestablecemos el tamaño del lienzo (canvas) a las dimensiones del video, el cual lo sustituye y tenemos un marco del video, el cual se copia al canvas. Luego necesitamos convertir los datos del canvas en datos tipo URL con un encabezado PNG, y establecer el src de la fotografía a este mismo url.

js
  function takepicture() {
    canvas.width = width;
    canvas.height = height;
    canvas.getContext('2d').drawImage(video, 0, 0, width, height);
    var data = canvas.toDataURL('image/png');
    photo.setAttribute('src', data);
  }

})();

Eso es todo lo que se necesita para mostrar la secuencia de la cámara web y capturar una imagen fija de ella, a través de Chrome, Opera y Firefox.

Compatibilidad

Actualmente utilizar WebRTC para acceder a la cámara es compatible en Chrome, Opera y Firefox Nightly 18. Para habilitar WebRTC en Firefox Nightly requiere que establezcas un indicador en la configuración:

  • Teclea "about:config" en la barra de direcciones y afirma que quieres realizar algunos cambios.
  • Encuentra la entrada "media.navigator.enabled" y establécelo a verdadero (true).