From e0bbb93f6a598206ecd6e09150d51eae64bd3507 Mon Sep 17 00:00:00 2001 From: Wei-Ta Chen Date: Fri, 11 Nov 2011 19:07:58 -0800 Subject: Set the orientation of a panorama image. The panorama image returned from the panorama library is oriented based on the natural orientation of the camera. We set an orientation in its EXIF header, so that the image can be displayed correctly. The orientation is calculated by compensating the device orientation and the camera orientation respective to the natural orientation of the device. Bug: 5603313 Change-Id: Id6907cb08a7ff77e44736f3c3cd1503e7a68d783 --- src/com/android/camera/Storage.java | 6 ++- src/com/android/camera/Util.java | 6 +++ .../android/camera/panorama/PanoramaActivity.java | 49 ++++++++++++++++++++-- 3 files changed, 56 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index 38a6d48..ea281a9 100644 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -52,7 +52,7 @@ public class Storage { public static Uri addImage(ContentResolver resolver, String title, long date, Location location, int orientation, byte[] jpeg, int width, int height) { // Save the image. - String path = DIRECTORY + '/' + title + ".jpg"; + String path = generateFilepath(title); FileOutputStream out = null; try { out = new FileOutputStream(path); @@ -98,6 +98,10 @@ public class Storage { return uri; } + public static String generateFilepath(String title) { + return DIRECTORY + '/' + title + ".jpg"; + } + public static long getAvailableSpace() { String state = Environment.getExternalStorageState(); Log.d(TAG, "External storage state=" + state); diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java index ba8a4f7..d6ebb0a 100644 --- a/src/com/android/camera/Util.java +++ b/src/com/android/camera/Util.java @@ -350,6 +350,12 @@ public class Util { return result; } + public static int getCameraOrientation(int cameraId) { + Camera.CameraInfo info = new Camera.CameraInfo(); + Camera.getCameraInfo(cameraId, info); + return info.orientation; + } + public static int roundOrientation(int orientation, int orientationHistory) { boolean changeOrientation = false; if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) { diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java index fe70827..331c849 100755 --- a/src/com/android/camera/panorama/PanoramaActivity.java +++ b/src/com/android/camera/panorama/PanoramaActivity.java @@ -52,6 +52,7 @@ import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; import android.hardware.Sensor; import android.hardware.SensorManager; +import android.media.ExifInterface; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -71,6 +72,7 @@ import android.widget.TextView; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.util.List; /** @@ -177,6 +179,8 @@ public class PanoramaActivity extends ActivityBase implements // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise // respectively. private int mDeviceOrientation; + private int mDeviceOrientationAtCapture; + private int mCameraOrientation; private int mOrientationCompensation; private RotateDialogController mRotateDialog; @@ -343,7 +347,9 @@ public class PanoramaActivity extends ActivityBase implements private void openCamera() { try { - mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId()); + int backCameraId = CameraHolder.instance().getBackCameraId(); + mCameraDevice = Util.openCamera(this, backCameraId); + mCameraOrientation = Util.getCameraOrientation(backCameraId); } catch (CameraHardwareException e) { Util.showErrorAndFinish(this, R.string.cannot_connect_camera); return; @@ -573,6 +579,7 @@ public class PanoramaActivity extends ActivityBase implements mPanoProgressBar.setIndicatorWidth(20); mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE); mPanoProgressBar.setVisibility(View.VISIBLE); + mDeviceOrientationAtCapture = mDeviceOrientation; keepScreenOn(); } @@ -804,7 +811,13 @@ public class PanoramaActivity extends ActivityBase implements } else if (!jpeg.isValid) { // Error when generating mosaic. mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); } else { - int orientation = Exif.getOrientation(jpeg.data); + // The panorama image returned from the library is orientated based on the + // natural orientation of a camera. We need to set an orientation for the image + // in its EXIF header, so the image can be displayed correctly. + // The orientation is calculated from compensating the + // device orientation at capture and the camera orientation respective to + // the natural orientation of the device. + int orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation); if (uri != null) { // Create a thumbnail whose width or height is equal or bigger @@ -894,14 +907,42 @@ public class PanoramaActivity extends ActivityBase implements private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) { if (jpegData != null) { - String imagePath = PanoUtil.createName( + String filename = PanoUtil.createName( getResources().getString(R.string.pano_file_name_format), mTimeTaken); - return Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, + Uri uri = Storage.addImage(getContentResolver(), filename, mTimeTaken, null, orientation, jpegData, width, height); + if (uri != null && orientation != 0) { + String filepath = Storage.generateFilepath(filename); + try { + // Save the orientation in EXIF. + ExifInterface exif = new ExifInterface(filepath); + exif.setAttribute(ExifInterface.TAG_ORIENTATION, + getExifOrientation(orientation)); + exif.saveAttributes(); + } catch (IOException e) { + Log.e(TAG, "cannot set exif data: " + filepath); + } + } + return uri; } return null; } + private static String getExifOrientation(int orientation) { + switch (orientation) { + case 0: + return String.valueOf(ExifInterface.ORIENTATION_NORMAL); + case 90: + return String.valueOf(ExifInterface.ORIENTATION_ROTATE_90); + case 180: + return String.valueOf(ExifInterface.ORIENTATION_ROTATE_180); + case 270: + return String.valueOf(ExifInterface.ORIENTATION_ROTATE_270); + default: + throw new AssertionError("invalid: " + orientation); + } + } + private void clearMosaicFrameProcessorIfNeeded() { if (!mPausing || mThreadRunning) return; mMosaicFrameProcessor.clear(); -- cgit v1.1