Guia para utilização da câmera no Flutter
Nos dias de hoje, os aplicativos não se limitam apenas em exibir informações estáticas. A capacidade de interagir com o ambiente ao redor tornou-se uma parte integral da experiência do usuário. Nesse contexto, a integração da câmera em aplicativos desempenha um papel fundamental, permitindo uma gama diversificada de recursos, desde simples capturas de fotos e vídeos até o uso de algoritmos de visão computacional para classificação de objetos.
Neste artigo, exploraremos o uso de diferentes recursos da câmera dos smartphones com a linguagem dart e o framework flutter.
Configurações iniciais
O primeiro passo é a criação de um projeto Flutter. Se você ainda não possui o ambiente de desenvolvimento configurado, siga as instruções na documentação oficial do Flutter para instalar o Flutter SDK e configurar suas ferramentas. Após isso, você pode criar um novo projeto usando o seguinte comando:
Este comando criará uma estrutura de pastas básica para o seu projeto, incluindo o arquivo “lib/main.dart”, que é o ponto de entrada da sua aplicação. E dentro do arquivo “pubspec.yaml” é onde colocaremos as bibliotecas do projeto. Com o projeto iniciado, adicione as bibliotecas camera e image_picker dentro do “pubspec.yaml” embaixo de dependencies:
Depois, dentro do arquivo “main.dart” na pasta lib, importe os módulos necessários:
Agora precisamos de uma estrutura básica para a aplicação, contendo a função main que é o ponto de entrada, um StatelessWidget que vai retornar o MaterialApp com o menu da câmera como home (esta parte é especialmente importante, pois mais na frente precisaremos pegar o size do MaterialApp para definir o tamanho do preview da câmera) e por fim, um StatefulWidget que vai retornar um Scaffold:
Obtendo permissões da câmera no Android
Para utilizar certos recursos do dispositivo, é necessário pedir a permissão do usuário. A biblioteca permission_handler vai facilitar esse processo, pois devemos projetar o aplicativo para responder de acordo com a interação do usuário, isso significa que, se ele aceitar a solicitação, a câmera vai abrir normalmente, se ele recusar, uma mensagem vai aparecer na tela dizendo que a permissão da câmera é necessária e se ele recusar novamente ou de forma permanente, as configurações do aplicativo no dispositivo serão abertas para que ele modifique as permissões por lá.
Para configurar a câmera, primeiro a versão mínima do sdk deve ser mudada para 21 no arquivo build.gradle dentro da pasta android/app:
Dentro do estado do CameraMenu, primeiro criamos uma função chamada requestPermission, ela é assíncrona e vai solicitar ao dispositivo para que a câmera possa ser utilizada, depois o estado do Widget será alterado com o novo valor do estado para a variável _permissionStatus:
Uma função será responsável por chamar o openAppSettings da biblioteca permission_handler para abrir as configurações e no início do estado chamamos a função requestPermission:
Agora dentro do Scaffold, adicionamos um Widget Center, dentro dele uma coluna contendo um texto com o valor da variável _permissionStatus para sabermos o estado atual da permissão de acesso à câmera, um botão elevado que quando pressionado chama a função requestPermission e um outro texto e botão que serão desenhados se o valor do Status for permanentlyDenied, esse botão vai chamar a função _openAppSettings:
Feito isso, a aplicação já tem a funcionalidade de pedir a permissão do usuário para utilizar a câmera e reagir de acordo com a sua resposta. O próximo passo é utilizar da biblioteca camera para utilizar as funções da câmera. Para isso, no início do estado, primeiro criamos uma variável para listar as câmeras disponíveis e outra para o controlador da câmera:
Depois, é preciso iniciar a câmera quando o elemento for iniciado e liberar quando o elemento for destruído. Uma função específica assíncrona vai obter as câmeras disponíveis, instanciar e iniciar o controlador, mudando o estado da variável da câmera inicializada para true, a inicialização do controlador deve ser colocada dentro de um bloco try/catch, pois caso o usuário não permita o uso da câmera ou ocorra algum erro na hora de pegar a lista de câmeras disponíveis, será retornado null e vai dar erro no aplicativo.
A função “CameraController” é como se inicializa o controlador da câmera, nela é passada primeiro a câmera a ser selecionada, depois a resolução (que pode ser baixa, média ou alta), o parâmetro enableAudio (que se colocado em falso, só vai habilitar a câmera para capturar vídeos sem áudio), o parâmetro para definir o formato das imagens (por exemplo, jpeg), dentre outros.
Agora, precisamos de uma função que vai retornar um Widget para que possamos alterar no body. Ela vai começar verificando se a permissão da câmera está habilitada, se não estiver, vai retornar o que já tínhamos no body, já se estiver liberado, vai conferir se a câmera ainda não foi inicializada para chamar a função startCamera e retornar um widget com texto informando que a câmera está sendo iniciada, quando finalizar o carregamento, o estado da aplicação será atualizado e a condição vai passar a ser verdadeira, então será retornado o widget contendo o CameraPreview:
Agora, basta substituir o que tinha no body do Scaffold pela chamada da função cameraElement:
Mudar o tamanho do preview
Para mudar o tamanho do preview, é necessário colocar ele dentro de um container contendo width e height. Outros elementos podem ser adicionados por cima do preview se este container estiver dentro de uma stack como o primeiro elemento, então os elementos abaixo na stack ficarão por cima do preview, dessa forma, você pode adicionar botões, criar menus, colocar as bounding boxes para indicar a posição de elementos no preview com algoritmos de visão computacional e muito mais!
Se quiser deixar o preview do tamanho da tela, a stack precisará estar dentro do scaffold e este dentro do MaterialApp. Pegamos o tamanho da tela pelo context do MaterialApp e então passamos como parâmetro para o width e height do container onde o preview está:
Mudando Configurações Padrões
Depois que o controlador da câmera é inicializado, algumas funções podem ser chamadas para alterar as configurações padrões da câmera, como o flash, foco e zoom:
Tirando fotos com a câmera
Para tirar uma foto precisa utilizar a função takePicture do controller, que pode ser colocado em um MaterialButton, sendo que o onPressed deve ser assíncrono, pois para tirar uma foto, as ações necessárias para o hardware podem demorar um tempo imprevisível, pois envolve vários fatores, como por exemplo: iniciar o hardware da câmera, aguardar o foco automático, tirar a foto e salvar em um arquivo. Tarefas que podem ser influenciadas pela capacidade de processamento do dispositivo.
Pegar o stream de imagens da câmera
Capturar o stream de imagens da câmera permite analisar em tempo real utilizando algoritmos de visão computacional o que está sendo capturado pela câmera e reagir desenhando bounding boxes na tela para indicar que um objeto está sendo identificado. Para pegar esse stream, na função de inicialização do controlador da câmera (que é assíncrona), quando ela estiver pronta, deve ser chamada a função startImageStream e quando o Widget for desmontado, o stream deve ser parado:
É importante notar que o imageFormatGroup não deve ser especificado na inicialização do controle da câmera quando se for utilizar o ImageStream, pois dará erro e o stream não iniciará. Neste exemplo, se tudo estiver funcionando corretamente, a hora atual estará sendo logada no terminal em tempo real.
Quando o stream estiver funcionando, uma variável do tipo CameraImage pode ser criada para armazenar a imagem que está sendo retornada pelo ImageStream:
Conclusão
Neste artigo, abordamos desde as configurações iniciais para instalar as bibliotecas no aplicativo e obter as permissões necessárias para utilizar os recursos de hardware dos smartphones até a criação do controlador e utilização de algumas das funcionalidades da câmera, como alterar o foco, dar zoom, ativar o flash, iniciar o preview dentro de um widget, tirar fotos e pegar o stream de imagens. Ainda existem diversas funcionalidades para aprimorar a experiência do usuário no aplicativo ao utilizar a câmera que poderemos explorar em um próximo artigo, como a possibilidade de gravar vídeos, salvar imagens e vídeos na galeria do dispositivo, além da integração do stream de imagens com o tensorflow lite para criar um aplicativo capaz de reconhecer objetos em tempo real.
A linguagem dart e o framework flutter, aliados com as diversas bibliotecas que existem para trabalhar com os recursos de hardware e inteligência artificial, criam uma abstração e abrem a possibilidade da criação de tecnologias avançadas multiplataforma com um esforço relativamente pequeno, comparado à necessidade de desenvolver tudo nativamente, proporcionando uma ótima experiência de desenvolvimento. A demanda por tecnologias portáteis e eficientes vem crescendo cada vez mais em diferentes mercados e aqueles profissionais que conseguirem se especializar para entrar neste mercado certamente terão ótimas oportunidades em um futuro próximo.
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.