カメラを起動するだけの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のタイプをノーマルからプッシュバッファに変更します。
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」というアクティビティで確認できます。
次は、起動したカメラで写真を撮影します。カメラのシャッターに当たるトリガーは、プログラマが自由に決められます。今回はメニューと、画面のタッチで撮影できるようにしてみます。
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】プレビューを再開します。
上記コードは簡単のために例外処理などを省略しています。詳しく知りたい方は、アプリのソースを確認してみてください。
後は、メニューやタッチイベントからこのメソッドを呼び出すだけですが、メニューは「カメラは横向き」という仕様があるため、かなり違和感があります。
メニュー以外の方法で撮影を行う方がいいでしょう。
それでは、次ページよりフラッシュやフォーカス、エフェクトの使い方を詳しく見ていきましょう。
Copyright © ITmedia, Inc. All Rights Reserved.