MediaStore.Images.Media.getBitmap and out of memory error - android

My code code is:
public Bitmap loadPhoto(Uri uri) {
Bitmap scaled = null;
try {
scalled = Bitmap.createBitmap(
MediaStore.Images.Media.getBitmap(getContentResolver(), uri),
0,0,90, 90);
if (scaled == null) { return null; }
} catch(Exception e) { }
return scaled;
}
After this. I display scaled in ImageView. Every image comes from the device camera.
Every time, I get error: out of memory after I display three photos from camera. How to solve this?

Answer of Praveen Katha will always return null. Here is the updated answer.
Here is the trick, close the input stream after every use. Input Stream means to be used one time. For more information, please follow this answer
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromUri(Context context, Uri imageUri, int reqWidth, int reqHeight) throws FileNotFoundException {
Bitmap bitmap = null;
try {
// Get input stream of the image
final BitmapFactory.Options options = new BitmapFactory.Options();
InputStream iStream = context.getContentResolver().openInputStream(imageUri);
// First decode with inJustDecodeBounds=true to check dimensions
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(iStream, null, options);
if (iStream != null) {
iStream.close();
}
iStream = context.getContentResolver().openInputStream(imageUri);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(iStream, null, options);
if (iStream != null) {
iStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}

Try using BitmapFactory to fix the problem http://developer.android.com/reference/android/graphics/BitmapFactory.html

The MediaStore.getBitmap method is a convenience method that does not specify a sample size when obtaining the bitmap. If you are using getBitmap(ContentResolver, Uri), and want to use a sample size, just use the ContentResolver to get the input stream, and decode the bitmap as you would normally (calculating sample size first, and then loading it with the appropriate sample size).

For those who are looking for code sample:
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromUri(Context context, Uri imageUri, int reqWidth, int reqHeight) throws FileNotFoundException {
// Get input stream of the image
final BitmapFactory.Options options = new BitmapFactory.Options();
InputStream iStream = context.getContentResolver().openInputStream(imageUri);
// First decode with inJustDecodeBounds=true to check dimensions
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(iStream, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(iStream, null, options);
}

Related

Android studio decodeStream returns image in landscape orientation

In an android studio project, I get an image from the gallery using the BitmapFactory.decodeStream method. But the received bitmap is always in landscape orientation, so pictures with a height greater than the width are rotated by 90 degrees. How to solve the problem? Here is the getter code
public static Bitmap decodeSampledBitmapFromResource(Context context, Uri resourceUri, int reqWidth, int reqHeight) throws IOException {
InputStream imageStream = context.getContentResolver().openInputStream(resourceUri);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(imageStream, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
imageStream.close();
imageStream = context.getContentResolver().openInputStream(resourceUri);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
//the bitmap is always in landscape orientation
return BitmapFactory.decodeStream(imageStream, null, options);
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of the image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize += 1;
}
}
return inSampleSize;
}

Bitmap null when attempting to load scaled down version

I'm attempting to scale down a bitmap to load a smaller version into memory. I'm pretty much following Google's example (search Loading Large Bitmaps Efficiently), except that I'm loading from the image gallery instead of a resource. But I seem to be getting back a null bitmap after calculating dimensions. Here's my code:
/** OnActivityResult Method **/
final Uri imageUri = data.getData();
final InputStream imageStream = getActivity().getContentResolver().openInputStream(imageUri);
Bitmap bitmapToLoad = Util.decodeSampledBitmapFromResource(imageStream, 500, 500); // bitmapToLoad is null.
mIvScreenshot.setImageBitmap(bitmapToLoad);
/**Helper Methods **/
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(InputStream is,
int reqWidth, int reqHeight) {
Rect rect = new Rect();
// First decode with inJustDecodeBounds = true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, rect, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is, rect, options);
}
Can anyone catch what I'm doing wrong?
I managed to get it working. Thanks to Biraj Zalavadia (How to reduce an Image file size before uploading to a server) for the scaling logic, and the cursor code here (How to return workable filepath?). Here is my onActivityResult():
try {
final Uri imageUri = data.getData();
String[] filePath = { MediaStore.Images.Media.DATA };
Cursor cursor = getActivity().getContentResolver().query(imageUri, filePath, null, null, null);
cursor.moveToFirst();
String imagePath = cursor.getString(cursor.getColumnIndex(filePath[0]));
Uri newUri = Uri.parse(ScalingUtilities.scaleFileAndSaveToTmp(imagePath, 500, 500));
final Bitmap selectedImage = BitmapFactory.decodeFile(newUri.getEncodedPath());
mIvScreenshot.setImageBitmap(selectedImage);
} catch (Exception e) {
// Handle
}

how to sample the bitmap for memory management in android?

i have made a demo for image editing,I am facing issue when i pass the image to another activity(Grow heap size),and my app crashed,Please tell me how cani sample and resize my bitmap directly (not from resources) to solve memory issue ,My code is as below:
code
if (Global.photo_editor_bitmap != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Global.photo_editor_bitmap.compress(Bitmap.CompressFormat.PNG,
100, stream);
byte[] byteArray = stream.toByteArray();
i = new Intent(PhotoEditor.this, Enhance.class);
i.putExtra("bitmap_image", byteArray);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
} else {
Toast.makeText(getApplicationContext(), "No Image", 1).show();
}
static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
int inSampleSize = 1; // Default subsampling size
// See if image raw height and width is bigger than that of required
// view
if (options.outHeight > reqHeight || options.outWidth > reqWidth) {
// bigger
final int halfHeight = options.outHeight / 2;
final int halfWidth = options.outWidth / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
I got solution of decodebitmapFromresources,But my bitmap is available,SO how to use this direclty.
I have the same problem the app gets crashed and showing message in log for heap size, allocation size and bitmap size, what i have done is checked the device width & height and on the basis of that scaled the bitmap or calculate sample size.
int screenHeight = getResources().getDisplayMetrics().heightPixels;
int screenWidth = getResources().getDisplayMetrics().widthPixels;
get the width and height and then put it in reqWidth and reqHeight

OutOfMemoryError when adding imageView programmatically

I want to add a few ImageView in a linearLayout programmatically.
but application crashed for more than 2 images. its error is OutOfMemoryError.
String[] titleImages={"a","b","c","d","e","f","g"};
for (String title : titleImages){
InputStream inputStream = context.getAssets()
.open("titles"+"/"+title);
Drawable drawable = Drawable.createFromStream(inputStream, null);
inputStream.close();
ImageView imageView = new ImageView(_context);
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setImageDrawable(drawable);
//more imageView set properties
LinearLayout shelf=findViewById(R.id.shelf);
//shelf is a LinearLayout
shelf.addView(imageView);
}
Use smaller images.
Or, use BitmapFactory.Options, an in particular its inSampleSize option, to downsample the images to something that is more appropriate for your screen size.
Or, use a third-party image-loading library, like Picasso, that can handle inSampleSize for you.
by using these methods you can resize the image as per your use.
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}

About how to get the Bitmap from a image or an video image?

Im a new in android im studying the image bitmap,
please add some info if something im missing..
My Learnings!
1. In decoding a bitmap from a file which is already an image,
String pathName = Environment.getExternalStorageDirectory()
+ "/download/" + "ZG4T5vzQSPQ.png";
imgView.setImageBitmap(decodeSampledBitmap(pathName, 100, 120));
public static Bitmap decodeSampledBitmap(String pathName, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
android.util.Log.d("calculateInSampleSize()", "H:" + options.outHeight
+ " W:" + options.outWidth);
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2; // 1 = 1 * 2
}
}
android.util.Log.d("calculateInSampleSize()", "inSampleSize:"
+ inSampleSize);
return inSampleSize;
}
If you want to decode an image to bitmap a single path is needed but
if you want to decode a video and get its videoThumbnail why single path is not
enough? you need to create a videoThumbnail like this!
Bitmap bmp = ThumbnailUtils.createVideoThumbnail(pathName,
MediaStore.Images.Thumbnails.MINI_KIND);

Categories

Resources