概ね、タイトルとおりです。
・【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 ){} } } } }
【実行結果】