Corrigir orientação e redimensionar imagem depois de capturar foto.

2 Flares Twitter 0 Facebook 1 Google+ 1 LinkedIn 0 Filament.io 2 Flares ×

Quando você precisa fazer a captura de uma imagem utilizando a câmera do Android existem alguns detalhes que é necessário dar atenção. Vamos começar com a chamada da câmera em si. É preciso passar como parâmetro o caminho onde deve ser ser salvo o arquivo e também um identificador pra conseguirmos capturar o resultado. Abaixo a chamada da intent da câmera:

private static final int TIRAR_FOTO = 1020394857;

public void chamaCamera() {
	local_foto = Environment.getExternalStorageDirectory() + "/Comparador/loja/"+loja_id+".png";
	tempFile = new File(local_foto); 
	outputFileUri = Uri.fromFile(tempFile);

	Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
	intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
	startActivityForResult(intent, TIRAR_FOTO);
	if (tempFile.exists()){ 
        	tempFile.delete(); 
	}
}

Para salvar a foto é preciso capturar o resultado da activity conforme abaixo:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (requestCode == TIRAR_FOTO) {
		if (resultCode == RESULT_OK) {
			foto = (ImageView) findViewById(R.id.foto);
			ajustaFoto();
			String local_foto = Environment.getExternalStorageDirectory() + "/diretorio/"+nome_da_foto+".png";
			File fileFoto = new File(local_foto); 
			Bitmap bitmap = BitmapFactory.decodeFile(local_foto);
			foto.setImageBitmap(bitmap);
		} else if (resultCode == RESULT_CANCELED) {
			Toast.makeText(getBaseContext(), "A captura foi cancelada", Toast.LENGTH_SHORT);
		} else {
			Toast.makeText(getBaseContext(), "A câmera foi fechada", Toast.LENGTH_SHORT);
		}
	}
}

Agora é que vem o pulo do gato. O resultado dessa captura é exibido sempre na mesma orientação. Veja abaixo um comparativo de como a foto foi tirada e como ela será exibida quando você atribuir a uma ImageView:

Mas porque a imagem é exibida em outra orientação? Isso ocorre pois o ImageView entende que todas as imagens são tiradas com o  celular na horizontal. Outra questão é que nem sempre precisamos obter as imagens em alta resolução e se formos exibir várias delas estamos ocupando memória desnecessária do sistema. Sendo assim precisamos diminuir a qualidade da imagem e como não sabemos qual a qualidade da câmera do aparelho precisamos fazer alguns cálculos para ter uma imagem com uma  resolução aproximada sempre. Notem que no código acima é feita uma chamada da função ajustaFoto(). Essa função ajusta a orientação e reduz a imagem para o tamanho que você definir, no exemplo abaixo estou reduzindo para um tamanho onde a dimensão maior (altura ou largura) fique com 256 pixels. Isso acaba gerando um arquivo de aproximadamente 80KB.

Pirei na camiseta Google Maps (http://www.linuxmall.com.br/produto/camiseta-google-maps.html) do @LinuxMall. Quem teve essa ideia acertou na mosca, ou melhor, no Wally. #OsNerdPira!

protected void ajustaFoto(){
	getContentResolver().notifyChange(outputFileUri, null);
	ContentResolver cr = getContentResolver();
	Bitmap bitmap = null;
	int w = 0;
	int h = 0;
	Matrix mtx = new Matrix();

	// Ajusta orientação da imagem
	try {
		// joga a imagem em uma variável
		bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, outputFileUri);

		// captura as dimensões da imagem
		w = bitmap.getWidth();
		h = bitmap.getHeight();
		mtx = new Matrix();

		// pega o caminho onda a imagem está salva
		ExifInterface exif = new ExifInterface(tempFile.getAbsolutePath());

		// pega a orientação real da imagem
		int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

		// gira a imagem de acordo com a orientação
		switch(orientation) {
			case 3: // ORIENTATION_ROTATE_180
				mtx.postRotate(180);
				break;
			case 6: //ORIENTATION_ROTATE_90
				mtx.postRotate(90);
				break;
			case 8: //ORIENTATION_ROTATE_270
				mtx.postRotate(270);
				break;
			default: //ORIENTATION_ROTATE_0
				mtx.postRotate(0);
				break;
		}
	}

	// cria variável com a imagem rotacionada
	Bitmap rotatedBmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
	BitmapDrawable bmpd = new BitmapDrawable(rotatedBmp);

	// redimensiona a imagem 
	Integer lateral = 256; // tamanho final da dimensão maior da imagem
	try {
		// cria um stream pra salvar o arquivo
		FileOutputStream out = new FileOutputStream(local_foto);

		// uma nova instancia do bitmap rotacionado
		Bitmap bmp = bmpd.getBitmap();

		//define um indice = 1 pois se der erro vai manter a imagem como está.
		Integer idx = 1;

		// reupera as dimensões da imagem
		w = bmp.getWidth();
		h = bmp.getHeight();

		// verifica qual a maior dimensão e divide pela lateral final para definir qual o indice de redução
		if ( w >= h){
			idx = w / lateral;
		} else {
			idx = h / lateral;
		}

		// acplica o indice de redução nas novas dimensões
		w = w / idx;
		h = h / idx;

		// cria nova instancia da imagem já redimensionada
		Bitmap bmpReduzido = Bitmap.createScaledBitmap(bmp, w, h, true);

		// salva a imagem reduzida no disco
		bmpReduzido.compress(Bitmap.CompressFormat.PNG, 90, out);
	}		
}

A última coisa que precisa ser feita antes de executar a app é incluir no AndroidManifest.xml as permissões para usar a câmera e escrever no cartão SD, que é onde você deve estar salvando suas imagens.

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />

Pronto. Como resultado teremos uma imagem reduzida e na orientação desejada após ser capturada pela câmera, e ela poderá ser exibida na aplicação corretamente.