Android: Rotating large image crashes without throwing an error - android

I have searched and found simple code to rotate an image. I am pulling the image out of an ImageView object into a bitmap, rotating it then putting it back. I realize this is not the most effective method but I don't think it should crash without giving an error message in the CATCH block.
Here is my code. The only value passed in is "r" or "l" depending on which direction I want to rotate. Smaler images (1500x1500 or smaller) work just fine. Things go bad around the 2500x2500 size.
public void rotate(String dir)
{
try
{
float angle = (dir.equals("r") ? 90 : -90);
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Matrix matrix = new Matrix();
matrix.reset();
matrix.postRotate(angle);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
imageView.setImageBitmap(bitmap);
}
catch(Exception e)
{
Utilities.logError(e.toString());
}
}
Any clue as to why it is crashing and why it doesn't thow an exception? I just get a message "Unfortuantly process .... has stopped" and I get kicked back to the welcome screen of my app.
Oh, for kicks I set the angle to ZERO (hard coded) and it didn't crash. I suspect that it is just taking too long to rotate and Android is having a fit. But I am not sure how to confirm that as the problem or how to tell Android to wait a little longer.
Even if I reduce the preview image for the rotation, when I go to save I will have to rotate the full size image at least once and will hit this same issue. Won't I?

I can more or less guarantee without looking at the logs that you're getting an Out Of Memory Exception.
You need to use smaller images, or use a different method to rotate that doesn't use up so much memory (you're allocating 2 2500x2500 bitmaps at the same time here! that's tons!).
Try using a RotateAnimation to get your effect instead.
Hope this helps :)

Related

Android out of memory error while rotate a bitmap

I am currently working on a project in which one I would like to rotate a bitmap.
The first time, I create my bitmap with the following code :
myBitmap = BitmapFactory.decodeResource(getResources(), drawableResource);
Then I rotate the bitmap using the following code :
final Matrix matrix = new Matrix();
matrix.postRotate(currentRotate);
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, directionBitmap.getWidth(), directionBitmap.getHeight(), matrix, true);
I works, but after several times, the memory increases and I have the following exception :
java.lang.OutOfMemoryError: Failed to allocate a 119071756 byte
allocation with 16775968 free bytes and 96MB until OOM
It seems that the old bitmaps are still in memory. How to delete/recycle them in order to save the memory ?
Thank your for your help.
I can suggest you to use Glide library from Github.
This library works in background threads. Anyway you can perform your rotation on Background like this:
runOnUiThread(new Runnable(final Matrix matrix = new Matrix();
matrix.postRotate(currentRotate);
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, directionBitmap.getWidth(), directionBitmap.getHeight(), matrix, true);
)
In my case, the problem was with the size of the bitmaps I was using. The bitmaps I was using were of very high pixels for the given device. In such case, Android system has to descale them to lower pixel density i.e. the one that will suit your device. When you rotate the bitmap, Android system takes up a lot of memory to descale it to lower pixels. Also, Android gets busy and in some cases results in UI thread blocking.
Also, increase the heap size in your manifest file.

Face not detected using vision google service

https://developers.google.com/android/reference/com/google/android/gms/vision/face/FaceDetector.Builder
I'm using the above google service in my app for face detection. I made sure my phone has the minimum google play service version, which on my phone is 8.3, but still I can't get the face detection to work! I imported the library by importing the google play library in my eclipse project.... Here's the code:
#Override
protected void onPreExecute()
{
detector = new FaceDetector.Builder(MainContext)
.setTrackingEnabled(false)
//.setProminentFaceOnly(true)
.setLandmarkType(FaceDetector.ALL_LANDMARKS) //required
.build();
}
private void detectTheFace(Bitmap converted)
{
Frame frame = new Frame.Builder().setBitmap(converted).build();
faces = detector.detect(frame);
}
I don't know if it's necessary to convert the bitmap you use to detect the faces has to be RGB_565 configuration but I did it anyways. I tried with and without changing the RGB configuration and it yields the same results. Basically the faces sparse array is of size 0 meaning it doesnt detect a face.... ever. Btw just to give some context on the above code, I'm executing the face detection in a async task because I want to run it on the background.
I have the same problem ,i.e. it was working fine on nexus but not in galaxy. I resolved the problem by rotating the bitmap to 90 degree in case detector.detect() method gives faces of zero size. so maximum retry is 3 times after calling detector.detect() because 4th rotation gives you the same bitmap.
Bitmap rotateBitmap(Bitmap bitmapToRotate) {
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmapToRotate, 0, 0,
bitmapToRotate.getWidth(), bitmapToRotate.getHeight(), matrix,
true);
return rotatedBitmap;
}
check if the face return by detector.detect() has zero size then below code should run.
if(!faces.size()>0){
if (rotationCounter < 3) {
rotationCounter++;
bitmap= rotateBitmap(bitmapToRotate);
//again call detector.detect() here
}
}
you can check for the need of rotating bitmap without writing above code. From your original, code try to capture the image in landscape mode of phone or just rotate the image to 90 degree ans capture it.
To solve this problem, use the orientation specification from the EXIF of the photo.

Avoiding java.lang.OutOfMemoryError

Hi all I am developing live wallpapers, and I am using lot of bitmaps. I have tested my new live wallpaper for aboute a week, and it was up and runing perfectly, but as soon as I have uploaded it to a market I keep getting this kind of exceptions : java.lang.OutOfMemoryError for both android.graphics.Bitmap.nativeCreate and android.graphics.BitmapFactory.nativeDecodeAsset. I use this kind of lifecycle of an bitmap:
I create a reference like:
Bitmap dark = null;
Bitmap cave = null;
at onCreateEngine I init them like :
cave = BitmapFactory.decodeResource(getResources(), R.drawable.cave);
dark = BitmapFactory.decodeResource(getResources(), R.drawable.dark);
here is where it trows the exception. for these images: . and after all I draw them to an canvas like this:
canvas.save();
canvas.drawBitmap(bg, new Matrix(), new Paint());
canvas.drawBitmap(dark, new Matrix(), new Paint());
canvas.restore();
What Should I do? It is better to load the dark image just one picture and draw it to the canvas width*height times? Or Are there any methods to do? I think recycle or calling onDestroy. But I do not know when to call them because the exceptions are thrown at onCreate.Are the images too big? And why it is working smoothly on my device, and on the other devices it is throwing exceptions? The bitmaps are 1484*1484 dimension big and the clouds are 250*172 dimensional big, should they be in 2^x * 2^x dimension?
Just try to use Memory Optimizer and see where are you creating Memory Leaks. You can use Eclipse Memory Analyzer(MAT) for this. Its a very common problem with using bitmaps. By using BitMaps you need to be extra careful for memory leaks.

Photo rotated in custom camera application

My app is using camera to take photos. The problem is, the photo is rotated by 90 degrees. The app is designed to run in portrait orientation and I have set
android:configChanges="orientation|screenSize"
to avoid orientation changes. I thought I managed to fix it with
parameters.setRotation(90);
but it turns out that it varies on different devices (tested on lenovo ThinkPad tablet and a copule of smartphones). I tried reading the EXIF of the photo but orientation is not included there. I know there are many similar posts but most of them regards default camera app. Could someone explain me what this problem is caused by and how can i fix it? Thanks in advance.
Try this for getting image as u wanted
public static Bitmap createRotatedBitmap(Bitmap bm, float degree) {
Bitmap bitmap = null;
if (degree != 0) {
Matrix matrix = new Matrix();
matrix.preRotate(degree);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), matrix, true);
}
return bitmap;
}
bitmap = createRotatedBitmap(bitmap, 90);
Yes, orientation will not be exactly same for all the devices. It is completely hardware dependent, can vary device to device. You can't fix it, only one option you have just allow user to set the rotation once your application launched at first time get the base rotation angle and save it in to the settings and then give your functionality afterwards.

OutOfMemoryError: Android large Bitmap rotation (90°)

I have a big Memory Problem:
// in sourceImage is a big JPEG previously loaded
Matrix mat = new Matrix();
mat.postRotate(90);
Bitmap rotatedImage = Bitmap.createBitmap(sourceImage, 0, 0, sourceImage.getWidth(), sourceImage.getHeight(), mat, true);
Always i Run this code, my App crashes and says "VM won't let us allocate xxxxxx bytes"
Can you help me?
Edit:
I saw much similar questions here, but i don't know how to recycle the sourceImage before rotatating it... (cause the second instance is to big to hold it at the same time)
Thanks.
You can't create a new rotated bitmap without holding temporary 2 bitmaps in memory.
But you can display the bitmap rotated without creating a new bitmap (apply a transformation).
ImageView does not come with rotation capabilities, so you should write your own extended version of ImageView (RotatedImageView?).
The idea is to override the onDraw method with something like this (not tested).
#Override
public void onDraw(Canvas canvas) {
canvas.rotate((int)(angle * 180 / Math.PI), getWidth() >> 1, getHeight() >> 1);
super.onDraw(canvas);
}
For others like me:
there's an option to have the camera perform the rotation,
https://stackoverflow.com/a/16010289/755804

Categories

Resources