I am trying to cache big bitmaps for drawing on screen in Android. But now I am facing OutOfMemoryException, say that the bitmap allocation exceeds the VM budget.
I need to minimize the size of the bitmap but I cannot reduce the resolution. For my use case, I need to only save the shape of the bitmap and apply color later when actually drawing, so I am using ALPHA_8 as the bitmap configuration.
I want to know if there is a 1-bit pixel (either completely opaque or completely transparent) configuration in bitmap, or any similar ways to save memory?
Reducing the color depth from 8 bits to 1 would, of course, help a little. However, it doesn't really solve the problem but just postpones it. It only means that you'll get the OOME later but you'll still get it.
Consider moving your cache from RAM to disk and, optionally, add a smaller RAM-based cache on top of it to improve performance.
Related
I'm taking whole screenshot of a WebView and display the bitmap on an ImageView. The bitmap can be 7 screen height. (E.g. 1440x14000 px)
I'm frequently face with
OutOfMemoryError.
I've seen this
This says that load a scaled down version into memory but I don't want to lose image quality. There are the same approaches on the web.
Is there any way to handle OutOfMemoryError without loading scaled down version?
The bitmap can be 7 screen height. (E.g. 1440x14000 px)
Note that this means that the user cannot see the whole image at once at full resolution.
I'm frequently face with OutOfMemoryError
On most devices, you will have a very difficult time loading an image that large, as you cannot get a single contiguous memory block that big.
This says that load a scaled down version into memory but I don't want to lose image quality
To some extent, you do not have much of a choice. If you want the user to see the full extent of the picture at once, the image has to be scaled to fit the screen.
Is there any way to handle OutOfMemoryError without loading scaled down version?
There are ImageView replacements that offer pan and zoom. Some of those, such as this one, handle loading in pieces of the image at a time, with whatever scaling is necessary for the current zoom level, to make it more likely that you will be able to show the user the entire image.
It is not a solution, of course, but I'm also not familiar with your exact needs, so maybe this may help you a little - you can try to play with bitmap options during decoding. Try to use Bitmap.Config.inPreferredConfig as RGB_565 - this will reduce size of your bitmap twice comparing to default ARGB_8888. But, of course, if you use complex images in your web page this may reduce their quality.
In terms of RAM utilized by a drawable when it is rendered on on the screen, does it make any difference if the drawable is a vector or a bitmap?
I understand that vectors take less media storage space, but I'm asking about the resident RAM needed in order to render it, since in theory, it is still being drawn onto a canvas with the same amount of pixels in the end.
Thanks!
From the document I read sometime ago (same question with you).
The different between these 2 options is the size of APK file after all when you release. SVG will help you save size of apk.
The initial loading of a vector graphic can cost more CPU cycles than the corresponding raster image. Afterward, memory use and performance are similar between the two. We recommend that you limit a vector image to a maximum of 200 x 200 dp; otherwise, it can take too long to draw.
Being drawn on view will have those 2 options having same RAM (memory) consumed.
My reference source: https://developer.android.com/studio/write/vector-asset-studio.html#about
use vector drawables for simple shapes. Using the same for complex structures will increase the size of the apk rapidly.
I have an application that displays lots of images, and images can be of varying size up to full screen dimensions of device. The images are all downloaded, and I use imagemagick to reduce colors of image to compress the file size, while keeping dimensions the same, to reduce download time. The reduced color space is fine for my application.
The problem is that when I load the image into a Bitmap in android the file size is much larger because of androids Bitmap config of ARGB_8888, I do need the ALPHA channel. Since ARGB_4444 is deprecated and had performance issues I am not using that. I am wondering if there is any other way to reduce the memory footprint of the loaded Bitmap while keeping the dimensions the same as the original?
---- Update ---
After discussions here and lots of other searching/reading it does not appear that there is a straight forward way do this. I could use ARGB_4444 which stores each pixel as 2 bytes, rather than 4 bytes per pixel. The problem there is that ARGB_4444 is deprecated, and I try not to use deprecated parts of the API for obvious reasons. Android recommends use of ARGB_8888 which is the default, since I need alpha I have to use that. Since there are many applications that do not need such a complex color space it would be nice to see ARGB_4444 or something similar become part of the supported API.
If you don't need alfa (transparency) you can use:
Bitmap.Config.RGB_565
which uses 2 bytes per pixel, instead of 4, reducing size by half.
You should also look at BitmapFactory.Options:
inSampleSize
inScaled
These values correctly set for your requirements, may have a very positive effect on Bitmap memory requirements.
Regards.
Read a similar answer I posted here
Basically, bitmap recycle is required for Pre honeycomb devices to reduce memory usage
I am joining two images using the code below but it throws an OutOfMemory error my images are around 1MB each.
private Bitmap overlayMark(String first, String second)
{
Bitmap bmp1, bmp2;
bmp1 = BitmapFactory.decodeFile(first);
bmp2 = BitmapFactory.decodeFile(second);
if (bmp1 == null || bmp2 == null)
return bmp1;
int height = bmp1.getHeight();
if (height < bmp2.getHeight())
height = bmp2.getHeight();
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth() + bmp2.getWidth(), height,
Bitmap.Config.ARGB_8888);// Out of memory
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, 0, 0, null);
canvas.drawBitmap(bmp2, bmp1.getWidth(), 0, null);
bmp1.recycle();
bmp2.recycle();
return bmOverlay;
}
Update: I tried below two answers but it still not allwoing me to create bitmap of such big size the problem is that the resultant bitmap is too large in size around 2400x3200 so its going out of memory.
How can I join large images without running out of memory?
Without loading the image into memory, you CAN get the size of the image, using inJustDecodeBounds. The Bitmap returns null, but all the parameters are set. You can scale down the image accordingly.
If your JPEG images are 1 MiB each, conversion to a BMP will take a lot of memory indeed. You can easily calculate its BMP equivalent by the dimensions of the image. Conversion of such a large image is expected to crash indeed. Android limits its apps to 16 MiB VM only.
Also use RGB_565 instead of ARGB_8888.
So your only solution is:
(a) To use BitmapFactory.Options.inSampleSize to scale down the image
or
(b) Use Android NDK where the 16 MiB limit isn't there.
I use this simple rule of the thumb:
the heavy lifting (both memory/CPU) is done on the server.
So write some servlet that takes the image, resizes it to a specified dimension (probably reduces the pixel depth too) and returns the result.
Piece of cake and it works on any mobile device you need.
Good luck!
I think a solution sort of like Sumon suggests might work.
Figure out the size of the final
image based on what will fit on the
screen.
Get the size of the first image using
the inJustDecodeBounds technique.
Figure out the size of the first
image in the final image. Calculate
re-sizing parameters.
Resize image, loading into memory.
Write resized image back to disk.
Recycle the bitmap. (This will help
when resizing the 2nd image)
Repeat for the second image, only you
can skip the writing to disk part.
Load first image.
If you only need to display, then just do that. If not then you can combine into a single bitmap at this point and write to disk. If this is the case, it may be difficult because you wil have essentially 2x the screen size in memory. In that case I would recommend resizing smaller. If you can't go smaller, then you will have to go the NDK route, thought I'm not sure how much that will help. Here's an amusing intro to the NDK and JNI. Finally, I would highly recommend developing this using a phone running Android 2.3+ since its use of heap-allocated bitmaps will make debugging much easier. More about those here.
It's not necessary that the space taken by in-memory representation of bitmaps correspond closely with file size. So even if you have 3mb memory available to jvm, you might still get OutOfMemoryException.
Your code is creating three in-memory images simultaneously. If you can find the size of both images without reading the complete files, you can modify the code in a way to have only one of the source images in memory at a time. If even that doesn't prove to be sufficient you might need some sort of streaming method of reading the images.
you may get some idea from here.
Are you trying to display this super large image or are you just trying to save it?
If your trying to display it. Cut the images into tiles. Then only display the tiles that are being viewed. If the user zooms out you need to reduce the size of the bitmap before showing the whole thing.
If your trying to save it, try saving it in sections to the same file by cutting the image up.
Loading 2 1m files in memory then creating a 2m file leaves you with 4M in memory for your images alone. Dynamically loading and unloading the memory solves this issue similar to tiles on Google maps or dynamic zooming in other map oriented solutions.
If you need to return that huge 2400x3200 bitmap as your result, there is no way to actually realize this goal. The reason is that 2400*3200*4 bytes ~ 30 Mb! How can you hope to implement this method, when even you can't even fit the return value into your limited heap space (ie 16Mb)?
And even if you used 16-bit color, it would still fail because you would end up using about 15MB, which would not leave you enough space for the language run time.
I am trying to decode a bitmap with pixel size 1024*683 with the api
decodefile(filepath) but process runs out of memory while decoding the
image.
I need the bitmap object for this image at one go without any scaling
as i have to work with NDK reading the pixel values using this bitmap.
Therefore any scaling or sampling method can't be applied in my case.
I wonder how come this is possible that just decoding a file with
such size would need any in-around method. There is enough heap size
available for this process.
Your opinion and perspective in this matter will be appreciated.
Thanks
Nawab
I faced the same problem when I had memory leaks in one of my activities. There were not only view leaks, but bitmap leaks too. And memory consumed by bitmaps is not taken into account when DDMS shows free heap space.