クリエイターブログ/システム開発

システム開発

Androidアプリにおける最小限のカメラ機能の実装

概要

Androidのアプリ開発においてカメラ機能を使用したいことがあります。
Intentを発行することで標準のカメラ機能を使用することができますが、今回はIntentではなくカメラアプリ等を作成する際に使用するCamera2 APIを使った実装方法を紹介します。
Camera2 APIを使うことでよりカスタマイズ性に富んだアプリを開発することができます。

※注意
Camera2 APIはAPI Level 21 以上で動作します。
カメラの使用には権限(Permission)が必要となります。
今回必要となる権限は以下のものとなります。
・android.permission.CAMERA
権限を与えたうえで実行してください。(権限を与えずに実行すると、アプリが正しく実行しないので注意してください。)

具体的なテーマ

今回は大きく分けて3つの段階に分けて紹介したいと思います。なおアプリの画面構成は以下の通りです。

TextureViewはカメラのプレビューを表示するためのビューです。
Buttonは撮影のイベントを発火させるためのビューです。

使用した端末はNexus5(Android 6.0)です。

カメラに接続する

・CameraManagerを取得し、使用可能なカメラIDを取得します。


//CameraManagerの取得
CameraManager mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
//利用可能なカメラIDのリストを取得
String[] cameraIdList = mCameraManager.getCameraIdList();
//用途に合ったカメラIDを設定
String mCameraId = null;
for(String cameraId: cameraIdList){
    //カメラの向き(インカメラ/アウトカメラ)は以下のロジックで判別可能です。(今回はアウトカメラを使用します)
    CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
    switch(characteristics.get(CameraCharacteristics.LENS_FACING)) {
        case CameraCharacteristics.LENS_FACING_FRONT:
            //インカメラ
	     break;
        case CameraCharacteristics.LENS_FACING_BACK:
	     //アウトカメラ
	     mCameraId = cameraId;
	     break;
        default:
    }
}

・カメラIDとCameraDevice.StateCallbackのインスタンスを使ってCameraDeviceをオープンし、CameraDevice.StateCallbackからCameraDeviceのインスタンスを取得(カメラに接続)します。


//CameraDeviceをオープン
mCameraManager.openCamera(mCameraId, mStateCallback, null);

//CameraDeviceインスタンス用変数
CameraDevice mCameraDevice = null;

//CameraDevice.StateCallback詳細
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
	 //接続成功時、CameraDeviceのインスタンスを保持させる
	 mCameraDevice = cameraDevice;
	 createCameraPreviewSession();	//次フェーズにて説明します。
    }
    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
	 //接続切断時、CameraDeviceをクローズし、CameraDeviceのインスタンスをnullにする
	 cameraDevice.close();
	 mCameraDevice = null;
    }
    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int error) {
	 //エラー発生時、CameraDeviceをクローズし、CameraDeviceのインスタンスをnullにする
	 cameraDevice.close();
	 mCameraDevice = null;
    }
};

カメラのプレビューを画面に表示

・CameraDeviceインスタンスからCameraCaptureSessionを生成し、リクエストを設定します。


//CameraCaptureSession用変数
CameraCaptureSession mCaptureSession = null;
//CaptureRequest用変数
CaptureRequest mPreviewRequest = null;
//画面にセットされたTextureView
TextureView mTextureView;

//CameraCaptureSession生成関数(前段CameraDevice.StateCallback.onOpened()より呼ばれる)
private void createCameraPreviewSession() {
    try {
        SurfaceTexture texture = mTextureView.getSurfaceTexture();

	 //バッファのサイズをプレビューサイズに設定(画面サイズ等適当な値を入れる)
	 texture.setDefaultBufferSize(1080, 1920);

	 Surface surface = new Surface(texture);

	 // CaptureRequestを生成
	 mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
	 mPreviewRequestBuilder.addTarget(surface);

	 // CameraCaptureSessionを生成
	 mCameraDevice.createCaptureSession(Arrays.asList(surface),
	         new CameraCaptureSession.StateCallback() {

	     @Override
	     public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
		 //Session設定完了(準備完了)時、プレビュー表示を開始
		 mCaptureSession = cameraCaptureSession;
		 try {
		     // カメラプレビューを開始(TextureViewにカメラの画像が表示され続ける)
		     mPreviewRequest = mPreviewRequestBuilder.build();
		     mCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);
		 } catch (Exception e) {
		     e.printStackTrace();
		 }
	     }

            @Override
	     public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
	         //Session設定失敗時
	         Log.e(TAG,"error");
	     }
        }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

撮影実行

・画面上に設置されたボタンのクリックイベントで以下の処理を実行させます。


try {
    //カメラプレビューを中断させる
    mCaptureSession.stopRepeating();
    File mFile = null;
    if (mTextureView.isAvailable()) {
        //TextureViewが使えることを確認し、"sample.jpg"という名前でファイルに書き出す
        mFile = new File(getActivity().getExternalFilesDir(null), "sample.jpg");
        FileOutputStream fos = new FileOutputStream(file);
        //TextureViewに表示されている画像をBitmapで取得
        Bitmap bmp = mTextureView.getBitmap();
        bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.close();
    }

    // カメラプレビューを再開
    mCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);

    //画像が出力されていたらトーストで通知
    if(mFile != null) {
        Toast.makeText(getActivity(), "Saved: " + mFile, Toast.LENGTH_SHORT).show(); 
    }
} catch(Exception e){
    e.printStackTrace();
}

まとめ

以上が最小限の撮影方法になります。
画像の保存先や、保存名を変更したり、オートフォーカスを効かせたりすることで実用的なカメラアプリを作成することが可能です。

最新記事

クリエイターブログの関連リンク