カメラを起動するだけの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.