De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.


Utilizando Câmeras em Aplicações Android

Colaboração: Carlos Tosin

Data de Publicação: 02 de abril de 2012

Grande parte dos dispositivos Android possui uma ou mais câmeras, que permitem tirar fotos e gravar vídeos. O objetivo deste artigo é mostrar como aplicações Android podem tirar proveito da presença destas câmeras.

A integração de uma aplicação com a câmera de um dispositivo pode ser feita de duas formas. A primeira, mais simples, utiliza a aplicação de câmera nativa que já existe no Android. E a segunda permite que o desenvolvedor tenha controle total do hardware da câmera. As duas formas serão abordadas na sequência.

Este artigo tem foco na utilização da câmera apenas, portanto é esperado que o leitor tenha conhecimento prévio a respeito de conceitos fundamentais do Android, como intents, activities, views e permissões de acesso.

Acessando a aplicação nativa de câmera

A forma mais simples de integrar uma aplicação com a câmera é chamar a aplicação nativa de câmera do dispositivo. A chamada de outras aplicações no Android é feita através do disparo de uma intent para a plataforma, que fica responsável por carregar a aplicação. O código que solicita a abertura da aplicação nativa da câmera pode ser visto a seguir:

  File picsDir = Environment.getExternalStoragePublicDirectory(
      Environment.DIRECTORY_PICTURES);
  File imageFile = new File(picsDir, "foto.jpg");
  
  Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
  startActivity(i);

A intent deve ser criada com a action MediaStore.ACTION_IMAGE_CAPTURE, que identifica a aplicação nativa de câmera. Dentro de intent, é fornecido também o caminho para o arquivo onde a foto tirada será armazenada. Neste caso, o armazenamento está sendo feito na memória externa do dispositivo, dentro da pasta onde normalmente as fotos ficam guardadas (mas poderia ser em outro local). Lembrando que, se você deseja gravar dados na área de memória externa, é preciso que sua aplicação declare a permissão android.permission.WRITE_EXTERNAL_STORAGE no arquivo AndroidManifest.xml.

Depois de criada a intent, o método startActivity() é chamado. É ele quem envia a intent para a plataforma, a qual vai abrir a aplicação da câmera. A foto tirada por esta aplicação será armazenada no caminho especificado pela propriedade MediaStore.EXTRA_OUTPUT adicionada à intent.

Como você pode perceber, este primeiro tipo de integração é bastante simples. É preciso apenas chamar a aplicação nativa de câmera e indicar onde a foto será armazenada. Se você precisa de um controle maior ou deseja realizar uma programação mais avançada nesta área, será necessário controlar diretamente a câmera via programação. Este é o assunto que será abordado a partir de agora.

Controlando a câmera via programação

Existem situações onde o programador não quer utilizar a aplicação nativa da câmera ou quer ter um controle maior sofre ela. Nesses casos o trabalho de programação é um pouco maior, pois é preciso seguir alguns passos.

Escolhendo a câmera

Um dispositivo pode ter várias câmeras, uma câmera ou nenhuma. Para identificar o número exato é possível fazer a seguinte chamada (disponível a partir do Android 2.3):

  int qtde = Camera.getNumberOfCameras();

O primeiro passo para trabalhar com uma câmera é obter uma instância de um objeto Camera (classe presente no pacote android.hardware.Camera). Isto pode ser feito desta forma:

  Camera camera = Camera.open();

Esta chamada retorna a referência à câmera traseira do dispositivo (retorna null caso ela não exista). Para referenciar outras câmeras, é preciso utilizar o método open() sobrecarregado, que recebe um int como parâmetro. Este parâmetro indica qual o ID da câmera, que pode variar de 0 até o número de câmeras subtraído de 1.

Um detalhe importante com relação à câmera é que ela deve ser liberada após o uso. Isto é feito através da seguinte chamada:

  camera.release();

Além disso, quando você acessa diretamente a câmera, o Android solicita que você declare uma permissão específica na sua aplicação, como pode ser visto abaixo:

  <uses-permission android:name="android.permission.CAMERA" />

Preview da imagem

Para que você possa tirar uma foto é necessário que você esteja vendo um preview da imagem, isto é, esteja vendo o que a câmera está enquadrando. Para trabalhar com preview, a classe SurfaceView é utilizada. Esta classe representa uma view, o que permite a sua utilização em um arquivo XML de definição de layout. Veja um exemplo:

  public class CameraActivity extends Activity 
      implements SurfaceHolder.Callback {
  
      private Camera camera;
      private SurfaceView surfaceView;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
  
          camera = Camera.open();
  		
          surfaceView = (SurfaceView) findViewById(R.id.preview);
          surfaceView.getHolder().addCallback(this);
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
  
          if (camera != null) {
              camera.release();
          }
      }
  
      @Override
      protected void onPause() {
          super.onPause();
  
          if (camera != null) {
              camera.stopPreview();
          }
      }
  
      @Override
      public void surfaceCreated(SurfaceHolder holder) {
          try {
              camera.setPreviewDisplay(holder);
              camera.startPreview();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  
      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, 
          int width, int height) {
          
          if (holder.getSurface() != null) {
              try {
                  camera.stopPreview();
              } catch (Exception e) {
              }
  			
              try {
                  camera.setPreviewDisplay(holder);
                  camera.startPreview();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
  
      @Override
      public void surfaceDestroyed(SurfaceHolder holder) {
      }
  }

Para trabalhar com um SurfaceView, é preciso registrar um callback. Isto é feito através do método surfaceView.getHolder().addCallback(). Este callback é um objeto de uma classe que implementa SurfaceHolder.Callback (neste caso, a própria activity).

A interface SurfaceHolder.Callback declara três métodos:

  • surfaceCreated(): Chamado quando a superfície, que é gerenciada pelo SurfaceView, é criada. O preview da imagem da câmera só pode ser iniciado quando a superfície é criada.

  • surfaceChanged(): Chamado quando a superfície é tem suas características alteradas. Se um preview está em andamento quando este método é chamado, ele deve ser reinicializado.

  • surfaceDestroyed(): Chamado quando a superfície é destruída.

O preview é iniciado ou parado, respectivamente, através dos métodos camera.startPreview() e camera.stopPreview(). O método camera.setPreviewDisplay() atrela a SurfaceView (onde o preview será mostrado) à câmera (que gera as imagens que serão exibidas).

Tirando fotos

Depois que a câmera foi inicializada e o preview está sendo exibido, é possível tirar fotos. Isto é feito através da seguinte chamada:

  camera.takePicture(shutter, raw, jpeg);

O método takePicture() é assíncrono. Conforme a imagem vai sendo processada, o Android invoca os callbacks passados como parâmetro. Os callbacks que não interessam para a aplicação não precisam ser fornecidos (neste caso null deve ser passado como parâmetro). O parâmetros deste método são os seguintes:

  • shutter: Objeto cuja classe implementa a interface ShutterCallback. Invocado assim que o obturador da câmera entra em ação e captura a imagem.

  • raw: Objeto cuja classe implementa a interface PictureCallback. Invocado quando a imagem "crua" tirada pela câmera está disponível.

  • jpeg: Objeto cuja classe implementa a interface PictureCallback. Invocado assim que a imagem comprimida, no formato JPEG, está disponível.

Veja um exemplo de implementação de um callback que grava a imagem no formato JPEG em algum local do dispositivo, assim que a imagem esteja disponível:

  PictureCallback jpeg = new PictureCallback() {
      @Override
      public void onPictureTaken(byte[] data, Camera camera) {
          FileOutputStream fos = null;
          try {
              try {
                  fos = new FileOutputStream(imageFile);
                  fos.write(data);
              } finally {
                  if (fos != null) {
                      fos.close();
                  }
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
  
          camera.startPreview();
      }

O método onPictureTaken() recebe como parâmetro um array de bytes, que representa o conteúdo da imagem. Este array deve ser usado para gerar o arquivo de imagem, por exemplo.

Outro detalhe importante é a chamada do método camera.startPreview() depois que a foto é gerada. Isto é necessário caso você deseje continuar exibindo o preview para tirar outras fotos.

Para tirar a foto utilizando o callback criado, a chamada pode ser feita assim:

  camera.takePicture(null, null, jpeg);

Seguindo estes passos você conseguirá ter controle total sobre a câmera e poderá utilizá-la de acordo com a sua necessidade.

Conclusão

Este artigo apresentou as duas formas de integrar aplicações Android com as câmeras presentes no dispositivo. A primeira através do uso da própria aplicação de câmera nativa do Android, e a segunda através do controle direto da câmera pela aplicação.

Referências

Sobre o Autor

Carlos Tosin é instrutor oficial dos cursos de Java e Android da SoftBlue. É formado em Ciência da Computação pela PUC-PR, pós-graduado em Desenvolvimento de Jogos para Computador pela Universidade Positivo e Mestre em Informática na área de Sistemas Distribuídos, também pela PUC-PR. Trabalha profissionalmente com Java há 10 anos e possui 6 anos de experiência no desenvolvimento de sistemas para a IBM dos Estados Unidos, utilizados a nível mundial. Atua há mais de 3 anos com cursos e treinamentos de profissionais em grandes empresas. Possui as certificações da Oracle SCJP, SCJD, SCWCD, SCBCD, SCEA; além das certificações IBM SOA, IBM OOAD (Object-Oriented Analysis and Design e ITIL Foundation.

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários

Nenhum comentário ainda. Seja o primeiro!


Veja a relação completa dos artigos de Carlos Tosin