Androidのカメラの向きに関する覚え書き

Androidでカメラを使ったアプリを作っているんだが、端末本体(カメラ)の向きに合わせて撮影した写真の向きも変えるのが結構面倒。その辺のAndroid API仕様の覚え書き。

Androidでは、カメラの向きに関するポリシーは、以下のどちらかになると思われる。

  1. 端末本体の向きに関係なく、アプリの向きlandscape固定にする
  2. 端末本体の向きに合わせて、アプリの向きや写真の向きを変える

1.が一番簡単。マニフェストファイルの要素で、android:screenOrientation属性を"landscape"にするだけ。カメラのプレビュー表示も撮影した写真の向きも全部landsacpe(横長)に固定される。

2.が結構面倒。カメラのプレビュー表示と撮影した写真の2つの向きを、それぞれ端末本体の向きに合うように制御する必要がある。

カメラのプレビュー表示の向きを変える

Cameraをopen()したあと、setDisplayOrientation()メソッドでプレビュー表示の向きを、端末本体の向きに合わせて変更する。これをしないと、カメラから撮影する対象の向きと、プレビュー表示の向きが合わなくなる。コードは、下記を参考に。
Camera#setDisplayOrientation()のAPI doc

撮影した写真の向きを変える

最初は、Camera.Parameters#setRotation()で変えられると思ったが、Camera.PictureCallbackで渡されるJPEG画像の向きが変わるかどうかは機種依存らしい。少なくとも手元のXPERIA arcでは向きは変わらなかった。
Camera.Parameters#setRotation()のAPI doc

仕方ないので、自分でBitmapを操作して、端末の向きに合わせて写真の向きを変える事にした。例えば、onPictureTaken()メソッドを下記のように実装する。

public void onPictureTaken(byte[] data, Camera camera) {
    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;
    }
    Matrix m = new Matrix(); //Bitmapの回転用Matrix
    m.setRotate(degrees);
    Bitmap original = BitmapFactory.decodeByteArray(data, 0, data.length);
    Bitmap rotated = Bitmap.createBitmap(
        original, 0, 0, original.getWidth(), original.getHeight(), m, true);
    savePicture(rotated);    	
}