HOW TO Resizing a bimap without createBitmap to avoid oom issue - android

after researching, i only find InSampleSize to resize a bitmap
but i am looking for something that'll allow me to resize the bitmap to large or smaller depends on the screen resolution
since bitmap.createBitmap will result OOM, i have to use something else...
please help
here is the code where i resize my bitmap which result 5mb~10mb bump each time i resize anybitmap
Bitmap createdBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
thanks

you can use this to get the screen that is currently running on:
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
screenW = w;
screenH = h;
}
and then use this to load the bitmap so you are loading it into memory reasonably:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(selectedImagePath, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
if(imageWidth > imageHeight){
options.inSampleSize = calculateInSampleSize(options,screenH,screenW);
}else{
options.inSampleSize = calculateInSampleSize(options,screenW,screenH);
}
options.inJustDecodeBounds = false;
photo = BitmapFactory.decodeFile(selectedImagePath,options);
method:
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) {
// 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;
}

Related

Bad image quality issue after scale down bitmap

I'm scaling down some bitmaps and getting low quality results.The result image looks different than original image.. I have used following code to scale down image,
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap ib=BitmapFactory.decodeResource(getResources(), R.drawable.card,options);
Bitmap mm=Bitmap.createScaledBitmap(ib,ib.getWidth()/5,ib.getHeight()/5, true);
AND
BitmapFactory.Options m_bmpFactoryOptions = new BitmapFactory.Options();
m_bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap m_bitmap = BitmapFactory.decodeFile(p_file, m_bmpFactoryOptions);
int m_heightRatio =
(int) Math.ceil(m_bmpFactoryOptions.outHeight / (float) p_height);
int m_widthRatio =
(int) Math.ceil(m_bmpFactoryOptions.outWidth / (float) p_width);
if (m_heightRatio > 1 || m_widthRatio > 1)
{
if (m_heightRatio > m_widthRatio)
{
m_bmpFactoryOptions.inSampleSize = m_heightRatio;
}
else
{
m_bmpFactoryOptions.inSampleSize = m_widthRatio;
}
}
m_bmpFactoryOptions.inJustDecodeBounds = false;
m_bitmap = BitmapFactory.decodeFile(p_file, m_bmpFactoryOptions);
*Please help If there are any filters like lanczos,catrom to improve image quality after scale down *
Use this method
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;
}
Replace options.inScaled = false; with
options.inSampleSize =2

High resolution image not display in ImageView Android

I am displaying an image in full screen mode,but whenever going to display large image then nothing display in the image view. Below code try to resize bitmap but got same result blank imageview.
public static 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;
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;
}
You solve your problem from two mehtods
Method 1
call this method(function)
public Bitmap decodeImage(int resourceId) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), resourceId, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 100; // you are free to modify size as your requirement
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeResource(getResources(), resourceId, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
add this before your adapter
picture.setImageBitmap((decodeImage(item.drawableId));
instead of
picture.setImageResource(item.drawableId);
Mehtod 2
You need to adjust your image size. The better way is to decode the image to a bitmap, and set the bitmap to the ImageView. For example:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), item.drawableId, opts);
picture.setImageBitmap (bitmap);
I had the same problem. Got is solved through the following code.
Provide the filepath, desired width and desired height to the method. For more reference see here
public static Bitmap decodeScaledBitmapFromSdCard(String filePath, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, 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;
}
Probably the image size is too large that the system cannot allocate enough memory to load it.
you can try loading your image after scaling it it with BitmapFactory.Options sampleSize
check this link for more info
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
may be this will work for you
public static Bitmap decodeSampledBitmapFromResource(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) {
// 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;
}
You solve your problem in Fragment
Add method in adapter
public Bitmap decodeImage(int gridViewImageId) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeResource(mContext.getResources(), gridViewImageId, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 100; // you are free to modify size as your requirement
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeResource(mContext.getResources(), gridViewImageId, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
and add this line
imageViewAndroid.setImageBitmap(decodeImage(gridViewImageId[i]));

Out of memory while creating bitmaps on device

im having problems with high resolution images.
Im using nodpi-drawable folder for 1280x720 images, and using this code to scale it.
public static Drawable scaleDrawable(Drawable d, int width, Activity cxt)
{
BitmapDrawable bd = (BitmapDrawable)d;
double oldWidth = bd.getBitmap().getWidth();
double scaleFactor = width / oldWidth;
int newHeight = (int) (d.getIntrinsicHeight() * scaleFactor);
int newWidth = (int) (oldWidth * scaleFactor);
Drawable drawable = new BitmapDrawable(cxt.getResources(),MainScreen.getResizedBitmap(bd.getBitmap(),newHeight,newWidth));
BitmapDrawable bd2 = (BitmapDrawable)drawable;
return drawable;
}
public static 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;
}
I use that code to scale images to screen witdh so if the screen is 320x480 the image will scale to 320 and keep proportions, i dont care if image go out of screen from bottom.
All its working fine, but when trying in a xhdpi device specifically a Samsung Galaxy Note 2 with a screen of exactly 720x1280.
It crash with Out Of Memory Exception in the line:
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
I cant understand why, the image should be scaled from 720 to 720 but my code must be really bad optimized or something.
I havent tried on a 1080x1920 device but it seems it will crash too.
Someone can see something bad when looking at the code?
use this method to resize your bitmap-
Bitmap bm=decodeSampledBitmapFromPath(src, reqWidth, reqHeight);
use this Defination-
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(path, options);
return bmp;
}
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
If you are using resource then replace method with BitmapFactory's decodeResource method..
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
....
.....
return BitmapFactory.decodeResource(res, resId, options);
}
You should use the utility class BitmapFactory for image-processing-operations. Also use BitmapFactory.Options to adjust the input/output sizes of the bitmaps. After a bitmap is not needed anymore, you should free the related memory.

How to scale background image on canvas according to device size in android

All I have used to get the image as the background on canvas
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.help_4, 0, 0, null);
And I get a large image. So can anyone pls. provide me a solution to get the Image set according to the Device size. As I'm new to coding a detailed explanation would be appreciated :)
Thank You
You're almost there. You just need to configure the BitmapFactory.Options variable by setting the output width and height (based on the screen size):
BitmapFactory.Options options = new BitmapFactory.Options();
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
options.outHeight = size.x;
options.outWidth = size.y;
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options));
Determine the device width and height and scale it:
int deviceWidth = getWindowManager().getDefaultDisplay()
.getWidth();
int deviceHeight = getWindowManager().getDefaultDisplay()
.getHeight();
So in complete you can use the following ready-to-use snippet taken from here:
public Bitmap scaleToActualAspectRatio(Bitmap bitmap) {
if (bitmap != null) {
boolean flag = true;
int deviceWidth = getWindowManager().getDefaultDisplay()
.getWidth();
int deviceHeight = getWindowManager().getDefaultDisplay()
.getHeight();
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();
if (bitmapWidth > deviceWidth) {
flag = false;
// scale According to WIDTH
int scaledWidth = deviceWidth;
int scaledHeight = (scaledWidth * bitmapHeight) / bitmapWidth;
try {
if (scaledHeight > deviceHeight)
scaledHeight = deviceHeight;
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
scaledHeight, true);
} catch (Exception e) {
e.printStackTrace();
}
}
if (flag) {
if (bitmapHeight > deviceHeight) {
// scale According to HEIGHT
int scaledHeight = deviceHeight;
int scaledWidth = (scaledHeight * bitmapWidth) / bitmapHeight;
try {
if (scaledWidth > deviceWidth)
scaledWidth = deviceWidth;
bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
scaledHeight, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return bitmap;
}
So finaly use:
myCanvas.drawBitmap(scaleToActualAspectRatio(myBitmap), X, Y, null)
The process would look something like this:
Get screen size
Calculate new image size (keeping aspect ratio)
Decode bitmap to new size.
Get screen size
To get the exact screen size of a device, use DisplayMetrics...
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
The metrics variable will now contain the screen dimensions in pixels. You can get the values by using metrics.widthPixels and metrics.heightPixels.
Calculate new image size (keeping aspect ratio)
To calculate new image size, we can use BitmapFactory.Options and tell it to scale the image down by a factor of x. To calculate that factor (also referred as inSampleSize), use the following method...
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;
}
Decode Bitmap to new size
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, metrics.widthPixels, metrics.heightPixels);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(getResources(), R.drawable.help_4, options);
The inJustDecodeBounds option tells the framework to null out the Bitmap to prevent OOM exceptions, since we are only interested in the dimensions, and not the actual image.
This method will ensure that the Bitmap is scaled efficiently. Read more here: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

unable to get rid of that outofmemory error

I want variable background to GridView and I run my app on a 800*480 resolution device.
I am able to add variable background, but after some time I am getting OutOfMemoryError.
I need to add that bitmap for each shelf and shelf has 800*200 dimensions.
I have tried bitmap.recycle()
and also
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
and also
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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
But still I am unable to get rid of that OutOfMemory error. Please help me.
Its Working Fine For Me.
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.inDither=false; //Disable Dithering mode
options.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
options.inInputShareable=true;
options.inTempStorage=new byte[32 * 1024];
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) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}

Categories

Resources