Out of memory while decoding Image using Base64 Decode - android

I'm getting image data from a server and I'm converting it to byte[] using Base64.decode. My code works fine for small image sizes but for a particular image of size 9.2MB, it crashes. I have read about down sampling in various posts but before I could get to the sampling section of code, I'm getting a out of memory exception while reading the bytes in the following line of code.
byte[] data = Base64.decode(attchData[i].getBytes(),0);
Please help me out.

You can simply use this and get better solution:
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap; }

Use this methood, May work for you
decodeSampledBitmapFromPath(src, reqWidth, reqHeight);
use this implementation
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}

Wrap the input stream you are reading from (when reading data from the server) in a Base64InputStream instead. This should reduce the amount of memory required during the base64 decoding phase.
But you should check if you really have to send images of that size to the client. Maybe the images can be scaled on the server side?

Related

Bitmap color code change after scaledown

I have one image which have color code of #AAA28B (170R,162G,139B). Now let's say current image size is 1200x1200 now I want to make it scale down at 600x600 so i use below code and get resulted in bitmap but the problem is its bitmap color code change to #ABA38C, So it RGB values increase to plus one compare to original image color and become (171R,163G,140B) how to prevent this?.
See attach a screenshot where the first image if original loaded directly from android drawable and other it loads by using following code.
private void loadImage(int width, int height){
Bitmap bitMapTest=BitmapFactory.decodeResource(getResources(),R.drawable.ic_test);
Log.i("IMAGE","Image format is"+ bitMapTest.getConfig().name()+
"Image size is"+ bitMapTest.hasAlpha() + "bitmap size is"+ bitMapTest.getHeight());
Bitmap decodeBitmap=decodeSampledBitmapFromResource(getResources(),R.drawable.ic_test,width,height);
Log.i("IMAGE","Image format is"+ decodeBitmap.getConfig().name()+
"Image size is"+ decodeBitmap.hasAlpha() + "bitmap size is"+ decodeBitmap.getHeight());
//adjust of alha deos not give me any help result remain same
//decodeBitmap=adjustOpacity(decodeBitmap);
mImgView.setImageBitmap(decodeBitmap);
}
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;
options.inPreferredConfig= Bitmap.Config.ARGB_8888;
options.inScaled=false;
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 = 2;
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;
}
Here is orginal image :-
It seems like applying following code for scaledown working fine for the solid image like this.
Bitmap decodeBitmap=Bitmap.createScaledBitmap(sourceBitmap,width,height,false/*Make sure filter is false*/);

How can I resolve OutofMemoryError error? (After Bitmap.createScaledBitmap)

I know, there are a lot of similar questions in Stackoverflow. But I could not solve my problem.
I have some kind of jigsaw puzzle. The pictures in the Drawable-nodpi folder are 2500x1250.
I am trying to resize the images with the following code suggested:
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;
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
I call it like this:
(I call these codes several times.)
private Bitmap resizeImg (int rsm) {
Bitmap bmp = decodeSampledBitmapFromResource(getResources(),rsm,wdth,hght);
return bmp;
}
I need to use Matrix as the scaling of Imageview. But it's not the size I want. It works right without the Matrix.
I'm solving the Matrix problem like this:
Bitmap.createScaledBitmap
private Bitmap resizeImg (int rsm) {
Bitmap bmp = decodeSampledBitmapFromResource(getResources(),rsm,wdth,hght);
// return bmp;
Bitmap resized = Bitmap.createScaledBitmap(bmp, wdth,hght,true); //I get OutOfMemoryError this line.
return resized;
}
This insertion really solves my problem. But every day I get lots of OutOfMemoryError errors.
What do I need to do to fix this error? Please help me. Thank you.
1] Add largeHeap as true in android manifest to your application tag:
android:largeHeap="true"
2] Recycle your all used bitmaps,
Example:
bmp.recycle();
resized.recycle();

decoding bitmap efficiently, avoiding OOM exceptions

I've written a multimedia app. In this I have made a gallery with a viewpager, and a FragmentStatePagerAdapter. I used FragmentStatePagerAdapter so that each time I'have in memory only two images and each time the user scrolls the pager the old picture is destroyed and the new is decoded in bitmap.
I have read lots of tutorials of how to efficiently load a bitmap using in a smart way the inSampleSize option and I've implemented it in such a way. In my phone runs great, but in some phones I get an out of memory exception so this is how I decode my ImageView in each fragment
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
try {
ImageArray=org.apache.commons.io.FileUtils.readFileToByteArray(new File(_imagePaths.get(mImageNum)));
if(MyApplication.getDeviceWidth() !=0 || MyApplication.getDeviceHeight()!=0)
bitmap=decodeSampledBitmapFromResource(ImageArray,MyApplication.getDeviceWidth(), MyApplication.getDeviceHeight());
else{
DisplayMetrics metrics = MyApplication.getAppContext().getResources().getDisplayMetrics();
bitmap=decodeSampledBitmapFromResource(ImageArray,metrics.widthPixels, metrics.heightPixels);
}
mImageView.setImageBitmap(bitmap);
} catch (IOException e) {
Log.e("ImageDetailFragment",e.getLocalizedMessage());
}
}
public static Bitmap decodeSampledBitmapFromResource(byte[] array,int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap b =BitmapFactory.decodeByteArray(array, 0, array.length,options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
if(b!=null)
b.recycle();
Log.i("inSampleSize", String.valueOf(options.inSampleSize));
return BitmapFactory.decodeByteArray(array, 0, array.length,options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth,int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
Log.i("inSample size", String.valueOf(inSampleSize));
if(sampleLimit==-1)
return 2;
return inSampleSize;
}
So as you can see (I think) I load each bitmap efficiently and if a screen is smaller inSampleSize goes to 2
My question is how can I compute inSampleSize not depending on screen size only but also on the memory that is available to my app, cause in my phone I get 64MB but i've come across tablets with 38MB or less

Scaling Icon to fit in Imageview Android

I have a list in my application that contains all the installed applications with their icons, I'm able to render the installed applications and the icons as well but it is consuming lot of memory as it loads the drawables(icons) of the installed applications into memory as well.
I want to scale down the icon and then load into memory just to reduce the memory usage of the application. Can anyone tell me how that can be achieved.
Note : if PNG format then it will not compress your image because PNG is a lossless format.
and applications icons are in PNG format
Any way to reduce the memory allocation for the icons??
Yeah it's all in the docs:
http://developer.android.com/training/displaying-bitmaps/index.html
Calculate your sample size, i.e. size of the bitmap you want:
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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
The decode your bitmap at this size:
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);
}
This should all be done off the UI thread:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
You can then cache the bitmaps so you don't have to do it more times than necessary:
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Use inSampleSize from BitmapFactory.Options
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; //Downsample 10x

How can i decrease the width and height for a image in android pragmatically?

My requirement is what ever the size(width,height not file size) image stored in the database i need to retrieving that as simple passport size of image.
My code is :
byte[] imgByte=null;
in the oncreate method
imageview=new ImageView(this);
imageview.setLayoutParams(llp2);
imgByte=cursor.getBlob(cursor.getColumnIndex("imagestore"));
imageview.setScaleType(ScaleType.CENTER);
imageview.setImageBitmap(BitmapFactory.decodeByteArray(imgByte, 0, imgByte.length));
layout.addView(imageview)
when i displaying that displayed only what ever the size before enter. so i need to fit that image size in the android.
I tried these links
Reduce size of Bitmap to some specified pixel in Android
but the problem here is i got image in byte. But all codes image data type int only. can i get the correct solution to decrease the image size pragmatically?
You can use following code to create sample sized image. This will return Bitmap.
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
Use this code,
decodeSampledBitmapFromResource(getResources(),R.drawable.xyz, 100, 100);
Here, 100 * 100 sample size you are providing. So Thumbnail of such size will be created.
Edit
To use bytes[] in code, use following short of code.
public static Bitmap decodeSampledBitmap(byte[] data, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}

Categories

Resources