I want to display a bitmap read from the SD card at actual pixel size in Android.
I can't assume anything about the bitmap, other than Android supports its image format. The bitmap might be huge.
Seems simple enough, but when you factor Android memory limitations it gets much more complicated.
Any ideas?
Edit: Attempting to load a large bitmap gives an out of memory error because Android is not able to allocate enough memory to decode it. You can load a scaled down version of the bitmap, but this is not useful to show the bitmap at actual pixel size. The question is about how to show a large bitmap on Android while staying within the app's memory constraints (most likely by loading it in chunks).
Edit 2: The bitmap might be huge, but within the realm of reasonable. I'm talking about user images, not HD Nasa pictures.
The managed code (Java) has memory limits of 16/24/32MB even if your device has a lot more free memory. I'm currently working on an application which needs to do this and the solution is to allocate the bitmap in native code (NDK) and then render views of the image into a Java-allocated bitmap which is the size of the display. In native code you can allocate all available memory of the device, but for some reason the virtual machine limits it.
Since android 2.3 (Gingerbread, API Level 10), you can use the BitmapRegionDecoder. I don't know any solution for older android versions. (and I've been looking for it for my EmailAlbum app)
Related
I would like to load, process and store high resolution image. In spite of largeHeap="true" option in AndroidManifest.xml, when some high resolution image was loaded, OOM exception was occurred frequently.
By googling, I knew that using JNI can load bitmap to native heap on lower version than Android 3.0. If so, how can I use native heap for bitmap on higher version of it? still JNI?
In my opinion, you should decode and process each part of big bitmap instead of process whole the bitmap. It'll help to avoid OOM.
BitmapRegionDecoder can be used to decode a rectangle region from an image. Hope it can help.
I am not sure that what do you mean by "process", but you could use the following library if you need to load large data and then zoom in to extract more details
https://github.com/davemorrissey/subsampling-scale-image-view
I'm writing a camera app and when I take a picture, I receive a byte [], decode it into a Bitmap and rotate it before saving it to JPEG. I'm rotating the photo using a native library, however the bitmap is still decoded from a byte[] into memory for this (still, allows me to keep 1 Bitmap instead of 2). So essentially there's 1 place in my code where I require a lot of memory and OOM on some devices where heap is low and cameras are stupid-megapixels. Any suggestions how to fix this without on loosing image quality?
I don't think I want to use largeHeap="true"
Should I forget about rotation and just set EXIF?
Also I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up: Android OutOfMemory when GC reports free memory?
Any suggestions how to fix this without on loosing image quality?
Use android:largeHeap="true".
Or, use some other native library that allows you to hand over the byte[] and does the rotation and saving to disk for you, to avoid the Bitmap and any Java-level processing of the huge thing.
Or, if your minSdkVersion is 19, and the rest of your logic supports it, use inBitmap on BitmapFactory.Options to try to reuse an already-allocated Bitmap object rather than allocate a fresh one. This option is available on earlier versions of Android, but for those it has to be an exact match in terms of resolution; on 19+, the Bitmap to be reused just has to be big enough to handle what you are trying to load into it.
I don't think I want to use largeHeap="true"
It may not help (not all devices will give you a larger heap), and there are costs to the user for the larger heap limit. That being said, manipulating big camera images is difficult without more memory, whether that is in the Java heap or represents allocations from the OS from native code.
Should I forget about rotation and just set EXIF?
That's certainly another possibility, though various things, like ImageView, seem to ignore EXIF headers.
I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up
In part, that's because Dalvik does not have a compacting/moving GC, and ART only has one while your app is not in the foreground. OutOfMemoryError means that there is no single contiguous free block of memory for what you are trying to allocate.
You might not have enough memory to create a rotated copy of a large bitmap.
You could instead paint a rotated image of the original.
Furthermore there are things that need to be considered when processing images:
Always load images scaled to the size of the ImageView.
Always recycle your images
Consider using largeHeap=true if you still have issues. Android might be growing the heap size too slowly (see https://stackoverflow.com/a/14462026/1390015).
I am Working with one android tablet application in which lots of work with Images.
i have to load hundred of large bitmap images in scroll view. one image is around 1Mb to 3 Mb.
i have already scale images using bitmap factory and sample size, and also load all the images in Async task.
i am loading all the images from SD card.
Still facing OUT OF MEMORY issue after scrolling some images.
any help would be appreciated.
thanks in advance.
hi hope your solution.
you can user Univarsal Image Loader. This is better api for image download and store in catch. and get from catch. it's a great api for image operation.
this case is often come while we getting bitmap so just use lazy loading. just take a look on this example
http://sunil-android.blogspot.in/2013/09/lazy-loading-image-download-from.html
To prevent your application from soaking up CPU time without getting anything done, the JVM throws this Error so that you have a chance of diagnosing the problem.
Its because of large bitmap memory in stored in native area
so it better i suggest you use libraries like Universal Image Loader or
Bitmap Fun from android
You have to find out when the OOM error occurs. Is it when you have too much bitmap cache in memory without releasing or you just meet it when you're decoding certain bitmap?
For the first situation, I think you should manage your bitmap cache yourself or using some effective 3rd-party library which mentions above.
For the second situation, I've met it on some low-performance mobile(usually with 512MB or less memory), when you decode a bitmap to requested size, it may needs a rather large memory to store the bitmap, for 240dpi devices, it's about 800 * 480 * 4 = 1.5MB, however you may fail to allocate that much memory on some machines cause they may have strict memory manage strategy to prevent that much memory allocation. You should just catch the OOM error and continue rather than get a crush.
Loading a bitmap in 1280x800 display will take 1280x800x4 byte (~4MB) memory. Java heap size is limited (~50MB) so you can not use lots of large bitmaps in your app. Using cache and reusing bitmap objects are necessary while working with bitmaps but another useful trick is to use larger hip size! to do so, add android:largeHeap="true" to Application tag in your manifest. It increases hip size to 4 or 5 times larger (~250MB) than normal. I hope this help other people reaching this thread while they search!
In: Decoding bitmaps in Android with the right size - it is posted that sampling down a bitmap may still lead to memory errors.
Is this issue still valid for newer versions of Android?
Does this mean that before sampling down, Android needs to load the full-size bitmap into memory? I believe this uses native memory, since image handling is implemented in native code.
Here is how you can get the available memory amount:
Runtime.getRuntime().maxMemory()
and here is an interesting blog about memory:
http://codelog.dexetra.com/getting-around-android-memory-blues
The problem with Android is ou never know when you may run ou of memory and the app just crashes. That is why you should try to avoid loading too large bimaps (I usually use maximum of 800 /600 or something like that depending on the screen orientation....)
If loading several bitmaps like for gallery or other view group you should use weak reference:
http://developer.android.com/reference/java/lang/ref/WeakReference.html
Also if you look at the example in the link you provided the scaling first decodes only bounds and then decides on the scale to use.
When you don't need a bitmap anymore call:
bitmap.recycle();
Newer versions might have more physical memory but it's still limited to whatever is the system stack size; that way, programming bitmap still should be done very carefully with the amount of memory used.
On this years Google I/O (2012) there was a great presentation named "Doing more with less" that shows some very nice caching techniques you should look into. I'm sure you can find this video on YouTube Android Developers account.
Found the video: http://www.youtube.com/watch?v=gbQb1PVjfqM
I'm performing an OCR utility for Android and I'd like to crop an image on the fly, I mean, take the picture and in the JPEG callback be able to crop the image from the byte array Android returns to you before to save it or whatever.
The original issue is that I need to generate a bitmap from that image and, if it has high resolution, I'm getting a "Bitmap exceeds VM budget" error. Also I'd like to crop the image (automatically, not allowing the user to do it) because of processing time of the OCR.
I saw a BitmapRegionDecoder class from Android 2.3.3 forth that makes all I'd like to do, but I need to work with earlier versions. Any suggestions?
Thank you guys!
Assuming it doesn't use any native code, just copy BitmapRegionDecoder to your project and use that instead of the system version.
Finally I've realized the only two feasible options seem to be storing the photo in the SD card and work with it after or to use a native library (which memory allocation is done out of the Dalvik VM heap so you're able to use up to 10 times more RAM than inside the VM). I think I'll choose to store it first. Seems to be more simple to do and maintain.