From 9dee4442162417bc45e03017ee44a6c4d5f28a4c Mon Sep 17 00:00:00 2001 From: Robert Mielnik Date: Mon, 18 Jan 2016 10:40:50 +0100 Subject: [PATCH 1/3] MediaStoreRequestHandler: read MediaStore.Image.ORIENTATION value and translate it to ExifInterface.ORIENTATION_* value. Picasso determines orientation according to ExifInterface.ORIENTATION_*. All possible values in MediaStore.Image.ORIENTATION are: 0, 90, 180, 270 (according to: https://developer.android.com/reference/android/provider/MediaStore.Images.ImageColumns.html#ORIENTATION). The values differ, thus orientation read from MediaStore must be translated to ExifInterface.ORIENTATION_* value. Updated RequestHandler::getExifOrientation description. --- .../picasso/MediaStoreRequestHandler.java | 16 ++++++++++++++-- .../com/squareup/picasso/RequestHandler.java | 9 +++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java index ccf72e3b89..856e23a4d2 100644 --- a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java @@ -20,6 +20,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.media.ExifInterface; import android.net.Uri; import android.provider.MediaStore; import java.io.IOException; @@ -108,10 +109,21 @@ static int getExifOrientation(ContentResolver contentResolver, Uri uri) { if (cursor == null || !cursor.moveToFirst()) { return 0; } - return cursor.getInt(0); + + int rotation = cursor.getInt(0); + switch (rotation) { + case 90: + return ExifInterface.ORIENTATION_ROTATE_90; + case 180: + return ExifInterface.ORIENTATION_ROTATE_180; + case 270: + return ExifInterface.ORIENTATION_ROTATE_270; + default: + return ExifInterface.ORIENTATION_NORMAL; + } } catch (RuntimeException ignored) { // If the orientation column doesn't exist, assume no rotation. - return 0; + return ExifInterface.ORIENTATION_UNDEFINED; } finally { if (cursor != null) { cursor.close(); diff --git a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java index 54798a553b..ceff84b37f 100644 --- a/picasso/src/main/java/com/squareup/picasso/RequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/RequestHandler.java @@ -17,6 +17,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.media.ExifInterface; import android.net.NetworkInfo; import java.io.IOException; import java.io.InputStream; @@ -55,11 +56,13 @@ public static final class Result { private final int exifOrientation; public Result(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) { - this(checkNotNull(bitmap, "bitmap == null"), null, loadedFrom, 0); + this(checkNotNull(bitmap, "bitmap == null"), null, loadedFrom, + ExifInterface.ORIENTATION_UNDEFINED); } public Result(InputStream stream, Picasso.LoadedFrom loadedFrom) { - this(null, checkNotNull(stream, "stream == null"), loadedFrom, 0); + this(null, checkNotNull(stream, "stream == null"), loadedFrom, + ExifInterface.ORIENTATION_UNDEFINED); } Result(Bitmap bitmap, InputStream stream, Picasso.LoadedFrom loadedFrom, int exifOrientation) { @@ -93,6 +96,8 @@ public Picasso.LoadedFrom getLoadedFrom() { /** * Returns the resulting EXIF orientation generated from a {@link #load(Request, int)} call. * This is only accessible to built-in RequestHandlers. + * + * @return MUST return one from values defined as android.media.ExifInterface.ORIENTATION_* */ int getExifOrientation() { return exifOrientation; From c000726dd0c2dd1e5a2f5276d031baab591b9dd7 Mon Sep 17 00:00:00 2001 From: st1hy Date: Wed, 20 Jul 2016 16:11:23 +0200 Subject: [PATCH 2/3] When reading exif in MediaStoreRequestHandler, read file directly with ExifInterface. If file cannot be read use value provided by content resolver. --- .../picasso/MediaStoreRequestHandler.java | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java index 856e23a4d2..f66d99cb8e 100644 --- a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java @@ -23,15 +23,16 @@ import android.media.ExifInterface; import android.net.Uri; import android.provider.MediaStore; + import java.io.IOException; import static android.content.ContentResolver.SCHEME_CONTENT; import static android.content.ContentUris.parseId; import static android.provider.MediaStore.Images; -import static android.provider.MediaStore.Video; import static android.provider.MediaStore.Images.Thumbnails.FULL_SCREEN_KIND; import static android.provider.MediaStore.Images.Thumbnails.MICRO_KIND; import static android.provider.MediaStore.Images.Thumbnails.MINI_KIND; +import static android.provider.MediaStore.Video; import static com.squareup.picasso.MediaStoreRequestHandler.PicassoKind.FULL; import static com.squareup.picasso.MediaStoreRequestHandler.PicassoKind.MICRO; import static com.squareup.picasso.MediaStoreRequestHandler.PicassoKind.MINI; @@ -41,6 +42,9 @@ class MediaStoreRequestHandler extends ContentStreamRequestHandler { private static final String[] CONTENT_ORIENTATION = new String[] { Images.ImageColumns.ORIENTATION }; + private static final String[] CONTENT_DATA = new String[] { + Images.ImageColumns.DATA + }; MediaStoreRequestHandler(Context context) { super(context); @@ -103,6 +107,37 @@ static PicassoKind getPicassoKind(int targetWidth, int targetHeight) { } static int getExifOrientation(ContentResolver contentResolver, Uri uri) { + int exifOrientation = getExitOrientationFromFile(contentResolver, uri); + if (exifOrientation == ExifInterface.ORIENTATION_UNDEFINED) { + exifOrientation = getExifOrientationFromContentResolver(contentResolver, uri); + } + return exifOrientation; + } + + static int getExitOrientationFromFile(ContentResolver contentResolver, Uri uri) { + Cursor cursor = null; + try { + contentResolver.openInputStream(uri); + cursor = contentResolver.query(uri, CONTENT_DATA, null, null, null); + if (cursor == null || !cursor.moveToFirst()) { + return 0; + } + String filePath = cursor.getString(0); + ExifInterface exifInterface = new ExifInterface(filePath); + return exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_UNDEFINED); + + } catch (Exception ignored) { + // In case of error during reading exif, assume no rotation. + return ExifInterface.ORIENTATION_UNDEFINED; + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + static int getExifOrientationFromContentResolver(ContentResolver contentResolver, Uri uri) { Cursor cursor = null; try { cursor = contentResolver.query(uri, CONTENT_ORIENTATION, null, null, null); From 36ddc4ce605c7c9b9d885cd333c7b2e447bd46cb Mon Sep 17 00:00:00 2001 From: st1hy Date: Sun, 31 Jul 2016 10:42:20 +0200 Subject: [PATCH 3/3] Fixed opening input stream without any reason and not closing it. Formatting. --- .../java/com/squareup/picasso/MediaStoreRequestHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java index f66d99cb8e..d65c57130f 100644 --- a/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java +++ b/picasso/src/main/java/com/squareup/picasso/MediaStoreRequestHandler.java @@ -43,7 +43,7 @@ class MediaStoreRequestHandler extends ContentStreamRequestHandler { Images.ImageColumns.ORIENTATION }; private static final String[] CONTENT_DATA = new String[] { - Images.ImageColumns.DATA + Images.ImageColumns.DATA }; MediaStoreRequestHandler(Context context) { @@ -117,7 +117,6 @@ static int getExifOrientation(ContentResolver contentResolver, Uri uri) { static int getExitOrientationFromFile(ContentResolver contentResolver, Uri uri) { Cursor cursor = null; try { - contentResolver.openInputStream(uri); cursor = contentResolver.query(uri, CONTENT_DATA, null, null, null); if (cursor == null || !cursor.moveToFirst()) { return 0;