Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crop image without OutOfMemory - Android

I want to crop image without getting OutOfMemory exception.
it means i have x, y, width and height of cropped image and want to crop original image without bringing it to memory.
Yes i know that BitmapRegionDecoder is good idea but maybe the cropped image would be too large for bringing it to memory.

In fact i don't want copped bitmap, just want to write cropped image from source file to destination file.


EDIT : I want to save cropped image not just showing it in an ImageView I want to save it in a new file without losing dimensions

This is the example
enter image description here

in this situation cropped image resolution is 20000x20000 and code below wont work cause of OOM:

BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);

using inSampleSize to decrease the original picture size is good but the result i save is no longer 20000x20000.

How can i crop the 25000x25000 and save the 20000x20000 part of image in a file?

like image 611
Sepehr Behroozi Avatar asked Dec 27 '15 11:12

Sepehr Behroozi


2 Answers

Simply put, it requires lots of low level programming and optimizations.

as you can see, lots of answers in this region are pointing to generic concepts of bitmap compression, etc which are indeed applicable in most issues but not specifically yours.

Also BitmapRegionDecoder as suggested in answers won’t work well. It sure prevents loading the whole bitmap in RAM but what about the cropped image? after cropping an image it gives you a giant bitmap which no matter what, gives you an OOM.

Because your problem as you described, needs Bitmaps to get written or get read from disk just as they get written or read from memory; something called a BufferedBitmap (or so) which efficiently handles the memory it requires by saving little chunks of a bitmap to disk and using them later, thus, avoiding OOM.

Any other solution which wants to tackle the problem with scaling only do half of the work. why? because cropped image itself can be too big for memory (as you said).

However, solving the problem by scaling isn’t that bad, if you don’t care about the quality of the cropped image compared to the quality user had seen when she was cropping it. that’s what the Google Photos do, it simply reduces the quality of cropped image, very simple!

I haven’t seen any BufferedBitmap classes around (but if there are, it would be awesome). They sure become handy for solving similar problems.

You can check Telegram messaging app which comes with an open-source implementation of image cropping facilities; you guess right, it handles all the similar nasty works with good old C... Hence, we might conclude that a good global solution (or better said, ONE OF THE SEVERAL APPLICABLE SOLUTIONS) appears to be low-level programming to handle disk and memory yourself.

I know my answer failed to give any copy-paste-ish solution to your problem but at least I hope it gave you some ideas my friend.

like image 53
Dusk Avatar answered Oct 25 '22 12:10

Dusk


Did you checked BitmapRegionDecoder? It will extract a rectangle out of the original image.

BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);

http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html

like image 35
Ankit Aggarwal Avatar answered Oct 25 '22 12:10

Ankit Aggarwal