Developer от Бога

DV

пятница, 7 июля 2017 г.

Android. Android.hardware.camera2. Сохранение фото

В прошлом примере был показан способ воспроизведения видео с камеры в реальном времени на поверхность TextureView, в этом примере будет показан комплекс действий по захвату полноценного изображения с камеры и сохранения его в папке с фотографиями. На схеме выше изображены три шага по работе с камерой в Android API 21 и выше (класс android.hardware.camera2).

1) Извлекаем нужные статичные данные о камере из класса CameraDevice, а  подкласса CameraDevice.StateCallback и его метода обратного вызова onOpened(CameraDevice camera) узнаем о готовности камеры к работе. Через  CameraManager.openCamera() открываем камеру.

2) CameraCaptureSessi создает сессию, а в CaptureRequest.Builder (постройщик запроса) заносятся параметры запроса (воспроизведение на выбранную поверхность SurfaceTexture или iImageReader c последующим сохранением). Ход запросов можно отслеживать через объект CameraCaptureSession.CaptureCallback  и метод обратного вызова
onCaptureCompleted() который вызывается системой по успешном окончании захвата изображения. В нем как правило можно переконфигурировать запрос CaptureRequest.Builder
и перенаправить изображение на класс iImageReader для последующего сохранения, вместо обычного TextureView при обычном воспроизведении.

3) В ImageReader и  его метод setOnImageAvailableListener() устанавливаем класс обратного вызова ImageReader.OnImageAvailableListener, метод которого  public void onImageAvailable(ImageReader reader) вызывается как только изображение будет готово для последующей обработки (сырое изображение передается входному аргументу метода).


В созданном классе ImageSaver проходит комплекс действий по обработке байтов изображения в нужный формат и его сохранению в папку с фотографиями.

  1. import android.content.Context;
  2. import android.content.Intent;
  3. import android.graphics.ImageFormat;
  4. import android.graphics.SurfaceTexture;
  5. import android.hardware.camera2.CameraAccessException;
  6. import android.hardware.camera2.CameraCaptureSession;
  7. import android.hardware.camera2.CameraDevice;
  8. import android.hardware.camera2.CameraManager;
  9. import android.hardware.camera2.CaptureRequest;
  10. import android.hardware.camera2.TotalCaptureResult;
  11. import android.media.Image;
  12. import android.media.ImageReader;
  13. import android.net.Uri;
  14. import android.os.Environment;
  15. import android.os.Handler;
  16. import android.os.HandlerThread;
  17. import android.support.v4.content.ContextCompat;
  18. import android.support.v7.app.AppCompatActivity;
  19. import android.os.Bundle;
  20. import android.view.Surface;
  21. import android.view.TextureView;
  22. import android.view.View;
  23. import android.widget.ImageButton;

  24. import java.io.File;
  25. import java.io.FileOutputStream;
  26. import java.io.IOException;
  27. import java.nio.ByteBuffer;
  28. import java.text.SimpleDateFormat;
  29. import java.util.Arrays;
  30. import java.util.Date;



  31. public class MainActivity extends AppCompatActivity {

  32. private TextureView iTextureView;
  33. private CameraDevice iCameraDevice;

  34. private HandlerThread iBackgroundHandlerThread;
  35. private Handler iBackgroundHandler;
  36. private ImageReader iImageReader;

  37. private CameraCaptureSession iPreviewCaptureSession;
  38. private CaptureRequest.Builder iCaptureRequestBuilder;
  39. private ImageButton foto;

  40. private File iImageFolder;
  41. private String iImageFile;


  42. @Override
  43. protected void onCreate(Bundle savedInstanceState) {
  44. super.onCreate(savedInstanceState);
  45. setContentView(R.layout.activity_main);

  46. createImageFolder();

  47. iTextureView = (TextureView) findViewById(R.id.textureView);
  48. foto = (ImageButton) findViewById(R.id.cameraImageButton2);





  49. foto.setOnClickListener(new View.OnClickListener() {
  50. @Override
  51. public void onClick(View v) {
  52. try {iPreviewCaptureSession.capture(iCaptureRequestBuilder.build(), iPreviewCaptureCallback, null); }
  53. catch (CameraAccessException e) { e.printStackTrace(); }
  54. } }); }




  55. private TextureView.SurfaceTextureListener iSurfaceTextureListener =
  56. new TextureView.SurfaceTextureListener() {
  57. @Override
  58. public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
  59. iImageReader = ImageReader.newInstance(1920,1080, ImageFormat.JPEG, 1);
  60. iImageReader.setOnImageAvailableListener(iOnImageAvailableListener,null);
  61. connectCamera();}

  62. @Override
  63. public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { }
  64. @Override
  65. public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
  66. return false;
  67. }
  68. @Override
  69. public void onSurfaceTextureUpdated(SurfaceTexture surface) {}};






  70. private CameraDevice.StateCallback iCameraDeviceStateCallback = new CameraDevice.StateCallback() {
  71. @Override
  72. public void onOpened(CameraDevice camera) {iCameraDevice = camera; startPreview(); }

  73. @Override
  74. public void onDisconnected(CameraDevice camera) { camera.close(); iCameraDevice = null; }

  75. @Override
  76. public void onError(CameraDevice camera, int error) {camera.close(); iCameraDevice = null; }
  77. };






  78. private final ImageReader.OnImageAvailableListener iOnImageAvailableListener = new
  79. ImageReader.OnImageAvailableListener() {
  80. @Override
  81. public void onImageAvailable(ImageReader reader) {
  82. iBackgroundHandler.post(new ImageSaver(reader.acquireLatestImage()));} };



  83. private class ImageSaver implements Runnable {

  84. private final Image iImage;

  85. public ImageSaver(Image image) { iImage = image; }

  86. @Override
  87. public void run() {
  88. ByteBuffer byteBuffer = iImage.getPlanes()[0].getBuffer();
  89. byte[] bytes = new byte[byteBuffer.remaining()];
  90. byteBuffer.get(bytes);

  91. FileOutputStream fileOutputStream = null;

  92. try {fileOutputStream = new FileOutputStream(iImageFile);
  93. fileOutputStream.write(bytes); }

  94. catch (IOException e) { e.printStackTrace(); }

  95. finally {
  96. iImage.close();

  97. Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  98. mediaStoreUpdateIntent.setData(Uri.fromFile(new File(iImageFile)));
  99. sendBroadcast(mediaStoreUpdateIntent);

  100. if(fileOutputStream != null) {try {fileOutputStream.close();}
  101. catch (IOException e) { e.printStackTrace(); }}}}}






  102. private CameraCaptureSession.CaptureCallback iPreviewCaptureCallback = new
  103. CameraCaptureSession.CaptureCallback() {

  104. @Override
  105. public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
  106. super.onCaptureCompleted(session, request, result);

  107. try {
  108. iCaptureRequestBuilder.addTarget(iImageReader.getSurface());
  109. iPreviewCaptureSession.capture(iCaptureRequestBuilder.build(), run2, null);

  110. } catch (CameraAccessException e) { e.printStackTrace(); }

  111. }
  112. };









  113. @Override
  114. protected void onResume() {
  115. super.onResume();

  116. startBackgroundThread();

  117. if(iTextureView.isAvailable()) {

  118. connectCamera();
  119. } else {
  120. iTextureView.setSurfaceTextureListener(iSurfaceTextureListener);
  121. }
  122. }

  123. private void connectCamera() {
  124. CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);

  125. try { ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA);
  126. cameraManager.openCamera("0", iCameraDeviceStateCallback, null);}
  127. catch (CameraAccessException e) { e.printStackTrace(); }}






  128. CameraCaptureSession.StateCallback run = new CameraCaptureSession.StateCallback(){

  129. @Override
  130. public void onConfigured(CameraCaptureSession session) {

  131. iPreviewCaptureSession = session;
  132. try {iPreviewCaptureSession.setRepeatingRequest(iCaptureRequestBuilder.build(),null, null);}
  133. catch (CameraAccessException e) {e.printStackTrace();}}

  134. @Override
  135. public void onConfigureFailed(CameraCaptureSession session) {} };






  136. CameraCaptureSession.CaptureCallback run2 = new
  137. CameraCaptureSession.CaptureCallback() {
  138. @Override
  139. public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {

  140. super.onCaptureStarted(session, request, timestamp, frameNumber);

  141. try {createImageFileName();}
  142. catch (IOException e) { e.printStackTrace(); } } };





  143. private void startPreview() {
  144. SurfaceTexture surfaceTexture = iTextureView.getSurfaceTexture();
  145. surfaceTexture.setDefaultBufferSize(1920,1080);
  146. Surface previewSurface = new Surface(surfaceTexture);

  147. try {
  148. iCaptureRequestBuilder = iCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  149. iCaptureRequestBuilder.addTarget(previewSurface);
  150. iCameraDevice.createCaptureSession(Arrays.asList(previewSurface,iImageReader.getSurface()),run, null);}

  151. catch (CameraAccessException e) {e.printStackTrace();}}




  152. private void startBackgroundThread() {
  153. iBackgroundHandlerThread = new HandlerThread("Camera2Foto");
  154. iBackgroundHandlerThread.start();
  155. iBackgroundHandler = new Handler(iBackgroundHandlerThread.getLooper()); }


  156. private void createImageFolder() {
  157. File imageFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  158. iImageFolder = new File(imageFile, "Camera2Foto");
  159. if(!iImageFolder.exists()) {
  160. iImageFolder.mkdirs(); } }



  161. private File createImageFileName() throws IOException {
  162. String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
  163. String prepend = "IMAGE_" + timestamp + "_";
  164. File imageFile = File.createTempFile(prepend, ".jpg", iImageFolder);
  165. iImageFile = imageFile.getAbsolutePath();
  166. return imageFile; }


  167. } return imageFile; }

Комментариев нет:

Отправить комментарий