HTML5 – Que tus usuarios suban su foto a su perfil (WebRTC)

Venga, seguro que como la mitad de mortales tienes una idea de negocio que consiste en hacer una web y que te la compre Google (la otra mitad esperan que la compre Microsoft :p).

Si este es el caso, ya sabes que se trata de tener cuantos más usuarios mejor (ahí tienes el caso de Mammoth que han lanzado una campaña viral para que todos nos apuntemos allí aunque no tengamos ni idea de que va). Hoy en día cualquier web que se precie tiene un perfil donde el usuario puede subir una foto suya para que sea su avatar. Imagina la situación de que un usuario se registra a tu web y no tiene a mano ninguna foto suya para subir. ¿No estaría bien que se pudiese hacer una foto con la webcam del portátil y subirla directamente? Todo ello des de tu web, por supuesto.

Pues bien, eso es ni más ni menos lo que permite WebRTC. 😉

WebRTC significa Web Real Time Communications y es una de las futuras APIs de HTML5 que más darán que hablar. Hablo en futuro porque actualmente no son un estándard terminado: la especificación actual es todavía un Working Draft. Eso significa que su soporte en navegadores es todavía muy escaso y en la mayoría de casos experimental. El código de este post ha sido probado en Chrome 26 y funciona. No he probado en otros navegadores, pero por lo que sé IE10 no soporta todavía WebRTC y por lo que he leído FF lo soporta a partir de su versión 20. Opera también parece que lo soporta pero no sé a partir de que versión. Al final no tengais ninguna duda de que IE terminará soportando WebRTC, pero como digo: no es un estándard terminado y su definición puede cambiar.

Manos a la obra

La implementación de WebRTC se basa básicamente en una función javascript llamada getUserMedia que está en el objeto navigator. De todos modos como ya digo el soporte puede ser experimental y así p.ej. en Chrome está función está prefijada y debe usarse webkitGetUserMedia. Cosas del desarrollo para web.

Nota: Personalmente lo de los vendor prefixes me parece una aberración. No sé, si una característica se soporta, se soporta y punto. No veo porque tenemos que andar prefijando cosas porque “están a medias” y tal. Al final el problema para el desarrollador es el mismo: debes acordarte de meter todos los prefijos que toquen. En CSS aún puede tener un pase pero… ¿en javascript? ¿De veras tenemos que prefijar una función javascript? A mi me parece que algo se nos está yendo de las manos, pero bueno los prefijos están ampliamente aceptados por el W3C así que supongo que será mejor tenerlos que no tenerlos.

La función getUserMedia permite obtener un stream de datos local. Resumiendo, con getUserMedia podemos obtener la imagen de la webcam o el sonido del microfono. Básicamente le pasamos dos o tres parámetros:

  1. Los streams locales que queremos capturar (p.ej audio y/o video).
  2. La función de callback a invocar cuando la captura haya empezado
  3. La función de callback en caso de error (opcional).

Así para capturar la webcam bastaría con:

navigator.getUserMedia({video: true}, onSucessCallback, onFailCallback);

Para no andar jugando con los prefijos es preferible hacer algo como:

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

Así a medida que los navegadores vayan incorporando la función (con o sin prefijo) pues ya la tendremos disponible.

Vale… capturamos un stream de video, pero lo suyo es poderlo mostrar ¿no? En HTML5 tenemos una etiqueta que nos permite mostrar vídeos (<video />). ¿No sería genial que la pudiesemos utilizar? Pues, por suerte, podemos. Para ello nos tenemos que apoyar en otra API de HTML5: window.URL

Con los métodos de window.URL podemos crear URLs “ficticias” que apunten a “objetos” (técnicamente Blobs) que están vivos dentro del documento. La idea viene a ser la siguiente: con getUserMedia capturamos un stream de video. Para mostrar videos tenemos la etiqueta <video />. Pero la etiqueta <video /> espera la URL del vídeo. Pues con window.URL vamos a poder crear esta URL.

El código es muy simple:

<!DOCTYPE html>

<html>

<head></head>

<body>

    <video autoplay></video>

    <script>

        var onErrorCallback = function (e) {

            console.log(‘Error!’, e);

        };

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

        navigator.getUserMedia({ video: true}, function (localMediaStream) {

            var video = document.querySelector(‘video’);

            video.src = window.URL.createObjectURL(localMediaStream);

        }, onErrorCallback);

    </script>

</body>

</html>

Bueno… Si ejecutais este código veréis algo como:

image

Por supuesto no vereis a este tipo en pantalla, seguramente el que aparezca sea más feo, pero bueno eso son cosas que pasan 😛 😛 😛 😛

La función getUserMedia pide permisos. Es decir el usuario debe confirmar que da acceso a la webcam en este caso:

image

Vale… ya estamos mostrando el vídeo de la webcam. Pero el objetivo era que el usuario pudiese subir una foto de su perfil a nuestra web, ¿recordáis?

Bueno, para ello acude en nuestra ayuda otro de los nuevos elementos de HTML5: el <canvas />. Como ya sabréis la mayoría el canvas de HTML5 es un espacio dentro del documento para dibujar gráficos en 2D o en 3D.

Pues bien, la idea es volcar el frame actual del video al canvas. Y por suerte nos basta con llamar al método drawImage del contexto 2D del canvas. Sí, tan simple como esto.

Veamos el código:

<!DOCTYPE html>

<html>

<head>

    <style>

        video {width: 300px; height: 300px;}

    </style>

 

</head>

<body>

    <video autoplay></video>

    <input type="button" value="snaphsot!" id="snap" />

    <canvas></canvas>

 

    <script>

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

        // Definición de variables globales

        var localUserMedia = null;

        var canvas = document.querySelector(‘canvas’);

        var video = document.querySelector(‘video’);

        var ctx = canvas.getContext(‘2d’);

        // Cuando cargamos el vídeo guardamos la relación

        // de aspecto y ajustamos el tamaño del canvas

        // para que se mantenga

        video.addEventListener(‘loadedmetadata’, function (e) {

            var relation =  e.target.videoWidth/e.target.videoHeight;

            canvas.width = 300;

            canvas.height = 300/relation;

        }, false);

        // Capturamos el frame actual del video

        document.getElementById(‘snap’).addEventListener(‘click’, function (e) {

            if (localUserMedia) {

                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            }

        }, false);

        // Callback de error de getUserMedia

        var onErrorCallback = function (e) {

            console.log(‘Error!’, e);

        };

        // Capturamos el video con getUserMedia y lo

        // mandamos a un vídeo

        navigator.getUserMedia({ video: true }, function (localMediaStream) {

            var video = document.querySelector(‘video’);

            video.src = window.URL.createObjectURL(localMediaStream);

            localUserMedia = localMediaStream;

        }, onErrorCallback);

    </script>

</body>

</html>

He puesto comentarios en el código para que sea más fácil de seguir. Pero la clave está en que ahora al pulsar el botón de “snapshot” utilizamos drawImage para volcar el contenido del frame actual del vídeo al canvas.

Una vez tenemos la imagen en un canvas ya tenemos vía libre! Por un lado podríamos utilizar el propio canvas para permitir que el usuario manipule la imagen y luego subirla via Ajax (ver mi post Crea tu propio Instagram) o bien podemos directamente volcar el contenido del canvas en una imagen (utilizando toDataURL del propio canvas).

No voy a poner en este post como subir los datos del canvas al servidor porque sería repetir lo que puse en el post de Crea tu propio Instagram (Paso 5 del post).

En fin… hemos visto como gracias a WebRTC podemos (podremos) hacer algo que hasta hace poco parecía fuera totalmente de las posibilidades de la web: el acceso a dispositivos locales tales como micro y webcam. Y WebRTC no se queda ahí! Según la especificación será posible montar meetings on-line utilizando plataforma 100% web! Pero esta parte está todavía en una fase muy experimental e inicial de implementación!

Un saludo!

2 comentarios en “HTML5 – Que tus usuarios suban su foto a su perfil (WebRTC)”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *