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.
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 want to crop image of large size and tried using Bitmap.createBitmap but it gives OOM error. Also, tried multiple technique around createBitmap but none of them were successful.
Now I thinking of saving image to file system and crop it without loading image into memory that might solve the problem. But don't know how to do it.
User flow: User will take multiple pictures from in-app camera after each snap user can crop it manually or app will silently crop it on some predefine login and later it will send these images to server.
Can anybody guide me how I can achieve this?
There is a class called BitmapRegionDecoder which might help you, but it's available from API 10 and above.
If you can't use it :
Many image formats are compressed and therefore require some sort of loading into memory.
You will need to read about the best image format that fits your needs, and then read it by yourself, using only the memory that you need.
a little easier task would be to do it all in JNI, so that even though you will use a lot of memory, at least your app won't get into OOM so soon since it won't be constrained to the max heap size that is imposed on normal apps.
Of course, since android is open source, you can try to use the BitmapRegionDecoder and use it for any device.
I very much doubt you can solve this problem with the existing Android API.
What you need to do is obtain one of the available image access libraries (libpng is probably your best bet) and link it to your application via jni (see if there's a Java binding already available).
Use the low-level I/O operations to read the image a single scanline at a time. Discard any scanlines before or after the vertical cropped region. For those scanlines inside the vertical cropped region, take only those pixels inside the horizontal cropped region and write them out to the cropped image.
I would like to capture an image with the Android Camera but because the image may contain sensitive data I dont want the image saved to the phone or sd card. Instead I would like a base64 string (compressed) which would be sent to the server immediately
In PhoneGap it seems files are saved to various places automatically.
Natively I was never able to get the image stream - in onJpegPictureTaken() the byte[] parameter was always null.
can anyone suggest a way?
See Camera.onPreviewFrame() and the YuvImage.compresstoJpeg() to be able to get a byte array you can convert into a bitmap.
Note that YuvImage.compressToJpeg() is only available in SDK 8 or later, I think. For earlier versions you'll need to implement your own YUV decoder. There are several examples around or, I could provide you an example.
Those two methods will allow you to get a camera picture in memory and never persist it to SD. Beware that bitmaps of most camera preview sizes will chew up memory pretty quickly and you'll need to be very careful to recycle the bitmaps and probably also have to scale them down a bit to do much with them and still fit inside the native heap restrictions on most devices.
Good luck!
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)