I am learning how to use Bitmap to scale down images instead of having them crash the app. I am following the developer page for android at http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. I have a couple of questions about the code.
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;
For the code above it creates a new bitmapFactory and decodes the widget. Why use R.id.myimage over R.drawable.image? I am assuming that R.id.myimage refers to a image view while R.drawable.image I added and it directly refers to the image I want rescaled. Finally what does outMimeType refer too?
You know, I'm pretty sure that's a mistake. The resource you want is indeed a drawable, referenced by R.drawable.image.
The options.outMimetype just tells you what the mimetype of the decoded resource is (a PNG, a JPEG, etc.), if that information is available.
Related
I have a question that I seem to find the answer nowhere.
Does this lines of code:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
actually mean that, that file is being downloaded? Android docs say something like this:
decode with inJustDecodeBounds=true to check dimensions
and
Does:
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
BitmapFactory.decodeStream(is, null, options);
means that it will actually download the file smaller (not downloaded as original size and copied after that to a smaller size bitmap).
Clear example: I have some url's that point to many 2000 x 1500 images. By decoding those files and loading them to bitmaps, do I need to have enough memory for downloading the file at its full resolution (2000 x 1500), if I only need thumbnails of (200 x 150)?
I know another answer has already been accepted as the right one but for clarity...
This line options.inJustDecodeBounds = true; means that the call to BitmapFactory.decodeStream(is, null, options); doesn't get the bitmap information but does get bounding information and the MimeType.
You can then use these returned values, outWidth, outHeight and outMimeType to get a 'resampled' version of the bitmap data by setting options.inJustDecodeBounds = false; and setting the sample size to a given ratio determined by your desired output dimensions options. inSampleSize = [int].
See this very informative page for more information: Loading Large Bitmaps Efficiently
Indeed looks like the file is being downloaded, and the effiency part comes where the bitmap being loaded in memory is the smaller one ( the one being decoded with inSampleSize options).
Drawable image = Drawable.createFromPath(newImagepath);
defective_image.setBackgroundDrawable(image);
The image is stored in the newImagePath variable which is a String. The above throws an outOfMemory Exception.
I also tried retrieving the image into a Bitmap object.
Bitmap bitmapImg= BitmapFactory.decodeFile(newImagepath);
In the above case the bitmapImg is Null. (Without any exception)
However if it is retrieved as a file, it's successful. This doesn't serve my purpose because I want this image to be the background of a RelativeLayout.
File imageFile = new File(newImagepath);
String imgPath = imageFile.getAbsolutePath();
The imgPath is the same as the newImagePath, concluding the path is not wrong. I also verified the image's existence in the SDCard.
This image was captured from the device's camera. This code is working on the emulator successfully. When debugged on the device the above said faults were noticed.
I also tried:-
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
It seems to be a memory issue. So I suggest to decode bitmap size with the option
options.inJustDecodeBounds = true;
then getting the size of this bitmap by looking at fields (don't try to use bitmap : it will be null) :
options.outWidth;
options.outHeight;
Then creating a scaled bitmap (depending on the screen dimension). To do this, you can look at
BitmapFactory.Options.inSampleSize
I would rather use a BitmapFactory to decode the Image from the file-path:
Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
jpgView.setImageDrawable(bitmap);
How to solve OOM issue in android . I have tried almost every things like scaling bitmap,inPurgeable in BitmapOption,releasing all resources etc. but still getting OOM issue.
This is basically in images taken by camera or any image i.e. larger then 1.5 mb. I have also images 15-20 mb size in my app.
this is what i´m doing to avoid OOM errors, Using some of the code of the android training. This is in my class "ScaledFactor"
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);
options.inPurgeable = true; // I aded this to the android training code, without this I still have OOM errors. so try using inPurgeable = true
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
In my Activity I use
background = ScaledFactor.decodeSampledBitmapFromResource(getResources(), R.drawable.menu, screenheight, screenwidth); // screeenhieght is the output height , screenwidth is the output width
Then in the on destroy method, or after calling an other intent I use background.recycle();
I´m not using the hdpi, ldpi and so folders... I just use the drawable with large bitmaps, and do the scalling. this way you save some mb on the final apk file
The android training code is here for more info http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap
C ya ! Hope this helps, I spent a hole day trying to figure this out and reading all the questions and answers in this forum. This is just the example of the background image but i have more than 20 images in my game all loaded this way but with smaller output size, and it works very smooth.
Have you tried Bitmap.recycle(); ?
It once solved my Out of Memory issue.
I have.png image file stored as a resource in my android application.
In my code, i am allocationg new Bitmap instance from that image as follow:
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.imgName);
But when I read the image dimensions from the Bitmap object using getWight() and getHeight() methods,
int width = img.getWidth();
int height = img.getHeight();
I am getting different results from the original image... Can some one explain me what am I missing, and how can I retreive the image size?
(My project is complied with android 2.2 - API 8)
Edit:
Ok - found out how to get the real dimensions:
setting inJustDecodeBounds property of the BitmapFactory.Options class to true as follow:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.imgName, options);
width = options.outWidth;
height = options.outHeight;
The problem now is that the decoder returns null when we send Options argument, so I need to decode again like I did before (without Options argument...) to retrieve Bitmap instance -bizarre, isnt it?
To get exact resource image use:
BitmapFactory.Options o = new Options();
o.inScaled = false;
Bitmap watermark = BitmapFactory.decodeResource(context.getResources(), id, o);
This turns off the automatic screen density scaling.
Update:
I'm sure you realized this by now, but inJustDecodeBounds does just that, it finds the dimensions. You will not get an image. That option is generally for doing custom scaling. You end up calling decodeResource twice, the second time setting:
options.inJustDecodeBounds = false;
and making any adjustments to the options based on your:
width = options.outWidth;
height = options.outHeight;
Android scales your image for different densities (in a way for different screen resolutions and sizes). Place a separate copy of your image in drawable-ldpi, drawable-hdpi,drawable-xhdpi , drawable folders.
I need to load lots of big images (500 .png files) from the SD card to my app. Do I always have to convert images to Bitmap and make Bitmap files? I don't want to resize the Heap.
Is there another way to read the images from SD card?
If you're displaying them in a view, then you have to load them into memory in their entirety.
You didn't mention how large your images will get, but what we do in our photo gallery is to keep a list of SoftReferences to these bitmaps, so that the garbage collector can throw them away when they're not visible (i.e. when the view displaying them gets discarded--make sure that this actually happens, e.g. by using AdapterView). Combine this with lazy loading of these bitmaps and you should be good.
The internal representation of the image in your app is a collection of bits and bytes - not an image of any specific format (png, bmp, etc).
The image is converted to this internal representation when the image is loaded by the BitmapFactory.
It is usually not a good idea to load all the bitmaps at once, you will quickly run out of memory...
If your image's dimension is very big, you must to resize them before loading in to ImageView. Otherwise, even one picture can easily cause out of memory problem. I don't know how many images you want to display concurrently and how big they are. But I suggest you to resize them before displaying them.
To resize image and show it, you can use this code:
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(fileInputStream, null, bitmapOptions);
//reduce the image size
int imageWidth = bitmapOptions.outWidth;
int imageHeight = bitmapOptions.outHeight;
int scale = 1;
while (imageWidth/scale >= screenWidth && imageHeight/scale >= screenHeight) {
imageWidth = imageWidth / 2;
imageHeight = imageHeight / 2;
scale = scale * 2;
}
//decode the image with necessary size
fileInputStream = new FileInputStream(cacheFile);
bitmapOptions.inSampleSize = scale;
bitmapOptions.inJustDecodeBounds = false;
imageBitmap = BitmapFactory.decodeStream(fileInputStream, null, bitmapOptions);
ImageView imageView = (ImageView)this.findViewById(R.id.preview);
imageView.setImageBitmap(imageBitmap);
In my android project, I am using this piece of code to resize my HD wallpaper to review it.
Android Save And Load Downloading File Locally