3

Can the code below cause OutOfMemory ? I think it allows to exceed the application memory limit.

Matrix matrix = new Matrix();
matrix.postRotate(orientation);

image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);

What is the best way to rotate an image in Android ?

Allocate it in a service in a new process to get more heap?

@CommonsWare said in this link [1] that many developers think that more heap is a solution for inefficient coding.

This question indicates large heap too [2].

Is there a simpler solution ?

[1] Can you start an IntentService on a separate process?

[2] How to avoid OutOfMemory ex while rotating the image?

trincot
  • 317,000
  • 35
  • 244
  • 286
insane.bot
  • 193
  • 1
  • 2
  • 11
  • 1
    Dealing with images has always been a risky business, i too have faced problems with my gaming app, You might want to look into this, if you haven't, already http://developer.android.com/training/displaying-bitmaps/load-bitmap.html – stack_ved Aug 22 '13 at 04:29
  • For 3.x and later devices just take reasonable measures to not keep a lot of unneeded bitmaps around. On 2.x devices there is no simple solution - You must very rigorously manage your bitmap references and recycling. – goto10 Aug 22 '13 at 04:34
  • If you want to rotate an image that originates from yuv format (such as camera preview or video frame decode), you will save memory. If your source is Jpeg (e.g. from a camera takePicture), it's possible to rotate it even faster. If you need a Jpeg for output, too, you can make rotation lossless. – Alex Cohn Jan 26 '14 at 18:04
  • In this spot: " ... Bitmap.createBitmap(..)" you will have TWO bitmap images at the same time. Original and New, so if you want to preserve quality for New image I think the best solution is to add "android:largeHeap="true"" in Application tag in Manifest file. Other solution will be to use some NDK libs which may or may not help you if you want to preserve quality. – Kirill Karmazin May 22 '17 at 12:27

4 Answers4

2

The short answer is, Yes, this code may cause OutOfMemory. I don't think that there is a simpler solution than increasing app heap size. I believe that @CommonsWare is right, and often OutOfMemory is an indication of wrong programming. But there are some situations when you need, ehm, huge memory. Rotation of a huge image is definitely one of such situations.

You can use native code (NDK) instead of asking for increased heap size, but this is definitely not easier. And it will still needs lots of memory, so there is no advantage in going for C++ (except that it works on 2.3).

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • i've added an NDK solution. check out my answer. – android developer Jan 26 '14 at 16:02
  • there are advantages in using NDK/C++: code runs faster and it could use more RAM then SDK app. Nowadays devices could have 1-2Gb RAM but SDK still limits RAM usage by 16Mb per process. – Stan Jan 28 '15 at 12:32
1

If you wish to use an NDK based solution, I've created one here, and i've made a github project here .

this will avoid OOM by putting the data into the native C "world", recycle the old data, and return the result back, after rotation.

it doesn't require any downsampling.

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • Could you please add compiled native libraries to your github (like ImageMagick devs did)? Cuz its really a BIG problem to compile it nowadays since for Windows it needs cygwin and the whole process is too complicated for SDK dev. Thanx. – Stan Feb 16 '15 at 07:37
  • @Stan It is ok to compile via Windows, and you don't need cygwin, just the NDK. Cygwin you might want for debugging, but I don't know how to do it for Android. I've already prepared instructions about how to compile the project. For me it worked on Eclipse. Someone else succeeded doing so for Android-Studio, and posted his instructions. – android developer Feb 16 '15 at 08:12
0

OutOfMemoryException thrown when your bitmap is to large to load in memory.

Here I am giving you one solution.

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap=BitmapFactory.decodeStream(is,null,options);

Use inSampleSize attribute of BitmapFactory.Options class.

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
    //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f),null,o);

    //The new size we want to scale to
    final int REQUIRED_SIZE=70;

    //Find the correct scale value. It should be the power of 2.
    int scale=1;
    while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
        scale*=2;

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize=scale;
    return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Jitesh Dalsaniya
  • 1,917
  • 3
  • 20
  • 36
  • This solution causes quality loss due to its main idea - using a smaller image size rather than original to avoid OOM. And when you need to keep original image size and quality while rotating it becames useless. – Stan Jan 28 '15 at 12:38
0

Here:

image = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);

code operates two bitmaps, the first image is a Bitmap you previosly loaded/decoded into RAM to work with - to rotate actually. And the second one will be created by Bitmap.createBitmap() no matter you store the result into the same variable. Anyway at this line you need bitmap x2 RAM and this causes the OOM for sure (speaking of device's camera biggest possible photos).
I think that using NDK is the best solution here.
Please check my very same question here for additional possible solution (MappedByteBuffer) and it has links to NDK/JNI solutions as well.

Community
  • 1
  • 1
Stan
  • 6,511
  • 8
  • 55
  • 87