Leak of memory with a rescale of bitmap - android

I wanted to scale image in order that they kept the same ratio. Thus for example, an arrow has the same size in all images after the rescaling. So I followed this example and it works fine.
But after lost of manipulations of the listview, I can have an OutOfMemoryError error. I ckeck the heap dump in DDMS and that's right, the allocation size always goes up. I put some bitmap.recycle() but it leads to an error: "cannot draw recycled bitmaps".
I also tried the official tutorial, but I had problems, the downloaded sample is not the same as those explained, and I don't understand everything.
Please, can you explain me how to solve my mistake?
Thanks

Bitmaps always stored in the device Heap Memory , and your device heap memory can't afford that number of Bitmaps as may be the way you try works on the same resolution of the image, So, at first try to grow the heap using your app manifest, then try this way to resize your Bitmaps:
public static Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth, float newHeight) {
if(bitmapToScale == null)
return null;
//get the original width and height
int width = bitmapToScale.getWidth();
int height = bitmapToScale.getHeight();
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(newWidth / width, newHeight / height);
// recreate the new Bitmap and set it back
return Bitmap.createBitmap(bitmapToScale, 0, 0, bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix, true);
}
if this don't work either, so, you have to make one of the following:
assign to each image a much less width and height.
compress the image using something like ImageLoader.
use another device with much Heap Space.
limit the number of images used.
HINT: recycling the Bitmap totally removes it from the Heap memory, So, it's logical to have a "cannot draw recycled bitmaps" error, So, if you want to recycle it and then use it in your app, you have to store it at first in something like ArrayList<Bitmaps>.

Related

Create bitmap out of memory in android

I have the following code to create a canvas with a size of 8303 × 5540, but running that code produces a OutOfMemoryException.
scaledBitmap = Bitmap.createBitmap(8303, 5540, Bitmap.Config.ARGB_8888);
How can I resolve this problem?
Setting android:largeHeap="true" in AndroidManifest.xml helped me.
Well.. Creating a bitmap of that size, you would have to allocate about 183MB of memory. That will be a problem on most phones. You could try to set android:largeHeap="true" in your manifest, but still that will not give you enough memory on most phones.
If you are willing to accept a "subsampled" version of your image, and the image data is coming from file, you could take a look at http://developer.android.com/training/displaying-bitmaps/load-bitmap.html for loading subsamples of large images into memory. Basically, you can tell the BitmapFactory to load one out of every X pixels, thereby avoiding the requirement to have all 183MB of image data in memory.
http://codingaffairs.blogspot.com/2016/07/processing-bitmap-and-memory-management.html
Now here are tips which you can follow and can avoid out of memory exception in your Android Application.
Always use inSampleSize
Now what is inSampleSize ?
with the help of inSampleSize you are actually telling the decoder not to grab every pixel in memory, instead sub sample image.
This will cause less number of pixels to be loaded in memory than the original image. you can tell decoder to grab every 4th pixel or every second pixel from original image.
if inSampleSize is 4. decoder will return an Image that is 1/16 the number of pixels in original image.
so how much memory you have saved ? calculate :)
Read Bitmap Dimensions before loading into memory.
How reading bitmap dimensions before loading image into memory can help you avoid out of
memory error ? Let's Learn
use inJustBounds = true
here is technique with the help of which you can get image dimension beore loading it in memory
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Above code snippet will not give us any image/bitmap. it will return null for bitmap Object.
but it will definitely return width and height of that image. which is R.id.myimage.
Now you have width and height of Image. you can scale up or scale down image based on these factors:
ImageView size which will be used to display Image.
Available amount of memory. you can check available amount of memory using ActivityManager and getMemoryClass.
Screen size and density of device.
Use appropriate Bitmap Configuration
Bitmap configurations is color space/color depth of an Image. Default bitmap Configuration in Android is RGB_8888 which is 4 bytes per pixel.
If you use RGB_565 color channel which use 2 Bytes per pixel. half the memory allocation for same resolution :)
Use inBitmap property for recycling purpose.
Do not make static Drawable Object as it cannot be garbage collected.
Request large heap in in manifest file.
Use multiple processes if you are doing lot of image processing(memory intensive task) or use NDK (Native Development using c, c++)

How to properly set a wallpaper on Android

It seems that setting a wallpaper on Android just doesn't work in any useful way.
If you get an image from your phone and set it as the wallpaper, it's way too big for the screen
If you resize it (either using a createBitmap() function that allows you to specify size, or the ridiculously useless createScaledBitmap()) it goes all jaggy and out of focus
If you use some freaky hacks to fix the quality of the image, it's better, but still not perfectly clear by any stretch.
If you attempt to get the current wallpaper and set that, it still seems to make it too big. It appears to give you the original image file, forcing you to resize it, which doesn't work.
Now, the phone's internal software is perfectly capable of resizing an image to be smaller with no reduction of quality. Why does it not share this functionality?
WallpaperManager wallpaperManager = WallpaperManager.getInstance(Spinnerz.this);
// gets the image from file, inexplicably upside down.
Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "DCIM/Camera/Zedz.jpg");
// use some rotation to get it on an angle that matches the screen.
Matrix bitmapTransforms = new Matrix();
bitmapTransforms.setRotate(90); // flip back upright
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),bitmapTransforms, false); // create bitmap from bitmap from file, using the rotate matrix
// lets set it exactly to the resolution of my Samsung Galaxy S2: 480x800 pixels.
// This function appears to exist specifically to scale a bitmap object - should do a good job of it!
bitmap = Bitmap.createScaledBitmap(bitmap, 480, 800, false);
wallpaperManager.setBitmap(bitmap);
// result is quite a jaggy image - not suitable as a wallpaper.
PIC:
Try this ,
Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = d.getWidth();
int height = d.getHeight();

Android - How to enlarge a bitmap

I usually download images that are larger in size and shrink them using an imageview but lately Im trying to deal with my apps not working on a lesser network connection so I was wondering how can I increase the size of an image once it gets to the device. I tried resizing the image once it was in an imageview but the imageview will get no larger than the original image. Im sure theres a really easy way to increase or blow up an image on the device but I havent come across it yet.
So.....how can I increase the size of an image. Id like to blow it up and use it in an imageview but the images Im dealing with are only 128X256 and Id like to expand them to about 512X1024.
Try using this method:
public static Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth, float newHeight) {
if(bitmapToScale == null)
return null;
//get the original width and height
int width = bitmapToScale.getWidth();
int height = bitmapToScale.getHeight();
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(newWidth / width, newHeight / height);
// recreate the new Bitmap and set it back
return Bitmap.createBitmap(bitmapToScale, 0, 0, bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix, true); }
refer to my answer in: ImageView OutofMemoryException
Use matrix to resize the bitmap.
Check this
Resize Bitmap
If you want to scale the Bitmap manually, there is a Bitmap.createScaledBitmap() method that you can use for this.
If you want the ImageView to handle this, you have to set the layout_width/layout_height to something other than wrap_content or it will always shrink to the size of the Bitmap. Then you need to change the scaleType attribute to a type that actually scales the bitmap.
The functionality to scale image up or down is readily available via android.graphics library:
Bitmap bitmapScaled = Bitmap.createScaledBitmap(Bitmap bitmapOrig, int widthNew, int heightNew, boolean filter);

Dealing with Large Bitmaps (tiling a small bitmap to create wallpaper)

I'm having memory problems and think it might have to do with creating large bitmaps.
The task at hand is to get a fairly small tile image and create a larger tiled image and set this as the phone wallpaper. The way I'm doing this is:
1) Create a view that is 2 * screen width, 1 * screen height
2) Set the view background to a BitmapDrawable with the tile mode set to repeat
3) Create a bitmap with the views dimensions
4) draw the view to the bitmap by: view.draw(new Canvas(bitmap))
5) set wallpper: getApplicationContext().setWallpaper(bitmap)
This works fine on my phone (HTC Magic) and other phones that I have tried. But I am getting bug reports relating to this issue. I tried to recreate the problem by doubling the required dimensions and the problem seems to be happening in the 4th step when the view is being drawn to the bitmap:
ERROR/dalvikvm-heap(124): Heap Massage needed (7372800-byte external allocation too big)
I'm not sure how to go about solving this. Please help!
Thanks
I'm sure you thought of it, but nevertheless: Have you included
<uses-permission android:name="android.permission.SET_WALLPAPER" />
in your manifest-file?
You're sure there is no exception thrown? It could possibly be a problem with showing the Toast.
Not exactly sure if this is your solution, but have you looked at ? BitmapFactory.Options.inTempStorage
The way you use it is:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
Bitmap bitmap_origin = BitmapFactory.decodeFile(path, options);
Unfortunately, I don't think you can do much... We are on a mobile phone here ; Android limis the process memory to 16MB.
Here are a couple of tips and tricks I can give you (because I have the sames issues in my application)
Are you sure you need 32 bits pixels? that's three 8bit color channels plus a 8bit alpha channel. You can use RGB_565 for a visually acceptable result.
Recycle the image that you don't need when you create your bitmap (and that you won't need to draw your bitmap)
null any other object that you don't need
Run System.gc() to force a garbage collection just before you create the Bitmap
Hope this helps!
Actually you could refactor your code. You'll have better performance and probably use less memory if you don't use a View
Create a Bitmap of the desired size bitmap = Bitmap.createBitmap(width,height,Bitamp.Config.RGV_565) (or ARGB_8888, that might work too)
Create a canvas = new Canvas(bitmap)
Create the tiled image yourself, from your src
simplified Code:
// set another matrix if you want rotation/scaling of the input
Matrix identity=new Matrix();
for (int i=0; i<maxLines; i++) {
for (int j=0; j<maxCol; j++) {
canvas.draw(src, identity,anyPaint);
}
}
Keep the end set wallpaper getApplicationContext().setWallpaper(bitmap)

Memory efficient image resize in Android

I am trying to reduce the size of images retrieved form the camera (so ~5-8 mega pixels) down to one a a few smaller sizes (the largest being 1024x768). I Tried the following code but I consistently get an OutOfMemoryError.
Bitmap image = BitmapFactory.decodeStream(this.image, null, opt);
int imgWidth = image.getWidth();
int imgHeight = image.getHeight();
// Constrain to given size but keep aspect ratio
float scaleFactor = Math.min(((float) width) / imgWidth, ((float) height) / imgHeight);
Matrix scale = new Matrix();
scale.postScale(scaleFactor, scaleFactor);
final Bitmap scaledImage = Bitmap.createBitmap(image, 0, 0, imgWidth, imgHeight, scale, false);
image.recycle();
It looks like the OOM happens during the createBitmap. Is there a more memory efficient way to do this? Perhaps something that doesn't require me to load the entire original into memory?
When you decode the bitmap with the BitmapFactory, pass in a BitmapFactory.Options object and specify inSampleSize. This is the best way to save memory when decoding an image.
Here's a sample code Strange out of memory issue while loading an image to a Bitmap object
Are you taking the picture with the camera within your application? If so, you should set the picture size to a smaller one in the first place when they're being captured via android.hardware.Camera.Parameters.setPictureSize
Here is a similar question that I answered and show how to go about dynamically loading the proper image size.
out of memory exception + analyzing hprof file dump

Categories

Resources