カメラのプレビューを回転して縦画面に対応する(Android 2.2〜)


以下、ウチの IS05 でカメラアプリを試作中、カメラのプレビュー画面が縦画面に対応できなくて嵌ったときのメモ。


IS05 を横持ち(本体右側面にあるシャッターボタンが上に来るよう)にしたときは、普通にプレビューが表示されるが、縦に持ち替えたとたん、本来横用画面の画像を無理矢理縦長にしたみたいなおかしな縦横比でプレビューが表示されるので困っていた。
これに簡単に対応する方法は、****Manifest.xmlでレイアウトを横画面固定にしてしまうことだが(android:screenOrientation="landscape"を指定)、そうするとメニューボタン押下時に表示されるメニューも横画面用のものに固定されてしまい、縦持ちで使ったときに残念な表示になる。


いろいろ調べていったところ、どうやら古い Android はカメラのプレビューが横画面のみ対応していたが、2.2からはAPIで回転できるようになったらしいことが判明。
Camera.setDisplayOrientation() でカメラのプレビューを回転できる。
サンプルコードもSDKに記載されている。


以下、Android Developpers:Camera.setDisplayOrientation より引用

 public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         //★引用者注:ここが背面カメラ用の処理
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }

しかし、このサンプルは、ソース中で Android 2.3 からサポートされるクラスを使っている(Camera.CameraInfo)ので、うちの IS05 (2.2)の環境ではそのまま利用できない。
ウチのIS05で調べたところ、背面カメラでこのソース中の「info.orientation」に当たる場所には、90 を固定で入れておくと問題なくプレビューが回転されることが判明した(前面カメラは未検証)。
Camera.CameraInfo.orientationが IS05 で固定 90 になるのは、SDKの以下に書いてある内容と合致するように思う。


http://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation


なお、上記の setDisplayOrientation コール時は、あらかじめCamera.stopPreview()をコールしてプレビューを止めておく必要がある。


また、この問題ではまっている人は結構いるようで、ぐぐると他にもいくつか対処法が出てくる。
# Camera.Parameters.set("orientation", "portrait") とか
# Camera.Parameters.setRotation() 等。
私も最初はそれらを IS05で試していたのだが、どれもうまく動作せず、最終的に Camera.setDisplayOrientation を使う方法に落ち着いた。Android が 2.2 より古いバージョンの場合や他の実機では、他の方法でもうまくいくのかもしれない。