Skip to content

Commit d8023cb

Browse files
* DownSample Upload image to be shown in UploadMediaDetailFragment to handle OOM, Bitmap Too large exception
1 parent 3e389be commit d8023cb

File tree

1 file changed

+82
-1
lines changed

1 file changed

+82
-1
lines changed

app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
import android.annotation.SuppressLint;
66
import android.content.Context;
7+
import android.graphics.Bitmap;
8+
import android.graphics.Bitmap.CompressFormat;
9+
import android.graphics.BitmapFactory;
10+
import android.graphics.Rect;
11+
import android.net.Uri;
712
import android.os.Bundle;
13+
import android.provider.MediaStore;
814
import android.text.TextUtils;
915
import android.util.DisplayMetrics;
1016
import android.view.LayoutInflater;
@@ -43,7 +49,17 @@
4349
import fr.free.nrw.commons.utils.DialogUtil;
4450
import fr.free.nrw.commons.utils.ImageUtils;
4551
import fr.free.nrw.commons.utils.ViewUtil;
52+
import io.reactivex.Observable;
53+
import io.reactivex.Scheduler;
54+
import io.reactivex.Single;
55+
import io.reactivex.SingleObserver;
56+
import io.reactivex.android.schedulers.AndroidSchedulers;
4657
import io.reactivex.disposables.Disposable;
58+
import io.reactivex.schedulers.Schedulers;
59+
import java.io.ByteArrayInputStream;
60+
import java.io.ByteArrayOutputStream;
61+
import java.io.File;
62+
import java.io.IOException;
4763
import java.util.ArrayList;
4864
import java.util.Arrays;
4965
import java.util.List;
@@ -284,7 +300,15 @@ public void onImageProcessed(UploadItem uploadItem, Place place) {
284300
}
285301

286302
descriptions = uploadItem.getDescriptions();
287-
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
303+
compositeDisposable
304+
.add(downSampleImage(uploadItem.getContentUri())
305+
.subscribeOn(Schedulers.io())
306+
.observeOn(AndroidSchedulers.mainThread())
307+
.subscribe(bitmap -> {
308+
if (null != bitmap) {
309+
photoViewBackgroundImage.setImageBitmap(bitmap);
310+
}
311+
}, Timber::d));
288312
setDescriptionsInAdapter(descriptions);
289313
}
290314

@@ -435,4 +459,61 @@ private void setDescriptionsInAdapter(List<Description> descriptions) {
435459
}
436460
}
437461

462+
/**
463+
* Downsample bitmap to handle OOM/Bitmap too large exception
464+
*
465+
* @param uri
466+
* @return
467+
*/
468+
private Single<Bitmap> downSampleImage(Uri uri) {
469+
Bitmap existing = null;
470+
try {
471+
existing = MediaStore.Images.Media
472+
.getBitmap(this.getContext().getContentResolver(), uri);
473+
} catch (IOException e) {
474+
e.printStackTrace();
475+
}
476+
477+
if (null == existing) {
478+
return Single.error(new Throwable("could not downsample"));
479+
}
480+
481+
final int requiredHeight = getResources().getDisplayMetrics().heightPixels;
482+
final int requiredWidth = getResources().getDisplayMetrics().widthPixels;
483+
484+
// Raw height and width of image
485+
final int height = existing.getHeight();
486+
final int width = existing.getWidth();
487+
int inSampleSize = 1;
488+
489+
if (height > requiredHeight || width > requiredWidth) {
490+
491+
final int halfHeight = height / 2;
492+
final int halfWidth = width / 2;
493+
494+
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
495+
// height and width larger than the requested height and width.
496+
while ((halfHeight / inSampleSize) >= requiredHeight
497+
&& (halfWidth / inSampleSize) >= requiredWidth) {
498+
inSampleSize *= 2;
499+
}
500+
}
501+
502+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
503+
existing.compress(CompressFormat.PNG, 0, byteArrayOutputStream);
504+
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
505+
byteArrayOutputStream.toByteArray());
506+
// First decode with inJustDecodeBounds=true to check dimensions
507+
final BitmapFactory.Options options = new BitmapFactory.Options();
508+
Rect rect = new Rect(0, 0, 0, 0);
509+
options.inJustDecodeBounds = false;
510+
options.inSampleSize = inSampleSize;
511+
Bitmap modified = BitmapFactory.decodeStream(byteArrayInputStream, rect, options);
512+
if (modified != null) {
513+
return Single.just(modified);
514+
} else {
515+
return Single.error(new Throwable("could not downsample"));
516+
}
517+
}
518+
438519
}

0 commit comments

Comments
 (0)