Como corrigir a orientação das fotos no Android

Imagina que você tá usando o seu aplicativo bacana pra tirar fotos e aplicar uns filtros marotos. Você vira o celular de lado para enquadrar melhor a foto e quando vai ver o resultado percebe que a foto saiu desse jeito:

Por que a orientação está incorreta?

Mas por que será que isso aconteceu?

Isso acontece porque o sensor da câmera é fixo e não sabe como o dispositivo está posicionado quando a foto é tirada. O papel dele é simplesmente capturar a imagem. Ah, mas quando tiramos uma foto com o celular virado de lado e abrimos a foto na galeria ela tá com a orientação correta!

Verdade! Isso mostra pra gente que tem alguém no meio do caminho fazendo algum tipo de correção pra mostrar a foto direitinho. Bom, o sensor da câmera é fixo mas sabemos que as câmeras digitais e também nossos smartphones tem aqueles sensores de orientação pra saber quando devem virar a tela. O que eles fazem então é salvar a imagem juntamente com essa informação da orientação justamente pra que a gente consiga corrigir depois.

Pra salvar essas informações extras, praticamente toda câmera digital salva as imagens no formato Exif que permite armazenar algumas tags com informações como data, hora, geolocalização e também a orientação da câmera no momento da captura. Isso significa que para mostrar uma foto no seu aplicativo com a orientação correta, você só precisa conseguir ler esses dados extras e descobrir qual correção aplicar antes de exibir a foto!

Mãos à obra então! Vamos criar uma classe que consiga devolver pra gente um Bitmap corrigido a partir do caminho de uma foto. Usaremos a classe ExifInterface para acessar as informações extras da imagem e descobrir a orientação da foto:


public class CarregadorDeFoto {
    public static Bitmap carrega(String caminhoFoto) {
        ExifInterface exif = new ExifInterface(caminhoFoto);
        String orientacao = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
    } 
} 

Agora que temos a orientação, só precisamos descobrir qual rotação devemos aplicar ao abrir o Bitmap. Para isso, vamos comparar a orientação que obtivemos da ExifInterface com algumas constantes que já estão prontas. Como essas constantes são do tipo inteiro, vamos ter que converter a orientação que pegamos da ExifInterface pra inteiro antes de fazer a comparação:


public class CarregadorDeFoto {
    public static Bitmap carrega(String caminhoFoto) {
        ExifInterface exif = new ExifInterface(caminhoFoto);
        String orientacao = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        int codigoOrientacao = Integer.parseInt(orientacao);

        switch (codigoOrientacao) {
            case ExifInterface.ORIENTATION_NORMAL:
                // rotaciona 0 graus no sentido horário
            case ExifInterface.ORIENTATION_ROTATE_90:
                // rotaciona 90 graus no sentido horário
            case ExifInterface.ORIENTATION_ROTATE_180:
                // rotaciona 180 graus no sentido horário
            case ExifInterface.ORIENTATION_ROTATE_270:
                // rotaciona 270 graus no sentido horário
        } 
    } 
} 

Agora só precisamos criar mais um método que abra a imagem como um Bitmap e faça a rotação de acordo com a correção a ser aplicada.


private Bitmap abreFotoERotaciona(String caminhoFoto, int angulo) {
    // Abre o bitmap a partir do caminho da foto
    Bitmap bitmap = BitmapFactory.decodeFile(caminhoFoto);

    // Prepara a operação de rotação com o ângulo escolhido 
    Matrix matrix = new Matrix();
    matrix.postRotate(angulo);

    // Cria um novo bitmap a partir do original já com a rotação aplicada 
    return Bitmap.createBitmap(bitmap, 0, 0, 
                               bitmap.getWidth(), bitmap.getHeight(), 
                               matrix, true);
}

Pronto! Agora só precisamos utilizar esse método na nossa classe que carrega as fotos. Veja como fica o código completo:


public class CarregadorDeFoto {
    public static Bitmap carrega(String caminhoFoto) {
        ExifInterface exif = new ExifInterface(caminhoFoto);
        String orientacao = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        int codigoOrientacao = Integer.parseInt(orientacao);

        switch (codigoOrientacao) {
            case ExifInterface.ORIENTATION_NORMAL:
                return abreFotoERotaciona(caminhoFoto, 0);
            case ExifInterface.ORIENTATION_ROTATE_90:
                return abreFotoERotaciona(caminhoFoto, 90);
            case ExifInterface.ORIENTATION_ROTATE_180:
                return abreFotoERotaciona(caminhoFoto, 180);
            case ExifInterface.ORIENTATION_ROTATE_270:
                return abreFotoERotaciona(caminhoFoto, 270);
        } 
    } 

    private Bitmap abreFotoERotaciona(String caminhoFoto, int angulo) {
        // Abre o bitmap a partir do caminho da foto
        Bitmap bitmap = BitmapFactory.decodeFile(caminhoFoto);

        // Prepara a operação de rotação com o ângulo escolhido 
        Matrix matrix = new Matrix();
        matrix.postRotate(angulo);

        // Cria um novo bitmap a partir do original já com a rotação aplicada 
        return Bitmap.createBitmap(bitmap, 0, 0, 
                                   bitmap.getWidth(), bitmap.getHeight(), 
                                   matrix, true);
    }
} 

Legal! Então agora só precisamos usar essa classe toda vez que formos carregar uma imagem. Então se a gente tiver uma Activity com uma ImageView pra mostrar uma foto, poderíamos usar nossa classe assim:


public class VisualizadorDeFoto extends AppCompatActivity {

    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_visualizador);

        ImageView campoFoto = (ImageView) findViewById(R.id.campoFoto);
        Bitmap bitmap = CarregadorDeFoto.carrega("foto_supimpa.jpg");
        campoFoto.setImageBitmap(bitmap);
    }

}

Agora sim já podemos mostrar nossas fotos sem se preocupar se elas foram tiradas com o celular de pé ou de lado!

O que você achou dessa dica? Também já passou por esse problema e resolveu de outro jeito? Conta pra gente! Se quiser aprender mais sobre desenvolvimento pra mobile, dá uma olhadinha nos cursos mobile do Alura ou nos cursos presenciais da Caelum!


Próximo Artigo8 ferramentas que vão tornar o seu trabalho remoto mais produtivo