Androidでカメラアプリを作成する(Android5.0以降に対応) (2)
Androidでカメラアプリを作成する(Android5.0以降に対応) (2)
撮影機能を実装する
カメラを準備するメソッドの修正
.. 省略 private Handler mBackgroundHandler; // ->(1) private ImageReader mImageReader; .. 省略 private void prepareCameraView() { CameraManager cameraManager = (CameraManager) mParentActivity.getSystemService(Context.CAMERA_SERVICE); try { String backCameraId = null; for (String cameraId : cameraManager.getCameraIdList()) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) { backCameraId = cameraId; StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0]; Size jpegSize = getJPEGSize(characteristics); // ->(2) mImageReader = ImageReader.newInstance(jpegSize.getWidth(), // ->(3) jpegSize.getHeight(), ImageFormat.JPEG, 1); mImageReader.setOnImageAvailableListener(mReaderListener, mBackgroundHandler); // ->(4) } } .. 省略
(1) バックグラウンドハンドラをメンバ変数として定義する onResumeでスレッドを開始させておく(コードは省略)
(2) ストリーム設定からJPEGの出力サイズを取得する
(3) 画像を取得するためのImageReaderの初期化
(4) Image取得リスナーをセットする 実装内容は後述
ImageReaderとは
SurfaceTextureの画像にアクセスする機能を提供するクラス
撮影メソッドの実装
.. 省略 private void takePicture() { if(null == mCameraDevice) { return; } try { mCaptureRequestBuilder.addTarget(mImageReader.getSurface()); // ->(5) mCaptureRequestBuilder.set( // ->(6) CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); int rotation = mParentActivity.getWindowManager().getDefaultDisplay().getRotation(); // ->(7) mCaptureRequestBuilder.set( CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); mCaptureSession.capture(mCaptureRequestBuilder.build(), // ->(8) new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, // ->(9) @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); } }, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } .. 省略
(5) 生成したImageReaderからSurfaceを取得する
(6) 自動モードをセットする
(7) 画像の縦横を設定する
(8) キャプチャを開始する
(9) キャプチャ成功時のコールバック
ImageReaderのコールバック
キャプチャが成功するとImageReadr.OnImageAvailableListenerに結果がかえってくる
.. 省略 private ImageReader.OnImageAvailableListener mReaderListener = new ImageReader.OnImageAvailableListener() { public void onImageAvailable(ImageReader imageReader) { // ->(10) Image image = imageReader.acquireNextImage(); // ->(11) ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); OutputStream output = null; String saveDirectory = Environment.getExternalStorageDirectory().toString(); String saveFileName = "pic_" + System.currentTimeMillis() + ".jpg"; try { File file = new File(saveDirectory,saveFileName); output = new FileOutputStream(file); output.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { if (image != null) { image.close(); } if (output != null) { try { output.close(); } catch (IOException e) { e.printStackTrace(); } } } String[] paths = {saveDirectory + "/" + saveFileName}; // ->(12) String[] mimeTypes = {"image/jpeg"}; MediaScannerConnection.scanFile(mParentActivity.getApplicationContext(), paths, mimeTypes, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String s, Uri uri) { mParentActivity.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(mParentActivity,"saved",Toast.LENGTH_LONG).show(); createCameraCaptureSession(); // ->(13) } }); } } ); } }; .. 省略
(10) 画像を取得可能になったときのコールバック
(11) バッファから画像をファイルとして保存していく処理
(12) MediaScannerConnectionでファイルをスキャンする これはメディアライブラリで使用可能にするための処理
(13) 再度プレビューを開始する
サンプルコード
githubに置いてありますので、参考にしていただければと思います。