Acceso a la cámara con HTML5

Hasta hace poco la única forma de acceder a la cámara web desde HTML era por medio de flash o instalando algún plugin específico al navegador. Recientemente, gracias a los esfuerzos de los miembros de la W3C, ahora contamos con nuevas etiquetas HTML5 que definen un mecanismo estándar para hacer tareas complejas como esta de forma simple. La influencia de la W3C en la estandarización de tecnologías web poco a poco a logrado que el diseño y la programación web sea más fácil para nosotros y accesible para los usuarios.
Primero hablemos un poco sobre videos: HTML5 define la etiqueta video que nos permite cargar un video, del mismo modo que la etiqueta img nos permite ver una imagen en HTML. Por si misma, la etiqueta video es suficientemente versátil para mostrar un video (en navegadores con soporte HTML5):
1
2
3
4
5
6
7
8
<!-- Etiqueta básica -->
<video src="PinturaSecandose.mp4" ></video>
<!-- Etiqueta con imagen fija más dos formatos de video -->
<video poster="brocha.jpg" width="480px" height="360px">
    <source src="PinturaSecandose.mp4" type="video/mp4">
    <source src="PinturaSecandose.webm" type="video/webm">
</video>
Muy versátil, ¿no? Ahora todos tus amigos podrán ver el video de 4h de la pintura de tu cocina secándose, mientras tu grabas otro emocionante video de tu gato durmiendo. Pero, ¿que tiene que ver esto con la cámara web? La etiqueta video requiere un archivo de video ya grabado ¿o no?… pues no, no tiene porque ser un video pregrabado.

Conectando tu webcam a la etiqueta Video

Bueno, vamos a hacer esto rápido. Antes que nada te explico que el acceso a la cámara está, por ahora, limitado a unos pocos navegadores: Opera (desktop y móvil) desde la versión 12, Chrome desde la versión 21, Firefox desde la versión 18 (disponible desde finales de octubre/2012), y leí por ahí que posiblemente IE lo soporte desde la versión 11; con esto en poco tiempo tendremos soporte en los principales navegadores. Un detalle más: la página debes abrirla desde un servidor web para poder acceder a la cámara de tu equipo. Puedes instalar Apache u otro servidor para hacer pruebas localmente (mira en mi post anterior sobre como instalarlo en ubuntu), o abre el ejemplo en jsFiddle con el link que está al final del post.
Comencemos con un poco de HTML y CSS para preparar nuestra página web:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Prueba de cámara Web</title>
    <script type="text/javascript" src="jquery-1.8.2.min.js"></script>
    <style type="text/css">
        .contenedor{ width: 350px; float: left;}
        .titulo{ font-size: 12pt; font-weight: bold;}
        #camara, #foto{
            width: 320px;
            min-height: 240px;
            border: 1px solid #008000;
        }
    </style>
    <script type="text/javascript">
        //El código Javascript está en la siguiente sección del post
    </script>
</head>
<body>
    <div id='botonera'>
        <input id='botonIniciar' type='button' value = 'Iniciar'></input>
        <input id='botonDetener' type='button' value = 'Detener'></input>
        <input id='botonFoto' type='button' value = 'Foto'></input>
    </div>
    <div class="contenedor">
        <div class="titulo">Cámara</div>
        <video id="camara" autoplay controls></video>
    </div>
    <div class="contenedor">
        <div class="titulo">Foto</div>
        <canvas id="foto" ></canvas>
    </div>   
</body>
</html>
Básicamente tenemos tres bloques en el cuerpo del HTML: vemos un div con 3 botones para iniciar el video, para detenerlo, y para tomar una foto (lo de la foto va para después), más abajo tenemos un segundo div que contiene una etiqueta video y un tercer div que contiene una etiqueta canvas.
En encabezado tenemos una referencia a jQuery, que va en la versión 1.8.2 al momento de publicar el post; este lo usaremos como herramienta para acceder al DOM (estructura del html) por javascript. Personalmente creo que hay que aprender Javascript antes de aprender a usar algún framework o librería (como jQuery, DOJO, Prototype, YUI…), porque un framework/librería solo va a ayudarte a hacer más fácilmente lo que igual podrías hacer “a mano”.
En el encabezado también tenemos algunos estilos definidos para mostrar el layout en pantalla. En este punto debes tener algo como esto:
Layout de la página de prueba de video HTML5
Ahora el código javascript. Este, debes colocarlo en el encabezado, después de la definición de los estilos puedes ver el espacio donde va situado (o si prefieres puedes colocarlo en un archivo externo):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Nos aseguramos que estén definidas
//algunas funciones básicas
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || function(){alert('Su navegador no soporta navigator.getUserMedia().');};
jQuery(document).ready(function(){
    //Este objeto guardará algunos datos sobre la cámara
    window.datosVideo = {
        'StreamVideo': null,
        'url' : null
    };
    
    jQuery('#botonIniciar').on('click', function(e){
        //Pedimos al navegador que nos de acceso a
        //algún dispositivo de video (la webcam)
        navigator.getUserMedia({'audio':false, 'video':true}, function(streamVideo){
            datosVideo.StreamVideo = streamVideo;
            datosVideo.url = window.URL.createObjectURL(streamVideo);
            jQuery('#camara').attr('src', datosVideo.url);
        }, function(){
            alert('No fue posible obtener acceso a la cámara.');
        });
    });
    jQuery('#botonDetener').on('click', function(e){
        if(datosVideo.StreamVideo){
            datosVideo.StreamVideo.stop();
            window.URL.revokeObjectURL(datosVideo.url);
        };
    });
});
Al hacer clic en el botón botonIniciar se ejecuta la función navigator.getUserMedia del navegador. Esta recibe tres parámetros: el primero con la configuración (pediremos video, sin audio), el segundo es una función que se ejecutará cuando obtengamos acceso a la cámara, y el tercero es una función que se ejecutará si no se puede obtener acceso a la cámara.
Si logramos obtener una fuente de video, generamos un url de “dispositivo de video” que podemos usar como origen para nuestra etiqueta video (como dije antes, no tiene que ser un video pregrabado). Este url, junto con el flujo de video lo almacenamos en el objeto que definimos al principio para poder detener el video con el segundo botón. Si tienes una cámara web conectada a tu equipo puedes probar este código y tendrás acceso a tu cámara.
Una aclaratoria sobre “obtener acceso a un dispositivo de video”: al ejecutar la funciónnavigator.getUserMedia le estamos pidiendo al navegador que nos provea acceso a “algún” dispositivo de audio y/o video (según el primer parámetro), pero por supuesto no vamos a acceder a la cámara y grabar a los usuarios sin pedir permiso, por esa razón el navegador probablemente muestre un mensaje al usuario indicándole que la página quiere tener acceso a la cámara web. El usuario puede aceptar o rechazar la petición, e incluso puede indicarle cuál “dispositivo” usar. Esto es útil si, por ejemplo, estás abriendo esta página desde tu móvil o tablet y este cuenta con dos cámaras (frontal y trasera).

Captura de foto desde la cámara

Ya tenemos video! ahora hagamos algo interesante con él. Debajo del botón botonDetenercolocamos el código para manejar el clic del botón botonFoto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jQuery('#botonFoto').on('click', function(e){
    var oCamara,
        oFoto,
        oContexto,
        w, h;
        
    oCamara = jQuery('#camara');
    oFoto = jQuery('#foto');
    w = oCamara.width();
    h = oCamara.height();
    oFoto.attr({'width': w, 'height': h});
    oContexto = oFoto[0].getContext('2d');
    oContexto.drawImage(oCamara[0], 0, 0, w, h);
});
El código es corto y simple: primero obtenemos una referencia a la etiqueta video (llamadacamara) y otra a la etiqueta canvas (llamada foto), redimensionamos el canvas para que coincida con el tamaño del video. Luego pedimos al canvas un contexto de dibujo; este es el que realiza las operaciones de dibujado sobre el canvas. Usaremos el método drawImage del contexto para dibujar sobre el canvas la imagen actual del video (el fotograma que esté mostrando al momento de hacer clic en botonFoto).
A la función drawImage le pasamos como parámetros: el objeto que representa a la etiquetavideo (escribimos oCamara[0] para pasarle el elemento del DOM, no el objeto/arreglo de jQuery), y otros cuatro parámetros que representan la posición dentro del canvas donde se comenzará a dibujar (coordenadas x y y del canvas) y el tamaño que tendrá la imagen dibujada (podríamos escalar la imagen cambiando estos valores).
Si tienes una cámara web instalada ya puedes probar el código y tomar una foto desde tu página web.
Etiquetas Video y Canvas trabajando juntas para tomar una foto
También puedes ver un ejemplo funcionando en jsFiddle. ¿Primera vez en jsFiddle? solo abre el link y presiona el botón run que está arriba a la izquierda, puedes modificar el código y presionar run de nuevo para hacer pruebas, pero no presiones update para no llenar la base de datos de jsFiddle con “pruebas” 🙂 .
Una recomendación: debes leer un poco más acerca de los atributos width y height de las etiquetas canvas y video (ojo: no son los mismos atributos css width y height, que podrían tener diferente valor), para que tengas una idea clara de como afectan la calidad y resolución de la imagen tomada. En este ejemplo, le dí a ambas etiquetas un ancho fijo de 320px, y una altura variable (de al menos 240px), de manera que se mantenga el aspecto (ratio aspect) del video y de la foto, y que la foto tenga al menos la misma calidad que provee la cámara. Más abajo te dejo el vínculo de las definiciones de estas etiquetas en la página de la W3C.
Claro que, teniendo la foto en pantalla probablemente quieras hacer algo más con ella, por ejemplo agregarle un marco o aplicar un filtro (como los de instagram); para esto puedes usar el objeto Context del canvas (el que usamos hace poco). Si deseas guardar la imagen en el servidor puedes hacerlo con AJAX (jQuery te facilitará mucho el trabajo) y algo de código en PHP, JSP o APS, incluso puedes determinar las medidas y tamaño de la imagen antes de enviarla.
Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s