42

I have gone through some of the links to get the correct image orientation of the image selected from the default image gallery to be worked standard in all devices the exif tag always returns 0.

EXIF orientation tag value always 0 for image taken with portrait camera app android

Exif orientation tag returns 0

Exif data TAG_ORIENTATION always 0

http://mobisocial.stanford.edu/news/2011/08/rotating-images-in-android/

How to get an exact solution that will work on all devices?

Cœur
  • 37,241
  • 25
  • 195
  • 267
ramsraj111
  • 421
  • 1
  • 5
  • 4
  • I have the answer . http://stackoverflow.com/questions/29971319/image-orientation-android/32747566#32747566 – A.Sanchez.SD Sep 23 '15 at 19:18
  • Here is a great one line solution I came across for this: >https://stackoverflow.com/a/34241250/8033090 It can take a second to load but I just put some text behind the image view that says "Loading image" and when the image loads it covers the text. – Andrew Moreau May 28 '17 at 05:16

5 Answers5

113

If the image(photo) was taken by a program made by you, you must set Parameters.setRotation with the correct rotation value.

This, depending of camera drive, rotates the image before save or save the rotation value to exif TAG_ORIENTATION.

Therefore, if TAG_ORIENTATION is null or zero, the image are in the correct orientation, otherwise you must rotate image according the value in TAG_ORIENTATION.

CODE

Get orientation from EXIF:

ExifInterface exif = null;
try {
    exif = new ExifInterface(path);
} catch (IOException e) {
    e.printStackTrace();
}  
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 
                                       ExifInterface.ORIENTATION_UNDEFINED);

Get bitmap rotated:

Bitmap bmRotated = rotateBitmap(bitmap, orientation);  

Method to rotate bitmap:

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;
    }
}
ramaral
  • 6,149
  • 4
  • 34
  • 57
  • 1
    How can i get the image orientation from the gallery of the selected image can you guide me please – ramsraj111 Dec 10 '13 at 16:14
  • 32
    using the exif always returning 0 only – ramsraj111 Dec 12 '13 at 02:30
  • Are those images photos? – ramaral Dec 12 '13 at 13:45
  • I get an OutOfMemoryError every time using this method. I don't think this can work for high-res images. – ashishduh Aug 11 '14 at 19:04
  • 3
    To avoid OutOfMemoryError I just resized the Bitmap before passing it to rotateBitmap() function like: Bitmap myBitmap = BitmapFactory.decodeFile(picturePath); Bitmap resized = Bitmap.createScaledBitmap(myBitmap, 720, 1280, true); photo = rotateBitmap(picturePath, resized); – Phil Jan 13 '15 at 16:08
  • @Phil Nice, but you lose ration between width and height in your resize function. I prefer originalBitmap.getWidth() / 2 and originalBitmap.getHeight() / 2; (you can replace 2 by what you want. – Cocorico Mar 31 '15 at 15:00
  • 1
    If using exif returns 0, you might get the correct orientation by querying the android media store: String[] orientationColumn = {Media.ORIENTATION}; Cursor cur = resolver.query(imageUri, orientationColumn, null, null, null); int orientation = -1; if (cur != null && cur.moveToFirst()) { orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0])); } – Torleif Dec 08 '16 at 11:48
  • Can someone try it with a pixel 3a with Google camera installed even with the emulator – nayan dhabarde Dec 08 '19 at 13:21
5

For me ExifInterface worked quite well like this:

ExifInterface exifInterface = new ExifInterface(imagePath);
degree = Integer.parseInt(exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION));

or you can try to get the details of image using MediaStore like this:

String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
} 

Similar Solution: ExifInterface always returns 1

Hope it helps.. :)

Community
  • 1
  • 1
Ankit Popli
  • 2,809
  • 3
  • 37
  • 61
4

I followed last answer and I tried hard to create a system to manage pictures, rotate, resize, cache and load into ImageViews and I can tell it is a hell. Even when all it was done it crashes sometimes cause OutOfMemory in some devices. Answer is correct but it is difficult to manage Bitmaps in Android.

My point is do not reinvent the wheel, it has a perfect design. Google itself encourage you to use Glide. It works in one line, super easy to use, lightweight in size and functions number, it manage EXIF by default, and it use memory like a charm.. It is simply black magic coded ;)

I'm not sure if Picasso also manages EXIF, but there is a quick intro to both of them:

https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

My Advice: do not waste your time and use them. You can solve your problem in one line:

Glide.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Santi Iglesias
  • 454
  • 4
  • 11
4

For those who come along this post, make sure to use the exifinterface from the Android Support Library that was introduced in December 2016:

compile "com.android.support:exifinterface:25.1.0" // or newer

Details about this library can be found in the according Android Developers Blog post: Introducing the ExifInterface Support Library

They also included a sample code for dealing with rotation information stored in the exif interface:

int rotation = 0;
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

switch (orientation) {
   case ExifInterface.ORIENTATION_ROTATE_90:
     rotation = 90;
     break;
  case ExifInterface.ORIENTATION_ROTATE_180:
     rotation = 180;
     break;
  case ExifInterface.ORIENTATION_ROTATE_270:
     rotation = 270;
     break;
}
Mehlyfication
  • 498
  • 5
  • 9
4

The solution for me was to create the ExifInterface from the input stream. Do not try to create it from a path, which maybe a content provider path and will fail to give the correct result. Convert the orientation into degrees and rotate image if required. Below is the key code for the solution when using the support library (e.g androidx.exifinterface.media.ExifInterface).

int orientation = 0;
InputStream input = mContext.getContentResolver().openInputStream(uri);
if (input != null){
    ExifInterface exif = new ExifInterface(input);
    orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    input.close();
}

Here is my full code to obtain a correctly orientated bitmap selected from the Gallery, which also takes a maxsize. If using it make sure you check for the null return case.

public Bitmap getBitmapFromGalleryUri(Context mContext, Uri uri, Double maxSize)throws IOException {
    int orientation = 0;

    InputStream input = mContext.getContentResolver().openInputStream(uri);
    if (input != null){
        ExifInterface exif = new ExifInterface(input);
        orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        //Log.d("Utils", "rotation value = " + orientation);
        input.close();
    }


    input = mContext.getContentResolver().openInputStream(uri);

    BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
    onlyBoundsOptions.inJustDecodeBounds = true;
    onlyBoundsOptions.inDither = true;//optional
    onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
    BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
    try {
        input.close();

    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
        return null;
    }

    int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;

    double ratio = (originalSize > maxSize) ? (originalSize / maxSize) : 1.0;

    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
    bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
    bitmapOptions.inDither = true; //optional
    bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//
    input = mContext.getContentResolver().openInputStream(uri);
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
    try {
        input.close();

    } catch (NullPointerException e) {
        e.printStackTrace();
    }
    Matrix matrix = new Matrix();

    //Log.d("Utils", "rotation value = " + orientation);

    int rotationInDegrees = exifToDegrees(orientation);
    //Log.d("Utils", "rotationInDegrees value = " + rotationInDegrees);

    if (orientation != 0) {
        matrix.preRotate(rotationInDegrees);
    }

    int bmpWidth = 0;
    try {
        bmpWidth = bitmap.getWidth();
    } catch (NullPointerException e) {
        e.printStackTrace();
    }
    Bitmap adjustedBitmap = bitmap;
    if (bmpWidth > 0) {
        adjustedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    return adjustedBitmap;

}
private static int getPowerOfTwoForSampleRatio(double ratio){
    int k = Integer.highestOneBit((int)Math.floor(ratio));
    if(k==0) return 1;
    else return k;
}

public static int exifToDegrees(int exifOrientation) {
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }
    return 0;
}
Grant Luck
  • 79
  • 3