Tirando fotos com JS – Mente de Iniciante
Tirando fotos com JS
set 01 2016 12/03/2018
Hoje em dia todo computador, notebook ou smartphone tem uma (ou mais) câmera(s).
Antigamente, a única maneira de aproveitar essas câmeras em uma aplicação Web era usando Flash.
Mas, hoje em dia, podemos tirar fotos com JS. Para isso, vamos utilizar o WebRTC.
WebRTC é um padrão Web que define protocolos e APIs em JS para enviar vídeo, áudio e dados entre navegadores de maneira peer-to-peer e em tempo real. Está disponível no Chrome para Desktop e Android, Firefox, Opera e Edge.
Pra começar, um <video> e um <canvas>
Precisamos de uma estrutura mínima no nosso HTML.
A tag <video> com a propriedade autoplay, ficará responsável por mostrar para o usuário as imagens obtidas da câmera.
Para guardar a imagem da foto, vamos usar um <canvas>, que começara invisível.
Finalmente, precisaremos de um <button> para que o usuário informe o momento em que deve ser tirada a foto a partir do vídeo.
Os três elementos mencionados ficarão dentro de uma <div>.
<video id="video" class="foto" autoplay>Vídeo não disponível.</video>
<canvas id="canvas" class="foto" style="display: none;"></canvas>
<button id="tira-foto">Tirar foto</button>
Um pouquinho de css
Para posicionar os elementos e definir uma borda, teremos um pequeno trecho de css:
Mude o CSS à vontade, para deixar mais estiloso!
Mostrando o vídeo
No nosso código JS, obteremos o elemento cujo id é video:
Para obter as imagens da câmera, precisamos usar o método getUserMedia do navigator.
Uma coisa chata é que a API ainda não está consolidada. Por isso, o getUserMedia tem prefixos diferentes para cada navegador:
navigator.webkitGetUserMedia – para o Chrome e Opera
navigator.mozGetUserMedia – para o Firefox
navigator.msGetUserMedia – para o Edge
Testaremos o getUserMedia correto, armazendo-o em uma variável e ajustando o this através de um bind com o objeto navigator:
var getUserMedia = (navigator.webkitGetUserMedia ||
navigator.msGetUserMedia).bind(navigator);
Ao chamar o getUserMedia, devemos passar 3 parâmetros:
um objeto de configuração que diz se deve ser obtido vídeo ou áudio da câmera, entre outros detalhes
uma função chamada quando houve sucesso ao obter mídia da câmera. Nessa função, obtemos um MediaStream, que devemos passar para a propriedade srcObject do nosso elemento video. Guardaremos o MediaStream em uma variável, para uso posterior.
uma função chamada em caso de erro
var configuracaoMedia = {video: true, audio: false};
function iniciaVideo (stream) {
function trataErroMedia (erro) {
console.error('Erro: ' + erro);
getUserMedia(configuracaoMedia, iniciaVideo, trataErroMedia);
O resultado até aqui pode ser encontrado em:
https://jsfiddle.net/alexandreaquiles/xqhLL2wm/1/
Obtendo uma foto
Devemos obter o canvas e o botão a partir de seus ids:
var botaoTiraFoto = document.querySelector('#tira-foto');
Precisamos registrar um tratador do evento de clique no botão.
botaoTiraFoto.addEventListener('click', function (e) {
//tratamento aqui...
Dentro da função de tratamento do clique, devemos obter o contexto 2D a partir do canvas e utilizá-lo para desenhar uma imagem a partir do vídeo. Nesse momento, a foto é tirada.
Podemos obter os dados através do método toDataURL do canvas.
var dados = canvas.toDataURL('image/png');
//fazer algo com os dados...
O método toDataURL retorna uma Data URI, uma maneira de representar imagens e outros tipos de dados como um texto. Por exemplo, um .png com um pontinho preto pode ser representado como: data:image/png;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=
Podemos enviar essa Data URI para o servidor com uma chamada AJAX.
Do lado do servidor, você pode gravar a Data URI no BD para uso posterior como src de um <img> ou ainda transformá-lo em um arquivo.
Em PHP, usaríamos str_replace, base64_decode e file_put_contents para salvar a imagem em um arquivo no servidor.
Você pode testar o código até essa parte em:
Mostrando a foto e escondendo o vídeo
Quando o usuário clicar o botão, é interessante mostrarmos o <canvas> que tem a imagem da foto tirada e, em seguida, escondermos o vídeo da câmera.
canvas.style.display = '';
Ao exibirmos a imagem, percebemos que há uma distorção. Para resolver, é importante fixar a altura e largura do <canvas>:
A câmera continuará filmando, mas a imagem ficará parada, sendo alterada só quando o usuário clicar no botão.
Você pode acompanhar o resultado em:
https://jsfiddle.net/alexandreaquiles/xqhLL2wm/2/
Parando a câmera ao obter foto
Para suspender a filmagem logo depois do clique no botão, podemos usar o seguinte código:
mediaStream.getVideoTracks().forEach(function (media) {
É interessante alternar entre filmagem com a câmera e a exibição da foto tirada. Para isso, alternamos entre exibição do <video> e do <canvas>. Além disso, alternamos entre parar e voltar com o funcionamento da câmera.
video.style.display = '';
O código até aqui está em:
https://jsfiddle.net/alexandreaquiles/xqhLL2wm/3/
Para funcionar no Chrome do Android
Com o código anterior, ocorre um bug quando acessado pelo Chrome do Android: é mostrada uma imagem preta no vídeo.
Para corrigí-lo, é necessário fixar as propriedades opcionais maxWidth e minWidth na configuração de getUserMedia:
var configuracaoMedia = {
{ maxWidth: 320},
{ maxHeight: 240}
O código final pode ser encontrado em:
https://jsfiddle.net/alexandreaquiles/xqhLL2wm/4/
Consideração importante: tem que ser HTTPS
Para que o código acima funcione no Chrome e Opera quando publicado em um servidor real, não em sua máquina local, é preciso que seja usado HTTPS.
Para o Firefox não há essa restrição.
01/09/2016 às 20:44
Alexandre como sempre muito bom o seu post, Gostei muito da explicação do WebRTC. parabéns.
Bom dia Alexandre, minha câmera está finalizando sozinha e não exibe mensagem, diz no console que está com erro na variável stream, consegue me ajudar?