diff --git a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java index 4662fbbd..f36cff2a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/ComposeActivity.java @@ -18,6 +18,7 @@ package com.keylesspalace.tusky; import android.Manifest; import android.annotation.SuppressLint; import android.app.ProgressDialog; +import android.arch.lifecycle.Lifecycle; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; @@ -135,12 +136,20 @@ import java.util.Locale; import javax.inject.Inject; import at.connyduck.sparkbutton.helpers.Utils; +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; import okhttp3.MediaType; import okhttp3.MultipartBody; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; +import static com.uber.autodispose.AutoDispose.autoDisposable; +import static com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from; + public final class ComposeActivity extends BaseActivity implements ComposeOptionsListener, @@ -1121,11 +1130,24 @@ public final class ComposeActivity DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - Picasso.with(this) - .load(item.uri) - .resize(displayMetrics.widthPixels, displayMetrics.heightPixels) - .onlyScaleDown() - .into(imageView); + Single.fromCallable(() -> + MediaUtils.getSampledBitmap(getContentResolver(), item.uri, displayMetrics.widthPixels, displayMetrics.heightPixels)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY))) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) {} + + @Override + public void onSuccess(Bitmap bitmap) { + imageView.setImageBitmap(bitmap); + } + + @Override + public void onError(Throwable e) { } + }); + int margin = Utils.dpToPx(this, 4); dialogLayout.addView(imageView); diff --git a/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java b/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java index be0c989d..3b9f04d0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/DownsizeImageTask.java @@ -18,16 +18,11 @@ package com.keylesspalace.tusky.util; import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Matrix; import android.net.Uri; import android.os.AsyncTask; -import android.support.annotation.Nullable; -import android.support.media.ExifInterface; -import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; -import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -37,7 +32,6 @@ import java.util.List; * aspect ratio and orientation. */ public class DownsizeImageTask extends AsyncTask { - private static final String TAG = "DownsizeImageTask"; private int sizeLimit; private ContentResolver contentResolver; private Listener listener; @@ -54,83 +48,6 @@ public class DownsizeImageTask extends AsyncTask { this.listener = listener; } - @Nullable - private static Bitmap reorientBitmap(Bitmap bitmap, int orientation) { - Matrix matrix = new Matrix(); - switch (orientation) { - default: - 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; - } - } - try { - Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), - bitmap.getHeight(), matrix, true); - if (!bitmap.sameAs(result)) { - bitmap.recycle(); - } - return result; - } catch (OutOfMemoryError e) { - return null; - } - } - - private static int getOrientation(Uri uri, ContentResolver contentResolver) { - InputStream inputStream; - try { - inputStream = contentResolver.openInputStream(uri); - } catch (FileNotFoundException e) { - Log.d(TAG, Log.getStackTraceString(e)); - return ExifInterface.ORIENTATION_UNDEFINED; - } - if (inputStream == null) { - return ExifInterface.ORIENTATION_UNDEFINED; - } - ExifInterface exifInterface; - try { - exifInterface = new ExifInterface(inputStream); - } catch (IOException e) { - Log.d(TAG, Log.getStackTraceString(e)); - IOUtils.closeQuietly(inputStream); - return ExifInterface.ORIENTATION_UNDEFINED; - } - int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, - ExifInterface.ORIENTATION_NORMAL); - IOUtils.closeQuietly(inputStream); - return orientation; - } - @Override protected Boolean doInBackground(Uri... uris) { resultList = new ArrayList<>(); @@ -147,7 +64,7 @@ public class DownsizeImageTask extends AsyncTask { BitmapFactory.decodeStream(inputStream, null, options); IOUtils.closeQuietly(inputStream); // Get EXIF data, for orientation info. - int orientation = getOrientation(uri, contentResolver); + int orientation = MediaUtils.getImageOrientation(uri, contentResolver); // Then use that information to determine how much to compress. ByteArrayOutputStream stream = new ByteArrayOutputStream(); /* Unfortunately, there isn't a determined worst case compression ratio for image @@ -176,7 +93,7 @@ public class DownsizeImageTask extends AsyncTask { if (scaledBitmap == null) { return false; } - Bitmap reorientedBitmap = reorientBitmap(scaledBitmap, orientation); + Bitmap reorientedBitmap = MediaUtils.reorientBitmap(scaledBitmap, orientation); if (reorientedBitmap == null) { scaledBitmap.recycle(); return false; diff --git a/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java index 2e93fc92..0ad3adb1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/MediaUtils.java @@ -20,6 +20,7 @@ import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Matrix; import android.media.MediaMetadataRetriever; import android.media.ThumbnailUtils; import android.net.Uri; @@ -27,6 +28,7 @@ import android.provider.OpenableColumns; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Px; +import android.support.media.ExifInterface; import android.util.Log; import java.io.ByteArrayOutputStream; @@ -111,7 +113,9 @@ public class MediaUtils { options.inJustDecodeBounds = false; try { stream = contentResolver.openInputStream(uri); - return BitmapFactory.decodeStream(stream, null, options); + Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options); + int orientation = getImageOrientation(uri, contentResolver); + return reorientBitmap(bitmap, orientation); } catch (FileNotFoundException e) { Log.w(TAG, e); return null; @@ -176,4 +180,81 @@ public class MediaUtils { return inSampleSize; } + + @Nullable + public static Bitmap reorientBitmap(Bitmap bitmap, int orientation) { + Matrix matrix = new Matrix(); + switch (orientation) { + default: + 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; + } + } + try { + Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), + bitmap.getHeight(), matrix, true); + if (!bitmap.sameAs(result)) { + bitmap.recycle(); + } + return result; + } catch (OutOfMemoryError e) { + return null; + } + } + + public static int getImageOrientation(Uri uri, ContentResolver contentResolver) { + InputStream inputStream; + try { + inputStream = contentResolver.openInputStream(uri); + } catch (FileNotFoundException e) { + Log.w(TAG, e); + return ExifInterface.ORIENTATION_UNDEFINED; + } + if (inputStream == null) { + return ExifInterface.ORIENTATION_UNDEFINED; + } + ExifInterface exifInterface; + try { + exifInterface = new ExifInterface(inputStream); + } catch (IOException e) { + Log.w(TAG, e); + IOUtils.closeQuietly(inputStream); + return ExifInterface.ORIENTATION_UNDEFINED; + } + int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL); + IOUtils.closeQuietly(inputStream); + return orientation; + } }