Caro amigo leitor, neste mês irei continuar escrevendo sobre a
utilização de câmeras em dispositivos móveis, tendo como plataforma de desenvolvimento
o Android Studio. No mês de Novembro, no artigo “Android – Utilizando a
Câmera”, foi desenvolvido a classe base “CameraVisualizacao” a qual agrega
alguns métodos e algumas funcionalidades básicas. Para este mês teremos como
base o artigo do mês anterior com algumas mudanças na classe
“CameraVisualizacao” e na Activity principal. A maior funcionalidade
implementada será a capacidade de salvarmos a foto tirada pelo aplicativo.
Então, mãos a obra.
Para isto separei este artigo com os seguintes tópicos:
- Modificação do arquivo “AndroidManifest.xml”
- Modificação do lay-out principal.
- Alteração e criação de novos métodos na classe “CameraVisualizacao”
- Implementação de novas rotinas na atividade principal “MainActivity”.
Criando o Exemplo
Seguindo como base o exemplo criado no mês passado, o primeiro passo
seria a alteração do arquivo de configuração “AnroidManifest.xml”. Iremos
inserir duas linhas conforme código destacado abaixo:
<?xml version="1.0"
encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.thiago.appcamera">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.thiago.appcamera">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
A funcionalidade
“android.hardware.camera.autofocus”, irá nos possibilitar recuperar
automaticamente o foco da imagem. Já o “android.permission.WRITE_EXTERNAL_STORAGE”
irá permitir a gravação da foto em nosso dispositivo no formato em que
desejarmos.
Modificação
do lay-out principal
No nosso lay-out principal adicionaremos um “Button” para fotografar.
Ver Imagem 01.
![]() |
Figura 01. Layout Principal. |
O XML correspondente poderemos conferir abaixo.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="15sp"
>
<SurfaceView android:id="@+id/area_view"
android:layout_width="300sp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
/>
<Button android:id="@+id/bt_fotografar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fotografar"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="15sp"
>
<SurfaceView android:id="@+id/area_view"
android:layout_width="300sp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
/>
<Button android:id="@+id/bt_fotografar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fotografar"
/>
</LinearLayout>
Alteração e
criação de novos métodos na classe “CameraVisualizacao”
Implementaremos alguns novos métodos, como por exemplo o “TirarFoto” e
declaramos algumas novas propriedades: a “visualizacao” e a “surfaceView”.
public
class CameraVisualizacao implements SurfaceHolder.Callback
{
private SurfaceHolder mHolder;
private Camera mCamera;
private SurfaceView surfaceView;
private boolean visualizacao = false;
{
private SurfaceHolder mHolder;
private Camera mCamera;
private SurfaceView surfaceView;
private boolean visualizacao = false;
public CameraVisualizacao(Activity atividade, int surfaceView)
{
this.surfaceView = (SurfaceView) atividade.findViewById(surfaceView);
mHolder = this.surfaceView.getHolder();
mHolder.addCallback(this);
}
Inicializaremos a variável “surfaceview” para logo em seguida invocarmos
o método “getHolder”. O “surfaceCreated” é
chamado imediatamente após o “SurfaceHolder” ser criado.
/**
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder)
{
mCamera = android.hardware.Camera.open();
mCamera.setDisplayOrientation(90);
}
/**
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder)
{
mCamera = android.hardware.Camera.open();
mCamera.setDisplayOrientation(90);
}
Usaremos o método “Open” e o
“setDisplayOrientation” para iniciar e definir uma orientação para a câmera.
public void iniciarVisualizacao()
{
visualizacao = true;
mCamera.startPreview();
}
visualizacao = true;
mCamera.startPreview();
}
Inicia o Preview da Câmera.
public void pararVisualizacao() {
mCamera.stopPreview();
visualizacao = false;
}
Para o Preview da Câmera.
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (visualizacao) {
pararVisualizacao();
}
if (mCamera != null) {
try {
mCamera.setPreviewDisplay(mHolder);
iniciarVisualizacao();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Chamaremos o método “surfaceChanged” imediatamente
após as alterações estruturais. Com o auxílio dos métodos “pararVisualizacao” e
“iniciarVisualizacao” conseguimos parar e iniciar o preview da Câmera.
*
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
pararVisualizacao();
mCamera.release();
mCamera = null;
}
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
pararVisualizacao();
mCamera.release();
mCamera = null;
}
Usaremos este método para liberarmos o objeto
“mCamera” da memória e pararmos o preview. Importante salientar que é chamado
imediatamente antes do SurfaceHolder ser destruído.
public void tirarFoto(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg) {
mCamera.takePicture(shutter, raw, jpeg);
}
}
Deveremo
tratar a ação de tirar foto, como notamos, o método “tirarFoto()” recebe três
parâmetros, sendo:
Camera.ShutterCallback shutter, Camera.PictureCallback raw,
Camera.PictureCallback jpeg
O primeiro é
referente a ação de tirar foto. Já o segundo e o terceiro é o retorno da
imagem. Podemos recebê-la no formato RAW (segundo parâmetro) ou em JPEG
(terceiro parâmetro), normalmente o modo RAW não é utilizado, por isso podemos
passar o valor como null.
Implementação
de novas rotinas na atividade principal “MainActivity”
O nosso controle será realizado por um “Button” e um “SurfaceView”
conforme mencionado anteriormente.
import android.app.Activity;
import android.os.Environment;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileOutputStream;
Usaremos algumas bibliotecas para trabalhar com Imagens, Câmeras e
Arquivos. (Conforme Seleção acima)
public
class CameraActivity extends Activity implements View.OnClickListener,
Camera.ShutterCallback, Camera.PictureCallback {
Precisaremos da implementação de alguns métodos
específicos da Câmera, conforme mencionado anteriormente.
private CameraVisualizacao mCameraView;
private boolean emCamera;
private Button botaoCamera;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
emCamera = true;
mCameraView = new CameraVisualizacao(this, R.id.area_view);
botaoCamera = (Button) findViewById(R.id.bt_fotografar);
botaoCamera.setOnClickListener(this);
}
“No evento OnCreate” inicializaremos a classe
“CameraVisualizacao” passando os parâmetros “Activity” e a “SurfaceView“.
Faremos o uso do evento “Onclick” do “Button”.
public void onClick(View view)
{
switch (view.getId())
{
case R.id.bt_fotografar:
if (emCamera)
{
mCameraView.tirarFoto(this, null, this);
}
else
{
emCamera = true;
botaoCamera.setText("Fotografar");
mCameraView.iniciarVisualizacao();
}
break;
}
}
No evento “onClick” analizaremos a variável booleana
“emCamera” para Tirar Foto e Parar o Preview da Câmera.
public void onShutter() {
botaoCamera.setText("Câmera");
emCamera = false;
}
Este é o evento responsável pela ação do clique ao
tirar a foto.
/*
* @param bytes
* @param camera
*/
public void onPictureTaken(byte[] bytes, Camera camera) {
Bitmap foto = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
String arquivo = "theclub.png";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, arquivo);
try {
FileOutputStream out = new FileOutputStream(dest);
foto.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
mCameraView.pararVisualizacao();
}
}
* @param bytes
* @param camera
*/
public void onPictureTaken(byte[] bytes, Camera camera) {
Bitmap foto = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
String arquivo = "theclub.png";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, arquivo);
try {
FileOutputStream out = new FileOutputStream(dest);
foto.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
mCameraView.pararVisualizacao();
}
}
Já o evento “onPictureTaken” receberá como parâmetro uma variável do
tipo “byte[]” e outra do tipo “Camera”. Criaremos um objeto “Bitmap” a qual
armazenaremos em memória o conteúdo fotografado. Definiremos um nome para nossa
foto (Ex: theclub.png) e com o comando “getExternalStorageDirectory”
recuperaremos o diretório de nosso cartão “SD”. A classe “FileOutputStream” e a
“File” fará o trabalho de gravar tudo que está na memória no diretório de nosso
dispositivo móvel.
Podemos conferir o aplicativo funcionando na Imagem 02.
![]() |
Figura 02: Aplicativo funcionando. |
Conclusões
Além de implementar mais alguns recursos na classe “CameraVisualizacao”,
pudemos aprender como fotografar e armazenar arquivos do tipo imagens em
dispositivos móveis. Acredito que este exemplo servirá de base para quem
desejar implantar este tipo de funcionalidade em seus sistemas.
Vou ficando por aqui. Um forte abraço e até o ano que vem!