Merge pull request #23 from wymsee/android_oom

Out of memory exception on rotate of images
This commit is contained in:
CSullivan102
2014-09-04 09:42:05 -04:00
2 changed files with 86 additions and 46 deletions
@@ -483,6 +483,8 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi
private class ResizeImagesTask extends AsyncTask<Set<Entry<String, Integer>>, Void, ArrayList<String>> {
private Exception asyncTaskError = null;
@Override
protected ArrayList<String> doInBackground(Set<Entry<String, Integer>>... fileSets) {
Set<Entry<String, Integer>> fileNames = fileSets[0];
@@ -493,6 +495,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi
while(i.hasNext()) {
Entry<String, Integer> imageInfo = i.next();
File file = new File(imageInfo.getKey());
int rotate = imageInfo.getValue().intValue();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inJustDecodeBounds = true;
@@ -506,41 +509,43 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi
int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight);
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
if (bmp == null) {
throw new IOException("The image file could not be opened.");
try {
bmp = this.tryToGetBitmap(file, options, rotate, true);
} catch (OutOfMemoryError e) {
options.inSampleSize = calculateNextSampleSize(options.inSampleSize);
try {
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch (OutOfMemoryError e2) {
throw new IOException("Unable to load image into memory.");
}
}
scale = calculateScale(options.outWidth, options.outHeight);
bmp = this.getResizedBitmap(bmp, scale);
} else {
try {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
bmp = this.tryToGetBitmap(file, null, rotate, false);
} catch(OutOfMemoryError e) {
options = new BitmapFactory.Options();
options.inSampleSize = 2;
try {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch(OutOfMemoryError e2) {
options = new BitmapFactory.Options();
options.inSampleSize = 4;
bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
try {
bmp = this.tryToGetBitmap(file, options, rotate, false);
} catch (OutOfMemoryError e3) {
throw new IOException("Unable to load image into memory.");
}
}
}
}
int rotate = imageInfo.getValue().intValue();
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
file = this.storeImage(bmp, file.getName());
al.add(Uri.fromFile(file).toString());
}
return al;
} catch(IOException e) {
try {
asyncTaskError = e;
for (int i = 0; i < al.size(); i++) {
URI uri = new URI(al.get(i));
File file = new File(uri);
@@ -557,22 +562,49 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi
@Override
protected void onPostExecute(ArrayList<String> al) {
Intent data = new Intent();
if (al.size() > 0) {
if (asyncTaskError != null) {
Bundle res = new Bundle();
res.putString("ERRORMESSAGE", asyncTaskError.getMessage());
data.putExtras(res);
setResult(RESULT_CANCELED, data);
} else if (al.size() > 0) {
Bundle res = new Bundle();
res.putStringArrayList("MULTIPLEFILENAMES", al);
if (imagecursor != null) {
res.putInt("TOTALFILES", imagecursor.getCount());
}
data.putExtras(res);
setResult(RESULT_OK, data);
} else {
setResult(RESULT_CANCELED, data);
}
progress.dismiss();
finish();
}
private Bitmap tryToGetBitmap(File file, BitmapFactory.Options options, int rotate, boolean shouldScale) throws IOException, OutOfMemoryError {
Bitmap bmp;
if (options == null) {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
} else {
bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
}
if (bmp == null) {
throw new IOException("The image file could not be opened.");
}
if (options != null && shouldScale) {
float scale = calculateScale(options.outWidth, options.outHeight);
bmp = this.getResizedBitmap(bmp, scale);
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
return bmp;
}
/*
* The following functions are originally from
@@ -631,6 +663,11 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi
return inSampleSize;
}
private int calculateNextSampleSize(int sampleSize) {
double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2));
return (int)Math.pow(logBaseTwo + 1, 2);
}
private float calculateScale(int width, int height) {
float widthScale = 1.0f;
@@ -17,53 +17,56 @@ import android.content.Intent;
import android.util.Log;
public class ImagePicker extends CordovaPlugin {
public static String TAG = "ImagePicker";
private CallbackContext callbackContext;
private JSONObject params;
public static String TAG = "ImagePicker";
private CallbackContext callbackContext;
private JSONObject params;
public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
this.params = args.getJSONObject(0);
this.callbackContext = callbackContext;
this.params = args.getJSONObject(0);
if (action.equals("getPictures")) {
Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class);
int max = 20;
int desiredWidth = 0;
int desiredHeight = 0;
int quality = 100;
int desiredHeight = 0;
int quality = 100;
if (this.params.has("maximumImagesCount")) {
max = this.params.getInt("maximumImagesCount");
max = this.params.getInt("maximumImagesCount");
}
if (this.params.has("width")) {
desiredWidth = this.params.getInt("width");
desiredWidth = this.params.getInt("width");
}
if (this.params.has("height")) {
desiredWidth = this.params.getInt("height");
desiredWidth = this.params.getInt("height");
}
if (this.params.has("quality")) {
quality = this.params.getInt("quality");
}
quality = this.params.getInt("quality");
}
intent.putExtra("MAX_IMAGES", max);
intent.putExtra("WIDTH", desiredWidth);
intent.putExtra("HEIGHT", desiredHeight);
intent.putExtra("QUALITY", quality);
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0);
}
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0);
}
}
return true;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && data != null) {
ArrayList<String> fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES");
JSONArray res = new JSONArray(fileNames);
this.callbackContext.success(res);
} else if (resultCode == Activity.RESULT_CANCELED) {
JSONArray res = new JSONArray();
this.callbackContext.success(res);
} else {
this.callbackContext.error("No images selected");
}
if (resultCode == Activity.RESULT_OK && data != null) {
ArrayList<String> fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES");
JSONArray res = new JSONArray(fileNames);
this.callbackContext.success(res);
} else if (resultCode == Activity.RESULT_CANCELED && data != null) {
String error = data.getStringExtra("ERRORMESSAGE");
this.callbackContext.error(error);
} else if (resultCode == Activity.RESULT_CANCELED) {
JSONArray res = new JSONArray();
this.callbackContext.success(res);
} else {
this.callbackContext.error("No images selected");
}
}
}