Cómo tomar fotos y controlar la configuración de la cámara

Miguel Casas-Sanchez
François Beaufort
François Beaufort

Image Capture es una API para capturar imágenes fijas y establecer la configuración de hardware de la cámara. Esta API está disponible en Chrome 59 en Android y computadoras de escritorio. También publicamos una biblioteca de polyfills de ImageCapture.

La API permite controlar las funciones de la cámara, como el zoom, el brillo, el contraste, la escala ISO y el balance de blancos. Lo mejor de todo es que la captura de imágenes te permite acceder a las capacidades de resolución completa de cualquier cámara o cámara web disponible en un dispositivo. En las técnicas anteriores para tomar fotos en la Web, se usaban instantáneas de video, que tienen una resolución más baja que la disponibles para las imágenes estáticas.

Se construye un objeto ImageCapture con un MediaStreamTrack como fuente. Entonces, la API tiene dos métodos de captura, takePhoto() y grabFrame(), y formas de recuperar las capacidades y la configuración de la cámara, y cambiar esos parámetros de configuración.

Construcción

La API de Image Capture obtiene acceso a una cámara a través de un MediaStreamTrack obtenido de getUserMedia():

navigator.mediaDevices.getUserMedia({video: true})
    .then(gotMedia)
    .catch(error => console.error('getUserMedia() error:', error));

function gotMedia(mediaStream) {
    const mediaStreamTrack = mediaStream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(mediaStreamTrack);
    console.log(imageCapture);
}

Puedes probar este código desde la consola de Herramientas para desarrolladores.

Captura

La captura se puede realizar de dos maneras: fotograma completo e instantánea rápida. takePhoto() muestra un Blob, el resultado de una sola exposición fotográfica, que puede descargarse, almacenarse en el navegador o mostrarse en un elemento <img>. Este método usa la resolución de cámara fotográfica más alta disponible. Por ejemplo:

const img = document.querySelector('img');
// ...
imageCapture.takePhoto()
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('takePhoto() error:', error));

grabFrame() muestra un objeto ImageBitmap, una instantánea de video en vivo, que podría, por ejemplo, dibujarse en un <canvas> y, luego, procesarse posteriormente para cambiar los valores de color de manera selectiva. Ten en cuenta que ImageBitmap solo tendrá la resolución de la fuente de video, que suele ser más baja que las capacidades de imagen fija de la cámara. Por ejemplo:

const canvas = document.querySelector('canvas');
// ...
imageCapture.grabFrame()
    .then(imageBitmap => {
    canvas.width = imageBitmap.width;
    canvas.height = imageBitmap.height;
    canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
    })
    .catch(error => console.error('grabFrame() error:', error));

Funciones y configuración

Hay varias formas de manipular la configuración de captura, en función de si los cambios se reflejarán en el MediaStreamTrack o solo se podrán ver después de takePhoto(). Por ejemplo, un cambio en el nivel zoom se propaga de inmediato a MediaStreamTrack, mientras que la reducción de ojos rojos, cuando se establece, solo se aplica cuando se toma la foto.

Las capacidades y la configuración de la cámara "en vivo" se manipulan mediante la vista previa MediaStreamTrack: MediaStreamTrack.getCapabilities() muestra un diccionario MediaTrackCapabilities con las capacidades concretas admitidas y los rangos o valores permitidos, p.ej., rango de zoom admitido o modos de balance de blancos permitidos. En consecuencia, MediaStreamTrack.getSettings() muestra un MediaTrackSettings con la configuración actual concreta. El zoom, el brillo y el modo linterna pertenecen a esta categoría, por ejemplo:

var zoomSlider = document.querySelector('input[type=range]');
// ...
const capabilities = mediaStreamTrack.getCapabilities();
const settings = mediaStreamTrack.getSettings();
if (capabilities.zoom) {
    zoomSlider.min = capabilities.zoom.min;
    zoomSlider.max = capabilities.zoom.max;
    zoomSlider.step = capabilities.zoom.step;
    zoomSlider.value = settings.zoom;
}

Las capacidades y los parámetros de configuración de la cámara "No en vivo" se manipulan mediante el objeto ImageCapture: ImageCapture.getPhotoCapabilities() muestra un objeto PhotoCapabilities que proporciona acceso a las capacidades de cámara disponibles "No publicadas". En consecuencia, a partir de Chrome 61, ImageCapture.getPhotoSettings() muestra un objeto PhotoSettings con la configuración actual concreta. La resolución de la foto, la reducción de ojos rojos y el modo de flash (excepto linterna) pertenecen a esta sección, por ejemplo:

var widthSlider = document.querySelector('input[type=range]');
// ...
imageCapture.getPhotoCapabilities()
    .then(function(photoCapabilities) {
    widthSlider.min = photoCapabilities.imageWidth.min;
    widthSlider.max = photoCapabilities.imageWidth.max;
    widthSlider.step = photoCapabilities.imageWidth.step;
    return imageCapture.getPhotoSettings();
    })
    .then(function(photoSettings) {
    widthSlider.value = photoSettings.imageWidth;
    })
    .catch(error => console.error('Error getting camera capabilities and settings:', error));

Configuración

La configuración de la cámara "en vivo" se puede establecer a través de las restricciones de applyConstraints() de la vista previa de MediaStreamTrack, por ejemplo:

var zoomSlider = document.querySelector('input[type=range]');

mediaStreamTrack.applyConstraints({ advanced: [{ zoom: zoomSlider.value }]})
    .catch(error => console.error('Uh, oh, applyConstraints() error:', error));

Los parámetros de configuración de la cámara "No en vivo" se establecen con el diccionario opcional PhotoSettings de takePhoto(), por ejemplo:

var widthSlider = document.querySelector('input[type=range]');
imageCapture.takePhoto({ imageWidth : widthSlider.value })
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('Uh, oh, takePhoto() error:', error));

Capacidades de la cámara

Si ejecutas el código anterior, notarás una diferencia en las dimensiones entre los resultados grabFrame() y takePhoto().

El método takePhoto() otorga acceso a la resolución máxima de la cámara.

grabFrame() solo toma el siguiente VideoFrame disponible en el MediaStreamTrack dentro del proceso del renderizador, mientras que takePhoto() interrumpe el MediaStream, reconfigura la cámara, toma la foto (generalmente en un formato comprimido; por lo tanto, el Blob) y luego reanuda el MediaStreamTrack. En esencia, esto significa que takePhoto() otorga acceso a las capacidades completas de resolución de imágenes estáticas de la cámara. Anteriormente, solo se podía "tomar una foto" llamando a drawImage() en un elemento canvas con un video como fuente (según el ejemplo aquí).

Para obtener más información, consulta la sección de README.md.

En esta demostración, las dimensiones de <canvas> se establecen en la resolución de la transmisión de video por Internet, mientras que el tamaño natural de <img> es la resolución máxima de la imagen estática de la cámara. CSS, por supuesto, se usa para configurar el tamaño de visualización de ambos.

El rango completo de resoluciones de cámara disponibles para las imágenes estáticas se puede obtener y configurar con los valores de MediaSettingsRange para PhotoCapabilities.imageHeight y imageWidth. Ten en cuenta que las restricciones mínimas y máximas de ancho y alto de getUserMedia() son para video, que (como se explicó) pueden ser diferentes de las capacidades de la cámara para imágenes fijas. En otras palabras, es posible que no puedas acceder a las capacidades de resolución completa de tu dispositivo cuando guardas de getUserMedia() en un lienzo. En la demostración de restricción de resolución de WebRTC, se muestra cómo establecer restricciones de getUserMedia() para la resolución.

¿Algo más?

Demostraciones y muestras de código

Asistencia

  • Chrome 59 en Android y computadoras de escritorio
  • Chrome Canary en Android y computadoras de escritorio anteriores a la versión 59 con funciones de Plataforma web experimental habilitadas.

Más información