Android Image Rotation
During recent development of an Android app we came across an interesting “bug” that was difficult to tackle. When taking a picture with the Android camera, the resulting image was rotated unpredictably. After a few Google searches it was clear that we were not the only ones having this issue as seen here in these forums:
As you can see, this was even occurring even in the very popular Facebook app. Part of the issue with this stems from a seemingly excellent aspect of Android development where you can pass off common tasks to other applications (Activities).
In this case, if you'd like to take a picture, rather than writing the image choosing/taking code yourself, you can ask the user to select an application that is currently installed on their device to take the picture, and return it to you. To do this in code, you create an intent and pass MediaStore.ACTION_IMAGE_CAPTURE, pass it a uri where you'd like the image to be saved, and let an onboard camera application do the work for you as shown here:
// create Intent to take a picture and return control to the calling application Intent intent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);// create a file to save the image intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);// set the image file name // start the image capture Intent startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
This can be done for a number of different tasks including sharing, photos, etc. The problem in this instance was that if the application was not properly writing the orientation of the photo, the returned photo was incorrectly oriented and there was no way to predict how to properly rotate it.
After much trial and error, we were able to determine the cause of this problem. The first clue we discovered was that no matter the orientation of the device when the picture was taken, the image was reporting the same orientation, which in our case was always 90 degrees. At first, we were using the Android chooser to allow the user to use an on board camera application. However, we were not able to reliably get a correctly oriented image, so we decided to write our own image capturing Activity.
Writing our own image capturing Activity turned out to be fairly easy, and is documented very clearly in the Android documentation here: http://developer.android.com/guide/topics/media/camera.html. For this to work, you essentially place a SurfaceView on the screen and connect it to the Android Camera. After some initial setup, you use the method Camera.takePicture() and save the byte data to the disk. After implementing this, we discovered that the Android Camera framework was at fault for writing the incorrect orientation. In our own camera activity, when we returned the image, we had the exact same problem where the images were being stored with the orientation of 90 degrees.
At this point, we tried to force the camera to be set to the orientation of the screen, but oddly enough the setCameraOrientation() method actually didn't set the camera orientation because the camera orientation is not settable (not sure why they provide you with a method that does nothing).
After some digging we discovered that the Android camera is mounted to the device, and therefore will always report the same orientation, no matter the actual orientation of the device. This makes sense if you think about it, because if you had a hand held camera and turned it upside down to take a picture, your image would be upside down.
We also tried to implement the CameraParams().setRotation(), which states in the documentation that it will rotate the image after taking the image, returning to you a properly rotated image. We found that this is not the case, and also does nothing (oh Android...sigh). So the problem was not that the camera was reporting the orientation wrong, it was that we needed to tell Android how to rotate the image so the user sees it correctly oriented.
In Android, each image saved has metadata associated with it called ExifData, and ExifData is what is used to correctly orient the image. When taking a picture, the camera will automatically write the orientation to the ExifData for the mounted orientation of the camera. Again, this is not technically incorrect; it is just an inconvenience for a user trying to view the image. In order for Android to properly show the image as we intended, after taking the image, we needed to rewrite the orientation of the screen (not the camera) to the ExifData.
So, in our camera activity, we simultaneously take the picture and record the orientation of the device. After the image is saved to disk, we recover (or create) the ExifData for this image, and write the proper orientation.
We noticed that the orientation was incorrectly being reported in the Android camera apps for each device we were testing on (4 separate devices), so we recommend always writing your own image capturing activity. The actual amount of code required for such an activity is relatively small (about 200 lines) and is well documented in the Android developer documentation. If you write your own activity, then you can be sure that your rotation will always be as expected, and you will not have to guess based on the device/version/app of Android used to take the image.
You can download Mindgrub's Camera Activity from github at : https://github.com/Mindgrub/MGCameraActivity