Toma una selfie con JavaScript

En este tutorial, le mostraremos cómo crear una aplicación de fotomatón de JavaScript que tome imágenes con la cámara de su teléfono, computadora portátil o computadora de escritorio. Mostraremos una serie de increíbles API nativas que nos permitieron hacer nuestro proyecto sin dependencias externas, bibliotecas de terceros o Flash, ¡solo JavaScript estándar!

La aplicación

Para el usuario final, nuestra aplicación es solo una versión simplificada de la aplicación de la cámara que puede encontrar en cualquier teléfono inteligente. Utiliza una cámara de hardware para tomar fotografías, eso es todo. Debajo del capó, sin embargo, está sucediendo mucha magia de JavaScript. Aquí hay una descripción general de alto nivel:

  1. Accedemos a la entrada de la cámara y obtenemos una transmisión de video usando la API getUserMedia.
  2. Proyecte la transmisión de la cámara en un elemento de video HTML.
  3. Cuando el usuario quiere tomar una foto, copiamos el cuadro de video actual y lo dibujamos en un elemento de lienzo.
  4. Transforme el lienzo en una URL de datos de imagen que luego se puede mostrar en la pantalla o descargar como PNG.

En el siguiente artículo solo veremos las partes más interesantes del código. Para obtener la fuente completa, vaya a Descargar cerca de la parte superior de esta página o echa un vistazo a la demostración en JSfiddle.

Acceso a la cámara

JavaScript proporciona una API nativa para acceder a cualquier hardware de cámara en forma del método navigator.getUserMedia. Dado que maneja datos privados, esta API solo funciona en conexiones HTTPS seguras y siempre solicita permiso al usuario antes de continuar.

Si el usuario permite habilitar su cámara, navigator.getUserMedia nos da una transmisión de video en una devolución de llamada exitosa. Esta transmisión consta de los datos de transmisión sin procesar que provienen de la cámara y debe transformarse en una fuente de medios utilizable real con el createObjectURL método.

navigator.getUserMedia(
    // Options
    {
        video: true
    },
    // Success Callback
    function(stream){

        // Create an object URL for the video stream and
        // set it as src of our HTLM video element.
        video.src = window.URL.createObjectURL(stream);

        // Play the video element to show the stream to the user.
        video.play();

    },
    // Error Callback
    function(err){

        // Most common errors are PermissionDenied and DevicesNotFound.
        console.error(err);

    }
);

Tomar una foto fija

Una vez que tengamos la transmisión de video en marcha, podemos tomar instantáneas desde la entrada de la cámara. Esto se hace con un ingenioso truco que utiliza el poderoso <canvas> para tomar un cuadro de la transmisión de video en ejecución y guardarlo en un <img> elemento.

function takeSnapshot(){

    var hidden_canvas = document.querySelector('canvas'),
        video = document.querySelector('video.camera_stream'),
        image = document.querySelector('img.photo'),

        // Get the exact size of the video element.
        width = video.videoWidth,
        height = video.videoHeight,

        // Context object for working with the canvas.
        context = hidden_canvas.getContext('2d');

    // Set the canvas to the same dimensions as the video.
    hidden_canvas.width = width;
    hidden_canvas.height = height;

    // Draw a copy of the current frame from the video on the canvas.
    context.drawImage(video, 0, 0, width, height);

    // Get an image dataURL from the canvas.
    var imageDataURL = hidden_canvas.toDataURL('image/png');

    // Set the dataURL as source of an image element, showing the captured photo.
    image.setAttribute('src', imageDataURL); 

}

El elemento canvas en sí ni siquiera necesita estar visible en el DOM. Solo usamos su API de JavaScript como una forma de capturar un momento fijo del video.

Descargando la foto

Por supuesto, no solo queremos tomar selfies gloriosas, sino que también queremos poder guardarlas para que las vean las generaciones futuras. La forma más sencilla de hacerlo es con el atributo de descarga para <a> elementos. En el HTML, el botón se ve así:

<a id="dl-btn" href="#" download="glorious_selfie.png">Save Photo</a>

El download El atributo transforma nuestro ancla de un hipervínculo a un botón de descarga. Su valor representa el nombre predeterminado del archivo descargable, el archivo real para descargar se almacena en el href atributo, que como puede ver está vacío por ahora. Para cargar nuestra foto recién tomada aquí, podemos usar la URL de datos de la imagen de la sección anterior:

function takeSnapshot(){

    //...

    // Get an image dataURL from the canvas.
    var imageDataURL = hidden_canvas.toDataURL('image/png');

    // Set the href attribute of the download button.
    document.querySelector('#dl-btn').href = imageDataURL;
}

Ahora, cuando alguien haga clic en ese botón, se le pedirá que descargue un archivo llamado glorious_selfie.png , que contiene la foto que tomaron. ¡Con esto nuestro pequeño experimento está completo!

Conclusión

Esperamos que haya aprendido mucho de este tutorial y que ahora se sienta inspirado para crear algunas aplicaciones de fotos increíbles. Como siempre, no dude en hacer preguntas o compartir ideas en la sección de comentarios a continuación.