What does BitmapFactory.Options in android.graphics.BitmapFactory.Options do?
There is no theoretical explanation in the android sdk reference manual about this class, it only contains the explanation about the methods of the class.
Bitmapfactory is mainly used for Scaling
Bitmap lBmp = BitmapFactory.decodeResource(getResources(), R.Drawable.ic_dolphin);
It gets the "dolpin" image and it will reduce the image size, if we dnt use bitmapfactory then it leads to insufficient memory allocations
It's used to pass options to the BitmapFactory - as you might expect :)
For example, you can use it to explicitly scale the Bitmap up or down from the source.
See this example
This method is used to create bitmap of given specific size which is stored in sdcard.
public Bitmap decodeFile(String path,int size) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// The new size we want to scale to
final int REQUIRED_SIZE = size;
// 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.decodeFile(path, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
Related
This code is used to compress and resize image in my app Image is showing blurry and size is reducing to much. Can yo Explain how this code works and how can i improve quality of my image with this existing code.
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
final int REQUIRED_SIZE = 200;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE
&& o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bit1 = BitmapFactory.decodeStream(new FileInputStream(f),
null, o2);
Your code is just initializing the bitmap options to work with a decodedStream ( the input image or file you will work with) after that is setting a rule thats say the required size should be >= 200 width and height and after that is just creating a final bitmap with the required output of the stream
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
final int REQUIRED_SIZE = 200;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE
&& o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bit1 = BitmapFactory.decodeStream(new FileInputStream(f),
null, o2);
bit1.compress(Bitmap.CompressFormat.PNG, 100, out); //you can use this line and play with the value 100 in order to set quality of the image when its compresed
Since your image is scaled to a certain size ( which is >= 200 width and height) your image output dimension will depend on the input bitmap at first
if you want to check out the Dimensions of the bitmap you can do this
Log.e("Dimensions", bit1.getWidth()+" "+bit1.getHeight());
Bitmap.compress
compress(Bitmap.CompressFormat format, int quality, OutputStream
stream) Write a compressed version of the bitmap to the specified
outputstream.
EDIT: As Vladyslav Matviienko suggests you could increase your REQUIRED_SIZE to a bigger value, since like i wrote above, you are setting a fixed size at first
I am developing a application where , there is a profile page where user can set its image via camera or from gallery.
Now when user sets large image then my app stops unfortunate , i found a reason for that is , we can't set image on image View exceeds some size.
So i decided to reduce image size before setting it on image view.
Here i found many solutions but in all that it also reduces its width and height, but i don't want to reduce its width and height.
I only want to reduce its size in percentage. E.x from 1 mb to 100 kb.
How can I achieve this in Android?
Try this way,hope this will help you to solve your problem.
public Bitmap decodeFile(String path) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 70;
// 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.decodeFile(path, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
During runtime, I am trying to put an image in the surface view. When I tried using the image from the Drawable folder I got Out of memory error. After a quick search in the stackoverflow, I found that there will be some relief if we access the image from the asset folder. But still I get the Out of memory error during runtime.
I have analyzed and found that scaling will help in resolving this kind of memory related issues. The thing is that I have the image size of 1280 x 720 and the device size also the same. Hence I feel like the scaling will not have any effect.
As we have experts in this community, I would appreciate if you can help me with some suggestions/examples to resolve this kind of issue.
Scenario 1:
Using the Bitmap from Drawable folder.
backgoundImage = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.backgroundhomepage), (int) dWidth, (int) dHeight, true);
/***********************************************************************************************************************************************************
1. To get the image from asset library
**************************************************************************************************************************************************************/
public Bitmap getAssetImage(Context context, String filename) throws IOException {
AssetManager assets = context.getResources().getAssets();
InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
Bitmap bitmap = BitmapFactory.decodeStream(buffer);
return bitmap;
}
Scenario 2:
Using the Bitmap from Assets folder
backgoundImage = Bitmap.createScaledBitmap(getAssetImage(context,"backgroundhomepage"), (int) dWidth, (int) dHeight, true);
OutofMemory occurs when your app exceeds memory allocated in heap. The bitmap is too large to fit in memory ie heap. In such a case you run out of memory. You need to scale down the bitmap and then use the same. For that check the link below
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html.
There is also a blog # http://android-developers.blogspot.in/2009/01/avoiding-memory-leaks.html (avoiding memory leaks)
public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_WIDTH=WIDTH;
final int REQUIRED_HIGHT=HIGHT;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Quoting from the docs
The BitmapFactory class provides several decoding methods (decodeByteArray(), decodeFile(), decodeResource(), etc.) for creating a Bitmap from various sources. Choose the most appropriate decode method based on your image data source. These methods attempt to allocate memory for the constructed bitmap and therefore can easily result in an OutOfMemory exception. Each type of decode method has additional signatures that let you specify decoding options via the BitmapFactory.Options class.
Setting the inJustDecodeBounds property to true while decoding avoids memory allocation, returning null for the bitmap object but setting outWidth, outHeight and outMimeType. This technique allows you to read the dimensions and type of the image data prior to construction (and memory allocation) of the bitmap.
Also check this link for memory management.
https://www.youtube.com/watch?v=_CruQY55HOk
Got a quick Solution
<application
android:largeHeap="true" >
put into appplication tag in manifest file.
You can use the following code to load the bitmap from file:
private Bitmap decodeFile(File f,int req_Height,int req_Width){
try {
//decode image size
BitmapFactory.Options o1 = new BitmapFactory.Options();
o1.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o1);
//Find the correct scale value. It should be the power of 2.
int width_tmp = o1.outWidth;
int height_tmp = o1.outHeight;
int scale = 1;
if(width_tmp > req_Width || height_tmp > req_Height)
{
int heightRatio = Math.round((float) height_tmp / (float) req_Height);
int widthRatio = Math.round((float) width_tmp / (float) req_Width);
scale = heightRatio < widthRatio ? heightRatio : widthRatio;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inScaled = false;
return BitmapFactory.decodeFile(f.getAbsolutePath(),o2);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
It should resolve your out of memory exception.
Link here has a good detailed explanation of your answer.
Ok Someone help me figure this out. I am using the Bitmap.options as recommended by other threads and android tutorials to figure out the inSample size. The problem that the following code is resulting in null bitmap instead of scaled bitmap
private int determineCorrectScale(InputStream imageStream){
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(imageStream, null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 100;
// 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;
}
return scale;
}
private String saveScaledBitmapToPhone(Uri imagUri){
InputStream imageStream;
try {
imageStream = getContentResolver().openInputStream(imagUri);
int scale= determineCorrectScale(imageStream);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = scale;
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream, null, options );
.
.
.
.
} catch (Exception e) {
return imagUri.toString(); //default
}
}
The problem that yourSelectedImage is null. However if I comment out the line
int scale= determineCorrectScale(imageStream);
and set the insampleSize to 8 or 16 or any other fixed manual number then everything works fine. Can any one explain this behaviour or how to fix it? My feeling says it is due to creating two Options objects of static class but that's just a guess. I still can't fix it :(
PLEASE HELP
You're reusing the same data stream. Either reset it, cache the data in a byte array, or open a new stream.
First off, I have read many posts and articles about out of memory exceptions but none of them have helped with my situation. What I'm trying to do is load an image from the sd card but scale it to an exact pixel size.
I first get the width and height of the image and calculate the sample size:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(backgroundPath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, getWidth(), getHeight());
Here's how I get the sample size (although its not really relevant):
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;
// NOTE: we could use Math.floor here for potential better image quality
// however, this also results in more out of memory issues
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;
}
Now that I have a sample size I load the image from disk to an approximate size (sample size):
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
options.inPurgeable = true;
Bitmap bmp = BitmapFactory.decodeFile(backgroundPath, options);
Now, I scale this bitmap that I have created to the exact size I need and clean up:
// scale the bitmap to the exact size we need
Bitmap editedBmp = Bitmap.createScaledBitmap(bmp, (int) (width * scaleFactor), (int) (height * scaleFactor), true);
// clean up first bitmap
bmp.recycle();
bmp = null;
System.gc(); // I know you shouldnt do this, but I'm desperate
The above step is usually get my out of memory exception. Does anyone know a way to load an exact size bitmap from disk to avoid having to create two separate bitmaps like above?
Also, it seems like more exceptions occur when the user runs this code for a second time (sets a new image). However, I make sure to unload the drawable that was created from the bitmap which allows it to be garbage collected before this code is run again.
Any suggestions?
Thanks,
Nick
In your case there's no need to create the intermediate bitmap after you've performed the first decode. Since you're drawing to to a Canvas, you can use either the following methods (whichever you find most convenient) to scale the image to the perfect size.
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
Maybe this method would be helpful, I think I pulled it off of stackoverflow myself. It solved my out of memory exception issue.
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=250;
//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.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}