HOW TO SET CAMERA IMAGE ORIENTATION WITH EXIF METADATA
You like what you Read then Vote!
0 / 5 5 3

Your page rank:

In this tutorial, we are going to learn how to set camera image orientation with exif metadata. If you have used you device camera to take a picture before and thereafter you display the photo on ImageView control. You realized that the shot you took in portrait for now appear in landscape.

Imagine you are developing Image Editor application where user can capture a photo and add filter or whatever to it. Then you find out that most captures do not appear the way they should orientation wise.

One way to handle this problem is by using image EXIF metadata. This metadata information is embedded in images during capture.

To understand how to set camera image orientation with exif metadata, we are going to create an application that will use the device camera to capture an image. The image will then be display on ImageView and if the orientation is not in portrait form, we will click the change orientation button tochange the image orientation to portrait.

Note that we will use android default ExifInterface class to obtain image orientation and we will pass the image orientation value to our imageRotate method.

To get a better understanding of what we plan to achieve, I have add some screen-shots from this application.

CREATE NEW ANDROID PROJECT

Lets start to soil our hands in code. Start up your IDE. For this tutorial, I am using the following tools and environment, feel free to use what works for you.

Windows 10

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 23

To create a new android application project, follow the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidImageOrientation

Package: com.inducesmile.androidimageorientation

Select Blank Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

UPDATE ANDROIDMANIFEST.XML

Open the manifest.xml file inside Manifests folder. We are going to add user permission for read access for external storage. Copy and add the code below to your manifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.inducesmile.androidimageorientation">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

STRINGS.XML

We are going to update our project strings.xml file located in the values folder inside the res folder. Open the file and add the code below to it.

<resources>
    <string name="app_name">EXIF Image Orientation</string>
    <string name="capture_image">CAPTURE IMAGE WITH CAMERA</string>
    <string name="image_orientation">CHANGE PHOTO ORIENTATION</string>
</resources>

COLORS.XML

Open the colors.xml file in the same location as the strings.xml file and add the code below to the file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBlack">#000000</color>
</resources>

ACTIVITY_MAIN.XML

Open the activity_main.xml file that was created for us by Android Studio. This is the main layout for our application.

Since our focus is on how to set camera image orientation with exif metadata, we are going to add two Button and one ImageView Controls.

The first button view will be used to trigger our device camera for image taking and the second button will be used to change the orientation of the captured image.

The ImageView widget will be use to display captured photo.

Copy and paste the code below to your main layout file.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.inducesmile.androidimageorientation.MainActivity">
    <Button
        android:id="@+id/capture_image_with_camera"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:textColor="@color/colorWhite"
        android:text="@string/capture_image"
        android:background="@color/colorPrimaryDark"
        android:padding="12dp"/>
    <ImageView
        android:id="@+id/photo_placeholder"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="@string/app_name"
        android:scaleType="centerCrop"
        android:layout_marginTop="24dp"/>
    <Button
        android:id="@+id/image_orientation_change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:textColor="@color/colorWhite"
        android:text="@string/image_orientation"
        android:background="@color/colorPrimaryDark"
        android:padding="12dp"/>
</LinearLayout>

MAINACTIVITY.JAVA

In the MainActivity class, we will obtain the instances of the View controls in the main layout file.

The button view will have a click event attached to their objects.

To trigger device camera, we will use Intent class with action ACTION_IMAGE_CAPTURE as below.

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE);

In onActivityResult(int requestCode, int resultCode, Intent data) callback method, we will check for runtime permission for READ_EXTERNAL_STORAGE. The Uri and path to the capture image storage is obtained and used to display the image on ImageView.

If the orientation change button is click, we will instantiate an object of ExifInterface and pass the image path as a parameter to its constructor.

The orientation value of the image is obtained by calling the getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED) method.

Open the MainActivity class and add the code below to it.

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private ImageView capturedPhoto;
    private static final int TAKE_PICTURE = 1;
    private static final int REQUEST_READ_PERMISSION = 100;
    private Uri capturedImageUri;
    private String selectedImagePath;
    private Bitmap bitmap;
    private ExifInterface exifObject;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        capturedPhoto = (ImageView)findViewById(R.id.photo_placeholder);
        Button cameraButton = (Button)findViewById(R.id.capture_image_with_camera);
        assert cameraButton != null;
        cameraButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, TAKE_PICTURE);
            }
        });
        Button changeOrientationButton = (Button)findViewById(R.id.image_orientation_change);
        assert changeOrientationButton != null;
        changeOrientationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(capturedPhoto.getDrawable() != null){
                    try {
                        exifObject = new ExifInterface(selectedImagePath);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    int orientation = exifObject.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
                    Bitmap imageRotate = rotateBitmap(bitmap,orientation);
                    capturedPhoto.setImageBitmap(imageRotate);
                }else{
                    Toast.makeText(MainActivity.this, "Image photo is not yet set", Toast.LENGTH_LONG).show();
                }
            }
        });
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK && requestCode == 1) {
            String result = data.toURI();
            capturedImageUri = data.getData();
            try {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_READ_PERMISSION);
                } else {
                    selectedImagePath = getRealPathFromURIPath(capturedImageUri, MainActivity.this);
                    bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), capturedImageUri);
                    capturedPhoto.setImageBitmap(bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "Image path return" + result);
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_READ_PERMISSION) {
            if (grantResults.length == 0) {
                // permission denied
            }else{
                // permission granted
            }
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        if(capturedImageUri != null){
            try {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_READ_PERMISSION);
                } else {
                    selectedImagePath = getRealPathFromURIPath(capturedImageUri, MainActivity.this);
                    bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), capturedImageUri);
                    capturedPhoto.setImageBitmap(bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private String getRealPathFromURIPath(Uri contentURI, Activity activity) {
        Cursor cursor = activity.getContentResolver().query(contentURI, null, null, null, null);
        if (cursor == null) {
            return contentURI.getPath();
        } else {
            cursor.moveToFirst();
            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            return cursor.getString(idx);
        }
    }
    public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
        }
        try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();
            return bmRotated;
        }
        catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }
}

This brings us to the end of this tutorial. I hope that you have learn something. Run your app and see for yourself.

You can download the code for this tutorial below. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address so that you will be among the first to receive my new android blog post once it is published.

Recent Articles

Related Stories

Stay on op - Ge the daily news in your inbox