I am trying to display an image selected by a user using the ACTION_GET_CONTENT intent. I present the user with a chooser to select an image from any app that can respond to this intent.
Intent intent = new Intent();
intent.setType(MediaType.ANY_IMAGE_TYPE.toString());
intent.setAction(Intent.ACTION_GET_CONTENT);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(Intent.createChooser(intent, "Choose Photo"),
Constants.CHOOSE_PHOTO_REQUEST_CODE);
}
When I received the result in onActivityResult
, I get the selected image's URI from Intent.GetData()
. So far, so good.
Now, I want to display the selected image, and I want to make sure it is correctly oriented. For this, I am using ExifInterface
, and falling back on MediaStore Orientation when that fails.
public static Bitmap obtainDecodedBitmap(int targetWidth, int targetHeight, Uri sourceUri, Context context) {
Bitmap bitmap = null;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
try {
InputStream decodeInputStream = context.getContentResolver()
.openInputStream(sourceUri);
InputStream readInputStream = context.getContentResolver()
.openInputStream(sourceUri);
// Get the dimensions of the bitmap
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(decodeInputStream, null, bmOptions);
int inSampleSize = calculateInSampleSize(bmOptions, targetWidth, targetHeight);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = inSampleSize;
bmOptions.inPurgeable = true;
bmOptions.inDither = false;
bmOptions.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeStream(readInputStream, null, bmOptions);
} catch (Exception e) {
e.printStackTrace();
} catch (OutOfMemoryError outOfMemoryError) {
outOfMemoryError.printStackTrace();
}
try {
ExifInterface ei = new ExifInterface(sourceUri.getPath());
int orientation = ei
.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
if (bitmap != null) {
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
bitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
bitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
bitmap = rotateImage(bitmap, 270);
break;
case ExifInterface.ORIENTATION_UNDEFINED:
String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = context.getContentResolver()
.query(sourceUri, orientationColumn, null, null, null);
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
if (orientation != 0) {
bitmap = rotateImage(bitmap, orientation);
}
}
break;
default:
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
This seems to work fine for images chosen using the gallery app, but when selecting an image using Google Photos app, the ExifInterface cannot find the orientation, and the fallback method provides orientation as 0. When I display the image, it is not oriented correctly, but rather it is 90 degrees rotated.
Other apps, such as Twitter, correctly orient the same image in the same scenario (choosing the image from Google Photos). The Google Photos app is also displaying the image thumbnails in the orientation that I expect. What am I doing wrong?
This may appear to be a duplicate of get Path name from Uri Android Lollipop, but the situation isn't identical:
- This is present in pre-lollipop devices.
- I get the correct bitmap, so I know the URI is correct, the only issue is that it is incorrectly oriented.