OutOfMemoryError with emodo/cropper library when using getCroppedImage - android

I am using edmodo/cropper library to crop the image after the user has taken the image from camera.
Link: https://github.com/edmodo/cropper/wiki
I got this issue on device GT-N7000 and some other android phones.
java.lang.OutOfMemoryError
1 at android.graphics.Bitmap.nativeCreate(Native Method)
2 at android.graphics.Bitmap.createBitmap(Bitmap.java:669)
3 at android.graphics.Bitmap.createBitmap(Bitmap.java:604)
4 at android.graphics.Bitmap.createBitmap(Bitmap.java:530)
5 at com.edmodo.cropper.CropImageView.getCroppedImage(CropImageView.java:357)
Does anyone know how to solve this issue. Please help me ,the device keep getting crashes.

I solved it by subsampling the captured image before storing it in cropView using BitmapFactory.Options.
Here is the code:
// setting path to the clicked image and cropped image
path_click = "sdcard/Pictures/Candice/Clicked.jpg";
path_crop = "sdcard/Pictures/Candice/Cropped.jpg";
final BitmapFactory.Options options = new BitmapFactory.Options();
//If set to a value > 1,requests the decoder to subsample the
//original image, returning a smaller image to save memory.
options.inSampleSize = 2;
clickedImage = BitmapFactory.decodeFile(path_click, options);
cropImageView.setImageBitmap(clickedImage);
// Sets initial aspect ratio to 10/10, for demonstration purposes
cropImageView.setAspectRatio(DEFAULT_ASPECT_RATIO_VALUES,
DEFAULT_ASPECT_RATIO_VALUES);
cropButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Here we save the cropped image and then call the next
// activity
// To retrieve the image contained within the Cropper window,
// use the provided method, getCroppedImage() to retrieve a
// Bitmap of the cropped image.
croppedImageBitmap = cropImageView.getCroppedImage();
/** Save cropped image to SD card using output streams **/
// An output stream that writes bytes to a file.
// If it does not exist, a new file will be created.
FileOutputStream out = null;
try {
out = new FileOutputStream(path_crop);
// Writing a compressed version of bitmap to outputstream.
croppedImageBitmap.compress(Bitmap.CompressFormat.JPEG, 90,
out);
// Just after compression,add
croppedImageBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
startActivity(chooseIntent);
}
});

I don't know how big is your image, but have you tried adding android:largeHeap="true" to your <application> tag in the AndroidManifest.xml?

Related

How do I tell BitmapFactory.decodeStream to give me a full quality image?

So I have the following code in an AsyncTask. The AsyncTask takes in a url to an image file, downloads it into a Bitmap, saves the Bitmap off to disk somewhere, and then displays the Bitmap in an existing ImageView.
Here's the implementation of the doInBackground() call for my AsyncTask:
protected Bitmap doInBackground(String... urls) {
try {
URL image_url = new URL(urls[0]);
String image_url_prefix_regex = "http://www\\.somewebsite\\.com";
if (externalStorageIsAvailable()) {
String file_path = getExternalFilesDir(null).getPath() + image_url.toString().replaceAll(image_url_prefix_regex, "");
File target_file = new File(file_path);
if (!target_file.getParentFile().exists()) {
target_file.getParentFile().mkdirs();
}
BitmapFactory.Options bitmap_options = new BitmapFactory.Options();
bitmap_options.inScaled = false;
bitmap_options.inDither = false;
bitmap_options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap_options.inPreferQualityOverSpeed = true;
bitmap_options.inSampleSize = 1;
Bitmap image = BitmapFactory.decodeStream(image_url.openStream(), null, bitmap_options);
image.compress(CompressFormat.JPEG, 100, new FileOutputStream(target_file));
return image;
}
}
catch (MalformedURLException e) {
Log.v(DEBUG_TAG, "Error: Caught MalformedURLException");
}
catch (IOException e) {
Log.v(DEBUG_TAG, "Error: Caught IOException");
}
return null;
}
Then later in the onPostExecute() call I have this:
protected void onPostExecute(Bitmap image) {
ImageView mImageView = (ImageView) findViewById(R.id.main_image);
mImageView.setImageBitmap(image);
}
Yet when the code downloads and displays the image, the image is reduced in size and quality. How do I make it so that the resulting image is full quality? Those BitmapFactory.Options settings are the things I've tried thus far, but they did not seem to work.
Note that I'm not asking about the image that gets saved to external storage. I think that one will likely be of lower quality due to getting compressed again, but that shouldn't affect the image I'm sending to my ImageView, which is what I'm asking about. Of course, if there's anything wrong with these assumptions please point them out.
Why you are using Bitmap factory options while decoding bitmap Stream ?
Just use the
Bitmap image = BitmapFactory.decodeStream(image_url.openStream());
instead of
Bitmap image = BitmapFactory.decodeStream(image_url.openStream(), null, bitmap_options);

Android ImageButton setImageBitmap goes on the wrong element

I have a situation with three image buttons:
Take a photo by the camera
Delete the photo
Show a cropped2fit version of the image taken
I'm using the camera of the phone.
My problem is that SOMETIMES, apparently without no explanation, when I set the photo with setImageBitmap, it goes on the wrong imageButton (seems to be always the delete button, but I'm not really sure). Rebooting the device seems to solve the problem.
The code is as simple as it should be: I use findViewById casting the object into an ImageButton and setting the image with setImageBitmap.
ImageView iv = ((ImageView) findViewById(R.id.imgFotoPrima));
iv.setImageBitmap(fn.setupImage(data, PrimaOutputFileUri));
iv.setScaleType(ScaleType.CENTER_CROP);
public static Bitmap setupImage(Intent data, Uri outputFileUri) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; // SAMPLE_SIZE = 2
Bitmap tempBitmap = null;
Bitmap bm = null;
try {
tempBitmap = (Bitmap) data.getExtras().get("data");
bm = tempBitmap;
Log.v("ManageImage-hero", "the data.getData seems to be valid");
FileOutputStream out = new FileOutputStream(outputFileUri.getPath());
tempBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
}
catch (NullPointerException ex) {
Log.v("ManageImage-other", "another phone type");
bm = otherImageProcessing(options, outputFileUri);
}
catch (Exception e) {
Log.e("ManageImage-setupImage", "problem setting up the image", e);
}
return bm;
}
The elements in the xml have different id.
I've tried the application on a Lenovo (7') and a Galaxy Tab 7 II.
It seems to happen only on the Galaxy Tab.
Could it be a problem on the tablet?? Anyone in my situation?

How can I set an image from a file path?

I'm saving an image from the device's camera to a directory on the SD card (ex: /sdcard/appName/image.jpg), then I save the path into a database. My problem is that I can't seem to load the images into a ListView with a cursor adapter.
I tried the following code, where helper.getImg(); is a method from my database helper that returns a String (the file path), but it is not working.
icon=(ImageView)row.findViewById(R.id.icon_pura);
String imgPath=helper.getImg(c);
Bitmap myBitmap=BitmapFactory.decodeFile(imgPath);
icon.setImageBitmap(myBitmap);
the answer has to do with URIs, and you need to use the externalstorage() function. Using set paths won't work on every device
anyway you store path into the URI which is more flexible for retrieving and parsings items at that path
String filepath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Directory name/";
File file = new File(filepath,imagename);
FileInputStream fs = null;
try
{
fs = new FileInputStream(file);
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BitmapFactory.Options bfOptions = new BitmapFactory.Options();
/*
* bfOptions.inDither=false; //Disable Dithering mode
* bfOptions.inPurgeable=true; //Tell to gc that whether it needs
* free memory, the Bitmap can be cleared
* bfOptions.inInputShareable=true;*/
bfOptions.inJustDecodeBounds = false;
bfOptions.inTempStorage = new byte[32 * 1024];
try {
Bitmap originalImage = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,bfOptions);
icon.setImageBitmap(originalImage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
If you follow himanshu's (correct) advice, make sure that if you're going to allow the user the option of loading and re-loading the image, make sure to manually icon.setImageBitmap(null); between loads, because otherwise Android will leak that memory and you'll crash your app. It's not 100% consistant, and has something to do with the sizes of the images you're loading, but I just found this leak a few days ago and am 100% certain that it's there.

resizing images in gallery for image processing app. android

i've an image processing app. If i take a picture using the part of the app that captures the image, the image is eventually displayed corectly on the screen. This is because i have specified camera params using the hardwares screen size. if i try to load an image that was taken from the phone's camera (not the app's camera), then the image is too large on the screen and sometimes too large from a byte point of view. how can i resize or compress the images in the gallery so that my app can use them? thanks
public class DisplayUndistortedBitmapFromGalleryActivity extends Activity {
private static final String TAG = "*********DUBFGActivity";
private Context mContext = this;
Uri uri;
private Bitmap mbitmap = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
uri = getIntent().getData();
if(uri != null){
Log.e(TAG, "uri ok");
}else {
Log.e(TAG, "uri not ok");
}
try {
mbitmap = Media.getBitmap(getContentResolver(), uri);
//setMbitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(mbitmap == null){
Log.e(TAG,"mbitmap is null");
}else{
Log.e(TAG,"mbitmap is not null");
}
.
public class DisplayUndistortedBitmapFromGallery extends View{
public DisplayUndistortedBitmapFromGallery(Context context) {
super(context);
}
public DisplayUndistortedBitmapFromGallery(Context context, AttributeSet attr) {
super(context,attr);
Log.e(TAG, "++++++++++ inside dubfgview constructor");
Bitmap bm = ((DisplayUndistortedBitmapFromGalleryActivity)getContext()).getMbitmap();
if(bm == null){
Log.e(TAG, "bm = null");
}else{
Log.e(TAG, "bm = not null");
}
bgr = bm.copy(bm.getConfig(), true);
If I understand your question correctly there are two problems. The first is that the ImageView isn't scaling the image to fit the screen and the second is that the Bitmaps are requiring too much RAM.
To solve the first problem simply tell the image view how you want the image to be scaled. Simply do the following:
imgView.setScaleType(ImageView.ScaleType.INSERT_SCALE_TYPE);
Here is a list of the different scale types.
If this doesn't solve the problem make sure the bounds of your ImageView aren't too large. Try hardcoding the size of the ImageView to something specific and see if that fixes the problem.
The second problem is really easy to fix. You simply need to tell BitmapFactory to downsample the image when its loaded. Here is an example:
int inSample = 4; // specifies how many 1/N samples to keep, in this case 1/4 off all samples are kept
opts = new BitmapFactory.Options();
opts.inSampleSize = inSample;
Bitmap b = BitmapFactory.decodeResource(c.getResources(), imgResId, opts);
For a more longer explanation see my answer to this question: Android GalleryView Recycling

creating a drawable from sd card to set as a background in android

I am trying to use an image from the sd card and set it as the background for a relativelayout. I have tried other solutions that i have found here and elsewhere but they havent seemed to work for me. here is my code. I have commented out other ways that i have tried and didnt work. the only thing that worked for me was using setBackgroudnResource and using a resource from the app, but this was just to test to make sure mRoot was set up correctly. when I have tried all the other ways, it just doesn't set anything. Anyone know what I am doing wrong, or if there is a better way to do this?
//one way i tired...
//String extDir = Environment.getExternalStorageDirectory().toString();
//Drawable d = Drawable.createFromPath(extDir + "/pic.png");
//mRoot.setBackgroundDrawable(d);
//another way tried..
//Drawable d = Drawable.createFromPath("/sdcard/pic.png");
//mRoot.setBackgroundDrawable(d);
//last way i tried...
mRoot.setBackgroundDrawable(Drawable.createFromPath(new File(Environment.getExternalStorageDirectory(), "pic.png").getAbsolutePath()));
//worked, only to verify mRoot was setup correctly and it could be changed
//mRoot.setBackgroundResource(R.drawable.bkg);
You do not load a drawable from SD card but a bitmap. Here is a method to load it with the reduced sampling (quality) so the program will not complain if the image is too large. Then I guess you need to process this bitmap i.e. crop it and resize for the background.
// Read bitmap from Uri
public Bitmap readBitmap(Uri selectedImage) {
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //reduce quality
AssetFileDescriptor fileDescriptor =null;
try {
fileDescriptor = this.getContentResolver().openAssetFileDescriptor(selectedImage,"r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
try {
bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);
fileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}
The Uri here can be supplied from a gallery picker activity.
The image then can be saved into application resources and loaded into an imageView
private void saveBackground(Bitmap Background) {
String strBackgroundFilename = "background_custom.jpg";
try {
Background.compress(CompressFormat.JPEG, 80, openFileOutput(strBackgroundFilename, MODE_PRIVATE));
} catch (Exception e) {
Log.e(DEBUG_TAG, "Background compression and save failed.", e);
}
Uri imageUriToSaveCameraImageTo = Uri.fromFile(new File(BackgroundSettings.this.getFilesDir(), strBackgroundFilename));
// Load this image
Bitmap bitmapImage = BitmapFactory.decodeFile(imageUriToSaveCameraImageTo.getPath());
Drawable bgrImage = new BitmapDrawable(bitmapImage);
//show it in a view
ImageView backgroundView = (ImageView) findViewById(R.id.BackgroundImageView);
backgroundView.setImageURI(null);
backgroundView.setImageDrawable(bgrImage);
}
File file = new File( url.getAbsolutePath(), imageUrl);
if (file.exists()) {
mDrawable = Drawable.createFromPath(file.getAbsolutePath());
}
I suggest checking that the drawable is being loaded correctly. Some things to try:
Try using a different image on the sd card
Put pic.png in R.drawable and make sure mRoot.setBackgroundResource() does what you expect
After loading the drawable, check d.getBounds() to make sure it is what you expect

Categories

Resources