Tirar fotos e controlar as configurações da câmera

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

A Image Capture é uma API para capturar imagens estáticas e definir as configurações de hardware da câmera. Essa API está disponível no Chrome 59 para Android e computadores. Também publicamos uma biblioteca de polyfill ImageCapture.

Com a API, é possível controlar os recursos da câmera, como zoom, brilho, contraste, ISO e balanço de branco. O melhor de tudo é que a captura de imagens permite acessar os recursos de resolução máxima de qualquer câmera ou webcam de dispositivo disponível. As técnicas anteriores para tirar fotos na Web usavam snapshots de vídeo, que têm resolução menor do que a disponível para imagens estáticas.

Um objeto ImageCapture é construído com uma MediaStreamTrack como origem. A API tem dois métodos de captura takePhoto() e grabFrame() e maneiras de extrair os recursos e as configurações da câmera e mudar essas configurações.

Construção civil

A API Image Capture recebe acesso a uma câmera por meio de um MediaStreamTrack recebido 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);
}

Teste esse código no console do DevTools.

Capturar

A captura pode ser feita de duas maneiras: frame completo e snapshot rápido. takePhoto() retorna um Blob, o resultado de uma única exposição fotográfica, que pode ser transferido por download, armazenado pelo navegador ou exibido em um elemento <img>. Esse método usa a resolução de câmera fotográfica mais alta disponível. Exemplo:

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() retorna um objeto ImageBitmap, um snapshot de vídeo ao vivo, que pode, por exemplo, ser desenhado em um <canvas> e depois pós-processado para mudar seletivamente os valores de cor. A ImageBitmap só terá a resolução da origem do vídeo, que geralmente será menor que os recursos de imagens estáticas da câmera. Exemplo:

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));

Recursos e configurações

Há várias maneiras de manipular as configurações de captura, dependendo se as mudanças são refletidas no MediaStreamTrack ou só podem ser vistas depois de takePhoto(). Por exemplo, uma mudança no nível da zoom é imediatamente propagada para a MediaStreamTrack, enquanto a redução de olhos vermelhos, quando definida, é aplicada apenas quando a foto está sendo tirada.

Os recursos e as configurações "em tempo real" da câmera são manipulados usando a visualização MediaStreamTrack: MediaStreamTrack.getCapabilities() retorna um dicionário MediaTrackCapabilities com os recursos concretos compatíveis e os intervalos ou valores permitidos, por exemplo, intervalo de zoom ou modos de balanço de branco permitidos. Correspondentemente, MediaStreamTrack.getSettings() retorna um MediaTrackSettings com as configurações atuais concretas. Os modos de zoom, brilho e lanterna pertencem a esta categoria, por exemplo:

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;
}

Os recursos e as configurações da câmera "Não ao vivo" são manipulados pelo objeto ImageCapture: ImageCapture.getPhotoCapabilities() retorna um objeto PhotoCapabilities que fornece acesso aos recursos disponíveis da câmera "Não ao vivo". A partir do Chrome 61, o ImageCapture.getPhotoSettings() retorna um objeto PhotoSettings com as configurações atuais concretas. A resolução da foto, a redução de olhos vermelhos e o modo do flash (exceto lanterna) pertencem a esta seção, por exemplo:

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));

Configurando

As configurações da câmera "Ao vivo" podem ser definidas usando as restrições applyConstraints() da MediaStreamTrack de visualização, por exemplo:

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

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

As configurações da câmera "não ao vivo" são definidas com o dicionário opcional PhotoSettings do takePhoto(), por exemplo:

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));

Recursos da câmera

Se você executar o código acima, vai notar uma diferença nas dimensões entre os resultados de grabFrame() e takePhoto().

O método takePhoto() dá acesso à resolução máxima da câmera.

O grabFrame() usa apenas o próximo VideoFrame disponível no MediaStreamTrack dentro do processo do renderizador, enquanto o takePhoto() interrompe o MediaStream, reconfigura a câmera, tira a foto (geralmente em um formato compactado, por isso o Blob) e, em seguida, retoma a MediaStreamTrack. Em essência, isso significa que takePhoto() fornece acesso a todos os recursos de resolução de imagem estática da câmera. Antes, só era possível "tirar uma foto" chamando drawImage() em um elemento canvas usando um vídeo como origem (como no exemplo aqui).

Mais informações podem ser encontradas na seção README.md.

Nesta demonstração, as dimensões <canvas> são definidas para a resolução do stream de vídeo, enquanto o tamanho natural de <img> é a resolução máxima de imagem estática da câmera. O CSS é usado para definir o tamanho de exibição de ambos.

A gama completa de resoluções de câmera disponíveis para imagens estáticas pode ser acessada e definida usando os valores MediaSettingsRange para PhotoCapabilities.imageHeight e imageWidth. As restrições de largura e altura mínimas e máximas para getUserMedia() são para vídeo, que, conforme discutido, podem ser diferentes dos recursos da câmera para imagens estáticas. Em outras palavras, talvez você não consiga acessar todos os recursos de resolução total do dispositivo ao salvar de getUserMedia() em uma tela. A demonstração de restrição de resolução do WebRTC mostra como definir restrições getUserMedia() para resolução.

Mais alguma coisa?

Demonstrações e exemplos de código

Suporte

  • Chrome 59 no Android e em computadores.
  • Chrome Canary para Android e computadores anteriores à 59a versão com os recursos da Plataforma Web experimental ativados.

Saiba mais