CameraActivity.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. package com.miekir.ocr;
  2. import android.Manifest;
  3. import android.annotation.SuppressLint;
  4. import android.content.Context;
  5. import android.content.res.Configuration;
  6. import android.graphics.ImageFormat;
  7. import android.graphics.Point;
  8. import android.graphics.SurfaceTexture;
  9. import android.hardware.camera2.CameraAccessException;
  10. import android.hardware.camera2.CameraCaptureSession;
  11. import android.hardware.camera2.CameraCharacteristics;
  12. import android.hardware.camera2.CameraDevice;
  13. import android.hardware.camera2.CameraManager;
  14. import android.hardware.camera2.CameraMetadata;
  15. import android.hardware.camera2.CaptureRequest;
  16. import android.hardware.camera2.TotalCaptureResult;
  17. import android.hardware.camera2.params.StreamConfigurationMap;
  18. import android.media.Image;
  19. import android.media.ImageReader;
  20. import android.os.Bundle;
  21. import android.os.Environment;
  22. import android.os.Handler;
  23. import android.os.HandlerThread;
  24. import android.util.Log;
  25. import android.util.Size;
  26. import android.util.SparseIntArray;
  27. import android.view.Surface;
  28. import android.view.TextureView;
  29. import android.view.View;
  30. import android.widget.Button;
  31. import android.widget.Toast;
  32. import androidx.annotation.NonNull;
  33. import com.miekir.ocr.base.BaseCameraActivity;
  34. import com.miekir.ocr.tool.Utils;
  35. import com.miekir.ocr.view.AutoFitTextureView;
  36. import com.tbruyelle.rxpermissions2.RxPermissions;
  37. import java.io.File;
  38. import java.io.FileNotFoundException;
  39. import java.io.FileOutputStream;
  40. import java.io.IOException;
  41. import java.io.OutputStream;
  42. import java.nio.ByteBuffer;
  43. import java.util.ArrayList;
  44. import java.util.Arrays;
  45. import java.util.Collections;
  46. import java.util.List;
  47. import java.util.concurrent.Semaphore;
  48. import java.util.concurrent.TimeUnit;
  49. import static android.os.Environment.DIRECTORY_PICTURES;
  50. public class CameraActivity extends BaseCameraActivity {
  51. private static SparseIntArray ORIENTATIONS = new SparseIntArray();
  52. static {
  53. ORIENTATIONS.append(Surface.ROTATION_0, 90);
  54. ORIENTATIONS.append(Surface.ROTATION_90, 0);
  55. ORIENTATIONS.append(Surface.ROTATION_180, 270);
  56. ORIENTATIONS.append(Surface.ROTATION_270, 180);
  57. }
  58. private String cameraId;
  59. private CameraDevice cameraDevice;
  60. private CameraCaptureSession cameraCaptureSessions;
  61. private CaptureRequest.Builder captureRequestBuilder;
  62. private Size imageDimension;
  63. private ImageReader imageReader;
  64. private File file = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES) + "/" + System.currentTimeMillis() + ".jpg");
  65. private static final int REQUEST_CAMERA_PERMISSION = 200;
  66. private Handler mBackgroundHandler;
  67. private HandlerThread mBackgroundThread;
  68. private AutoFitTextureView textureView;
  69. private Button button;
  70. private Semaphore mCameraOpenCloseLock = new Semaphore(1);
  71. private static final int MAX_PREVIEW_WIDTH = 1920;
  72. private static final int MAX_PREVIEW_HEIGHT = 1080;
  73. private int mSensorOrientation;
  74. private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
  75. @Override
  76. public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
  77. openCamera(width, height);
  78. }
  79. @Override
  80. public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
  81. if (null != textureView || null == imageDimension) {
  82. textureView.setTransform(Utils.configureTransform(width, height, imageDimension, CameraActivity.this));
  83. }
  84. }
  85. @Override
  86. public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
  87. return false;
  88. }
  89. @Override
  90. public void onSurfaceTextureUpdated(SurfaceTexture surface) {
  91. }
  92. };
  93. private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
  94. @Override
  95. public void onOpened(CameraDevice camera) {
  96. Log.e("tag", "onOpened");
  97. mCameraOpenCloseLock.release();
  98. cameraDevice = camera;
  99. createCameraPreview();
  100. }
  101. @Override
  102. public void onDisconnected(CameraDevice camera) {
  103. mCameraOpenCloseLock.release();
  104. cameraDevice.close();
  105. }
  106. @Override
  107. public void onError(CameraDevice camera, int error) {
  108. mCameraOpenCloseLock.release();
  109. cameraDevice.close();
  110. cameraDevice = null;
  111. }
  112. };
  113. @Override
  114. public int getLayoutID() {
  115. return R.layout.activity_camera;
  116. }
  117. @SuppressLint("CheckResult")
  118. @Override
  119. public void initViews(Bundle savedInstanceState) {
  120. textureView = (AutoFitTextureView) findViewById(R.id.textureView);
  121. button = (Button) findViewById(R.id.button);
  122. textureView.setSurfaceTextureListener(textureListener);
  123. button.setOnClickListener(new View.OnClickListener() {
  124. @Override
  125. public void onClick(View v) {
  126. takePicture();
  127. }
  128. });
  129. }
  130. private void openCamera(int width, int height) {
  131. CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
  132. Log.e("tag", "is camera open");
  133. try {
  134. if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
  135. throw new RuntimeException("Time out waiting to lock camera opening.");
  136. }
  137. cameraId = manager.getCameraIdList()[0];
  138. CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
  139. StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
  140. assert map != null;
  141. Size largest = Collections.max(
  142. Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
  143. new Utils.CompareSizesByArea());
  144. int displayRotation = getWindowManager().getDefaultDisplay().getRotation();
  145. //noinspection ConstantConditions
  146. mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
  147. boolean swappedDimensions = false;
  148. switch (displayRotation) {
  149. case Surface.ROTATION_0:
  150. case Surface.ROTATION_180:
  151. if (mSensorOrientation == 90 || mSensorOrientation == 270) {
  152. swappedDimensions = true;
  153. }
  154. break;
  155. case Surface.ROTATION_90:
  156. case Surface.ROTATION_270:
  157. if (mSensorOrientation == 0 || mSensorOrientation == 180) {
  158. swappedDimensions = true;
  159. }
  160. break;
  161. default:
  162. Log.e("tag", "Display rotation is invalid: " + displayRotation);
  163. }
  164. Point displaySize = new Point();
  165. getWindowManager().getDefaultDisplay().getSize(displaySize);
  166. int rotatedPreviewWidth = width;
  167. int rotatedPreviewHeight = height;
  168. int maxPreviewWidth = displaySize.x;
  169. int maxPreviewHeight = displaySize.y;
  170. if (swappedDimensions) {
  171. rotatedPreviewWidth = height;
  172. rotatedPreviewHeight = width;
  173. maxPreviewWidth = displaySize.y;
  174. maxPreviewHeight = displaySize.x;
  175. }
  176. if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
  177. maxPreviewWidth = MAX_PREVIEW_WIDTH;
  178. }
  179. if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
  180. maxPreviewHeight = MAX_PREVIEW_HEIGHT;
  181. }
  182. imageDimension = Utils.chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
  183. rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
  184. maxPreviewHeight, largest);
  185. int orientation = getResources().getConfiguration().orientation;
  186. if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
  187. textureView.setAspectRatio(
  188. imageDimension.getWidth(), imageDimension.getHeight());
  189. } else {
  190. textureView.setAspectRatio(
  191. imageDimension.getHeight(), imageDimension.getWidth());
  192. }
  193. if (null != textureView || null == imageDimension) {
  194. textureView.setTransform(Utils.configureTransform(width, height, imageDimension, CameraActivity.this));
  195. }
  196. manager.openCamera(cameraId, stateCallback, null);
  197. } catch (CameraAccessException e) {
  198. e.printStackTrace();
  199. } catch (InterruptedException e) {
  200. e.printStackTrace();
  201. }
  202. Log.e("tag", "openCamera X");
  203. }
  204. protected void createCameraPreview() {
  205. try {
  206. SurfaceTexture texture = textureView.getSurfaceTexture();
  207. assert texture != null;
  208. texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
  209. Surface surface = new Surface(texture);
  210. captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  211. captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
  212. captureRequestBuilder.addTarget(surface);
  213. cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
  214. @Override
  215. public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
  216. //The camera is already closed
  217. if (null == cameraDevice) {
  218. return;
  219. }
  220. // When the session is ready, we start displaying the preview.
  221. cameraCaptureSessions = cameraCaptureSession;
  222. updatePreview();
  223. }
  224. @Override
  225. public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
  226. Toast.makeText(CameraActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
  227. }
  228. }, null);
  229. } catch (CameraAccessException e) {
  230. e.printStackTrace();
  231. }
  232. }
  233. protected void updatePreview() {
  234. if (null == cameraDevice) {
  235. Log.e("tag", "updatePreview error, return");
  236. }
  237. captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
  238. try {
  239. cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
  240. } catch (CameraAccessException e) {
  241. e.printStackTrace();
  242. }
  243. }
  244. protected void startBackgroundThread() {
  245. mBackgroundThread = new HandlerThread("Camera Background");
  246. mBackgroundThread.start();
  247. mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
  248. }
  249. protected void stopBackgroundThread() {
  250. mBackgroundThread.quitSafely();
  251. try {
  252. mBackgroundThread.join();
  253. mBackgroundThread = null;
  254. mBackgroundHandler = null;
  255. } catch (InterruptedException e) {
  256. e.printStackTrace();
  257. }
  258. }
  259. private void closeCamera() {
  260. try {
  261. mCameraOpenCloseLock.acquire();
  262. if (null != cameraCaptureSessions) {
  263. cameraCaptureSessions.close();
  264. cameraCaptureSessions = null;
  265. }
  266. if (null != cameraDevice) {
  267. cameraDevice.close();
  268. cameraDevice = null;
  269. }
  270. if (null != imageReader) {
  271. imageReader.close();
  272. imageReader = null;
  273. }
  274. } catch (InterruptedException e) {
  275. throw new RuntimeException("Interrupted while trying to lock camera closing.");
  276. } finally {
  277. mCameraOpenCloseLock.release();
  278. }
  279. }
  280. @Override
  281. protected void onResume() {
  282. super.onResume();
  283. Log.e("tag", "onResume");
  284. startBackgroundThread();
  285. if (textureView.isAvailable()) {
  286. openCamera(textureView.getWidth(), textureView.getHeight());
  287. } else {
  288. textureView.setSurfaceTextureListener(textureListener);
  289. }
  290. }
  291. @Override
  292. protected void onPause() {
  293. Log.e("tag", "onPause");
  294. closeCamera();
  295. stopBackgroundThread();
  296. super.onPause();
  297. }
  298. protected void takePicture() {
  299. if (null == cameraDevice) {
  300. Log.e("tag", "cameraDevice is null");
  301. return;
  302. }
  303. CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
  304. try {
  305. CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
  306. Size[] jpegSizes = null;
  307. if (characteristics != null) {
  308. jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
  309. }
  310. int width = 640;
  311. int height = 480;
  312. if (jpegSizes != null && 0 < jpegSizes.length) {
  313. width = jpegSizes[0].getWidth();
  314. height = jpegSizes[0].getHeight();
  315. }
  316. ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
  317. List<Surface> outputSurfaces = new ArrayList<Surface>(2);
  318. outputSurfaces.add(reader.getSurface());
  319. outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
  320. final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
  321. captureBuilder.addTarget(reader.getSurface());
  322. captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
  323. // Orientation
  324. int rotation = getWindowManager().getDefaultDisplay().getRotation();
  325. captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
  326. reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
  327. final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
  328. @Override
  329. public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
  330. super.onCaptureCompleted(session, request, result);
  331. Toast.makeText(CameraActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
  332. createCameraPreview();
  333. }
  334. };
  335. cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
  336. @Override
  337. public void onConfigured(CameraCaptureSession session) {
  338. try {
  339. session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
  340. } catch (CameraAccessException e) {
  341. e.printStackTrace();
  342. }
  343. }
  344. @Override
  345. public void onConfigureFailed(CameraCaptureSession session) {
  346. }
  347. }, mBackgroundHandler);
  348. } catch (CameraAccessException e) {
  349. e.printStackTrace();
  350. }
  351. }
  352. ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
  353. @Override
  354. public void onImageAvailable(ImageReader reader) {
  355. Image image = null;
  356. try {
  357. image = reader.acquireLatestImage();
  358. ByteBuffer buffer = image.getPlanes()[0].getBuffer();
  359. byte[] bytes = new byte[buffer.capacity()];
  360. buffer.get(bytes);
  361. save(bytes);
  362. } catch (FileNotFoundException e) {
  363. e.printStackTrace();
  364. } catch (IOException e) {
  365. e.printStackTrace();
  366. } finally {
  367. if (image != null) {
  368. image.close();
  369. }
  370. }
  371. }
  372. private void save(byte[] bytes) throws IOException {
  373. OutputStream output = null;
  374. try {
  375. output = new FileOutputStream(file);
  376. output.write(bytes);
  377. } finally {
  378. if (null != output) {
  379. output.close();
  380. }
  381. }
  382. }
  383. };
  384. }