概ね、タイトルとおりです。
・【Android】カメラ機能を使ってプレビューをSurfaceViewに表示する方法
↑前回の記事でカメラのプレビューを表示するところまでやっているので、
今回で実際にシャッターを切り撮影する機能を紹介してみます。
AndroidManifestにSDカードを使用する用のパーミッションを追加
AndroidManifest.xmlに以下の一文追加するだけです。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
撮影のトリガーとなるシャッターボタンを付ける
前回のプログラムでは全画面にプレビューを表示するだけでしたので、
まず撮影するボタンを付けてみます。
SurfaceView sv;
SurfaceHolder sh;
Button btn;
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       LinearLayout ll = new LinearLayout(this);
       ll.setOrientation(LinearLayout.VERTICAL);
       setContentView(ll);
       sv = new SurfaceView(this);
       sh = sv.getHolder();
       sh.addCallback(  new SampleCallback() );
       sh.setType( SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS );
        btn = new Button(this);
        btn.setText("撮影");
        ll.addView(btn);
        ll.addView(sv);
        btn.setOnClickListener( new SampleClick() );
   }
  class SampleClick implements OnClickListener{
    @Override
    public void onClick(View v) {
    }
  }
ボタンにOnClickListenerを登録しています。
takePicture関数の引数にコールバックを設定する
撮影をする時には、CameraクラスのtakePicture関数を使います。
この関数の引数には3つのコールバックを設定できます。
| Camera.ShutterCallback shutter | シャッター音を鳴らす時に使用 | 
|---|---|
| Camera.PictureCallback raw | RAW画像データを受け取る時に使用 | 
| Camera.PictureCallback jpeg | JPEG画像データを受け取る時に使用 | 
今回は三番目のJPEG画像データを受け取るコールバックを使いSDカードに保存する処理を紹介します。
class SampleClick implements OnClickListener{
@Override
public void onClick(View v) {
	cm.takePicture(null, null, new SamplePictureCallback() );
}
  class SamplePictureCallback implements PictureCallback{
  	@Override
  	public void onPictureTaken(byte[] data, Camera camera) {
  		try{
  			File dir = new File( Environment.getExternalStorageDirectory(), "sample20120712" );
  			if( dir.exists() == false ){
  				dir.mkdir();
  			}
  			File f = new File( dir, "test.jpg" );
  			FileOutputStream out = new FileOutputStream(f);
  			out.write(data);
  			Toast.makeText(getApplicationContext(), "保存しました。", Toast.LENGTH_LONG).show();
  			out.close();
  			//プレビュー再開
  			cm.startPreview();
  		}catch( Exception e ){}
  	}
  }
}
撮影された時にCameraクラスのtakePicture関数を実行。
三番目の引数にコールバック用の内部クラスを設定しています。
onPictureTaken関数の第一引数にjpegデータが渡されるので、それをSDカードに保存しています。
最後にstartPreview関数でプレビューを再開させています。
サンプルプログラム
(importは省略)
public class Sample20120712Activity extends Activity {
	Button btn;
	SurfaceView sv;
	SurfaceHolder sh;
	Camera cm;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        setContentView(ll);
        //全画面表示
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        sv = new SurfaceView(this);
        sh = sv.getHolder();
        sh.addCallback(  new SampleCallback() );
        sh.setType( SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS );
        btn = new Button(this);
        btn.setText("撮影");
        ll.addView(btn);
        ll.addView(sv);
        btn.setOnClickListener( new SampleClick() );
    }
    class SampleCallback implements Callback{
		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,	int height) {
			try{
				int d = 90;
				cm.setDisplayOrientation(d);
				cm.setPreviewDisplay(sv.getHolder());
				Camera.Parameters pr = cm.getParameters();
				pr.setPictureSize( width , height );
				cm.setParameters(pr);
				cm.startPreview();
			}catch( Exception e ){ }
		}
		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			cm = Camera.open();
			Camera.Parameters pr = cm.getParameters();
			List<Size> ss = pr.getSupportedPictureSizes();
			Size s = ss.get(0);
			pr.setPictureSize( s.width , s.height );
			cm.setParameters(pr);
		}
		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			cm.stopPreview();
			cm.release();
		}
    }
    class SampleClick implements OnClickListener{
  		@Override
  		public void onClick(View v) {
  			cm.takePicture(null, null, new SamplePictureCallback() );
  		}
  		class SamplePictureCallback implements PictureCallback{
  			@Override
  			public void onPictureTaken(byte[] data, Camera camera) {
  				try{
  					File dir = new File( Environment.getExternalStorageDirectory(), "sample20120712" );
  					if( dir.exists() == false ){
  						dir.mkdir();
  					}
  					File f = new File( dir, "test.jpg" );
  					FileOutputStream out = new FileOutputStream(f);
  					out.write(data);
  					Toast.makeText(getApplicationContext(), "保存しました。", Toast.LENGTH_LONG).show();
  					out.close();
  					//プレビュー再開
  					cm.startPreview();
  				}catch( Exception e ){}
  			}
  		}
    }
}
【実行結果】
  				  			