連載
» 2010年05月27日 00時00分 公開

Androidで動く携帯Javaアプリ作成入門(17):もはやケータイに必須のカメラをAndroidで制御しよう (2/3)

[ 緒方聡,株式会社イーフロー]

カメラ起動Activityのコード

 カメラを起動するだけのActivityのソースコードは以下の通りです。

 フルスクリーンにしたり、タイトルを消したりするのは必須ではありませんが、行った方がプレビューの見栄えが良いです。これらを行った後で、カメラ用のプレビューを設定します。

public class Hello extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new CameraPreview(this));
    }
}

 カメラのプレビューはSurfaceViewで作成します。疑似コードを以下に示します。

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder holder;
    protected Camera camera;
 
    CameraPreview(Context context) {
        super(context);
        holder = getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        camera = Camera.open();
        camera.setPreviewDisplay(holder);
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        camera.stopPreview();
        Camera.Parameters params = camera.getParameters();
        params.setPreviewFormat(format);
        params.setPreviewSize(width, height);
        camera.setParameters(params);
        camera.startPreview();
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
    }
}

 この疑似コードは、エラー処理やプレビューの再表示などが考慮されていません。これらの細かい処理については後ほど解説するとして、ここでは基本的な部分のみを解説します。

SurfaceViewのタイプ変更

 SurfaceViewのタイプをノーマルからプッシュバッファに変更します。

holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

カメラの起動

 SurfaceCreatedメソッド内で、【1】カメラをオープンし、【2】プレビューディスプレイを設定します。

camera = Camera.open(); // 【1】
camera.setPreviewDisplay(holder); // 【2】

プレビューサイズ変更

 SurfaceChangedメソッド内では、【1】プレビューを停止し、【2】カメラパラメータを取得し、【3】プレビューのフォーマットと、【4】プレビューのサイズをカメラパラメータに設定し、【5】カメラにパラメータをカメラに設定し、【6】プレビューを再開します。

camera.stopPreview(); // 【1】
Camera.Parameters params = camera.getParameters(); // 【2】
params.setPreviewFormat(format); // 【3】
params.setPreviewSize(width, height); // 【4】
camera.setParameters(params); // 【5】
camera.startPreview(); // 【6】

カメラの終了

 SurfaceDestroyedメソッド内で、【1】プレビューを停止し、【2】カメラをリリースします。

camera.stopPreview(); // 【1】
camera.release(); // 【2】

 このようにカメラのライフサイクルは、カメラのプレビューのライフサイクルにひも付けると管理が簡単です。

 上記解説の実際の動作は、ダウンロードしたアプリの「Hello」というアクティビティで確認できます。

AndroidのAPIで写真撮影をするには

 次は、起動したカメラで写真を撮影します。カメラのシャッターに当たるトリガーは、プログラマが自由に決められます。今回はメニューと、画面のタッチで撮影できるようにしてみます。

 Cameraクラスには「autoFocus」というメソッドがあり、これにAutoFocusCallbackを設定することで、オートフォーカスが行われた直後にコールバックが呼び出されるようになります。写真撮影にオートフォーカスは必須ではないのですが、オートフォーカス機能を使用しないと、常にピンボケの写真が撮影されてしまうため、今回はオートフォーカス機能を使用して写真を撮影します。

 ただし、オートフォーカスを使用すると、0.5〜1秒程度、タイムラグが発生するため「いま見えているものを、そのまま撮影したい」という場合は、オートフォーカスを使用しないのも、1つの方法です。

 以下はオートフォーカスを使用する撮影のコード例です。

void autoFocus() {
    camera.autoFocus(new AutoFocusCallback() { // 【1】
        @Override
        public void onAutoFocus(boolean success, final Camera camera) { // 【2】
            ShutterCallback shutter = new ShutterCallback() { // 【3】
 
……【略】……
 
            };
            PictureCallback raw = new PictureCallback() { // 【4】
 
……【略】……
 
            };
            PictureCallback jpeg = new PictureCallback() { // 【5】
                @Override
                public void onPictureTaken(byte[] data, Camera camera) { // 【6】
                    FileOutputStream fos = new FileOutputStream("/sdcard/test.jpg");
                    fos.write(data);
                    fos.close();
                }
            };
            camera.takePicture(shutter, raw, jpeg); // 【7】
            new Thread() {
                @Override
                public void run() {
                    Thread.sleep(3000); // 【8】
                    camera.startPreview(); // 【9】
                }
            }.start();
        }
    });
}

 まず、【1】「Camera#autoFocus(AutoFocusCallback)」にコールバックを登録します。登録するコールバックは、【2】onAutoFocusメソッドが実装されている必要があり、このメソッドがオートフォーカス後に呼び出されます。このコールバックメソッド内で写真撮影を行うので、【3】ShutterCallback、【4】rawdata用のPictureCallback、【5】JPEG用のPictureCallbackを用意します。

 JPEG用のコールバック内で実際に保存を行うため、【6】onPictureTakenメソッド内で処理します。コールバックが用意できたら、【7】Camera#takePictureメソッドを呼び出すと撮影が行われます。このままだと撮影した状態でプレビューが止まったままになるので、【8】3秒だけ待ってから、【9】プレビューを再開します。

 上記コードは簡単のために例外処理などを省略しています。詳しく知りたい方は、アプリのソースを確認してみてください。

 後は、メニューやタッチイベントからこのメソッドを呼び出すだけですが、メニューは「カメラは横向き」という仕様があるため、かなり違和感があります。

図2 カメラアプリでメニューを表示(常に横方向でメニューが出てしまう) 図2 カメラアプリでメニューを表示(常に横方向でメニューが出てしまう)

 メニュー以外の方法で撮影を行う方がいいでしょう。

 それでは、次ページよりフラッシュやフォーカス、エフェクトの使い方を詳しく見ていきましょう。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。