1

In Android I have noticed that when I take a picture with the camera and map it to an ImageView, on some cameras (such as my physical phone), it's rotated 90 degrees (whereas on the emulator phones I use, they aren't rotated).

I tried this:

    //once you have the main bitmap
    ExifInterface ei = null;
    try {
        ei = new ExifInterface(imageFilepath);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
        bitmap = getRotatedBitmap(bitmap, orientation);
    }
    catch (IOException e) {
        e.printStackTrace();
    }        

Now the rotate code:

public static Bitmap getRotatedBitmap(Bitmap bitmap, int orientation) {
    Matrix matrix = new Matrix();
    switch (orientation) {
        case ExifInterface.ORIENTATION_NORMAL:
            return bitmap;
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
            matrix.setScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.setRotate(180);
            break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            matrix.setRotate(180);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
            matrix.setRotate(90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.setRotate(90);
            break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
            matrix.setRotate(-90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.setRotate(-90);
            break;
        default:
            return bitmap;
    }
    try {
        Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap.recycle();
        return bmRotated;
    }
    catch (OutOfMemoryError e) {
        return bitmap;
    }
}

Is this correct? Or is it horribly inefficient? Is there some smarter way to do this? If I apply the rotate code to a bitmap and then save it back to Storage, will it now be "incorrectly rotated" or do I have to rotate it back? I don't know what the accepted practice is for all this.

1 Answers1

0

Is this correct?

I am skeptical that you will actually see all of those orientation possibilities in the wild. And rotating the image takes up a lot of heap space, so expect this code to fail with an OutOfMemoryError sometimes.

Is there some smarter way to do this?

If all you want is for the image to show up properly in the ImageView, rotate the ImageView.

If I apply the rotate code to a bitmap and then save it back to Storage, will it now be "incorrectly rotated" or do I have to rotate it back?

That's impossible to answer, as only you know how you are saving it and what "incorrectly" would mean in that context. IMHO, if you are going through this process, you rotate it to the ORIENTATION_NORMAL state, then either save it with no EXIF headers or save it with ORIENTATION_NORMAL.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • "IMHO, if you are going through this process, you rotate it to the ORIENTATION_NORMAL state, then either save it with no EXIF headers or save it with ORIENTATION_NORMAL." How would I do this, though? Rotate the bitmap, save over the old file, somehow replace the EXIF? – user7461935 Jan 24 '17 at 13:07
  • @user7461935: If you use a better `ExifInterface`, you can write tags as well as read them. In [this sample app](https://github.com/commonsguy/cw-omnibus/blob/master/Camera/EXIFRotater/app/src/main/java/com/commonsware/android/exif/MainActivity.java), I demonstrate both rotating the `ImageView` and (separately) rotating the actual bitmap, setting the EXIF orientation header to 1. In principle, you could copy other EXIF headers from the old file to the new one, though I forget whether or not that is practical. – CommonsWare Jan 24 '17 at 13:16
  • I am not really sure what all that means in the context of my question. Are you saying I can't just rotate the source image (by rotating the bitmap and then saving that bitmap as the .png) accordingly and set it to ORIENTATION_NORMAL? – user7461935 Jan 24 '17 at 13:24
  • @user7461935: Sure you can. However, whatever you write out will not have EXIF headers, unless you arrange to add them yourself. For example, `Bitmap#compress()` does not write out EXIF headers, even if you choose JPEG as the format. The `ExifInterface` implementation that I culled from the AOSP and used in that sample app allows you to write a JPEG with EXIF headers that you supply. However, doing so sets *all* the headers. – CommonsWare Jan 24 '17 at 13:25
  • Are you saying that if I rotate and re-save the file, all the EXIF information will be wiped out / not retained? Wouldn't this not matter with respect to having it display in the right orientation for an ImageView? – user7461935 Jan 24 '17 at 13:28
  • @user7461935: "Are you saying that if I rotate and re-save the file, all the EXIF information will be wiped out / not retained?" -- again, it depends on how you are saving it. "Wouldn't this not matter with respect to having it display in the right orientation for an ImageView? " -- you lost me there. If all you want to do is show the image in the correct orientation in the `ImageView`, just rotate the `ImageView`, as you will not run out of heap space doing that (the rotation is handled on the GPU). – CommonsWare Jan 24 '17 at 13:31
  • In my particular case I don't know if I can just rotate the ImageView because I'm also trying to incorporate some canvas-related stuff where the x and y coordinates need to be specific (I'm allowing the user to add a shape as an overlay to an image) – user7461935 Jan 24 '17 at 13:33
  • @user7461935: You should be able to rotate stuff as you draw them to the `Canvas`. If you are downsampling the bitmap (e.g., `BitmapFactory.Options` and `inSampleSize`), then the heap issues become less likely, and rotating the bitmap using your above algorithm may be successful. You can further reduce the odds of heap issues if your images happen to have consistent sizes, and you can reuse existing allocated `Bitmap` objects, rather than recycling them and trying to allocate them fresh again later. – CommonsWare Jan 24 '17 at 13:38
  • What I meant earlier was that if I were to rotate the bitmap and then save over the original file, would this probably take care of the issue? It would not have EXIF data right? But no EXIF data = it probably shows up with the equivalent of ORIENTATION_NORMAL by default when mapped to an ImageView? – user7461935 Jan 24 '17 at 13:43
  • @user7461935: Correct on all counts. There are other EXIF headers beyond orientation, though, and they will be lost too. I do not know if that is an issue for you or not. BTW, `drawBitmap()` on `Canvas` takes a `Matrix`. – CommonsWare Jan 24 '17 at 13:49