Android 实现无预览拍照功能

矫情吗;* 2024-03-23 20:46 226阅读 0赞

Android 实现无预览拍照功能

1.权限

需要相机、读写文件、悬浮窗权限

申请相机、读写文件

manifest.xml

  1. <uses-permission android:name="android.permission.CAMERA" />
  2. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  3. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

相机、读写文件权限需要动态申请

  1. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA,
  2. Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
悬浮窗权限
  1. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  2. <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />

需要申请

  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  2. if (!Settings.canDrawOverlays(this)) {
  3. startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);
  4. } else {
  5. //TODO do something you need
  6. }
  7. }

2.布局与使用

布局
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".test1.Main2Activity">
  8. <Button
  9. android:id="@+id/button"
  10. android:layout_width="match_parent"
  11. android:layout_height="wrap_content"
  12. android:text="拍照"
  13. app:layout_constraintTop_toTopOf="parent" />
  14. </androidx.constraintlayout.widget.ConstraintLayout>
使用

主要参数

  1. Camera camera;
  2. WindowManager wm;
  3. SurfaceView preview;
  4. String path = Environment.getExternalStorageDirectory().getAbsolutePath();
  5. File fileTest = new File(path + "/test.jpg");

然后调用

  1. public void onTakePhotoClicked() {
  2. preview = new SurfaceView(this);
  3. SurfaceHolder holder = preview.getHolder();
  4. // deprecated setting, but required on Android versions prior to 3.0
  5. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  6. holder.addCallback(new SurfaceHolder.Callback() {
  7. @Override
  8. //The preview must happen at or after this point or takePicture fails
  9. public void surfaceCreated(SurfaceHolder holder) {
  10. Log.d("zcf", "Surface created");
  11. camera = null;
  12. try {
  13. camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
  14. Log.d("zcf", "Opened camera");
  15. try {
  16. camera.setPreviewDisplay(holder);
  17. } catch (IOException e) {
  18. throw new RuntimeException(e);
  19. }
  20. camera.startPreview();
  21. Log.d("zcf", "Started preview");
  22. Log.e("zcf","开始拍照");
  23. camera.takePicture(null, null, TestActivity.this);
  24. } catch (Exception e) {
  25. if (camera != null)
  26. camera.release();
  27. throw new RuntimeException(e);
  28. }
  29. }
  30. @Override
  31. public void surfaceDestroyed(SurfaceHolder holder) {}
  32. @Override
  33. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
  34. });
  35. wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
  36. WindowManager.LayoutParams params = null;
  37. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
  38. params = new WindowManager.LayoutParams(
  39. 1, 1, //Must be at least 1x1
  40. WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
  41. 0,
  42. //Don't know if this is a safe default
  43. PixelFormat.UNKNOWN);
  44. }
  45. //Don't set the preview visibility to GONE or INVISIBLE
  46. wm.addView(preview, params);
  47. }
  48. @Override
  49. public void onPictureTaken(byte[] bytes, Camera camera) {
  50. Log.e("zcf", "拍照结束");
  51. try {
  52. FileOutputStream fos = new FileOutputStream(fileAdvert);
  53. fos.write(bytes);
  54. fos.close();
  55. Log.e("zcf","保存结束");
  56. Message message = handler.obtainMessage();
  57. message.what = 1;
  58. handler.sendEmptyMessageDelayed(1,1500);
  59. } catch (FileNotFoundException e) {
  60. Log.d("zcf", "File not found: " + e.getMessage());
  61. } catch (IOException e) {
  62. Log.d("zcf", "Error accessing file: " + e.getMessage());
  63. }
  64. }

拍照结束需要把wm给remove掉,要不还是会挡着下边的东西。

3.完整代码

  1. import android.Manifest;
  2. import android.annotation.SuppressLint;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.graphics.Bitmap;
  6. import android.graphics.BitmapFactory;
  7. import android.graphics.Matrix;
  8. import android.graphics.PixelFormat;
  9. import android.hardware.Camera;
  10. import android.os.Build;
  11. import android.os.Bundle;
  12. import android.os.Environment;
  13. import android.os.Handler;
  14. import android.os.Message;
  15. import android.provider.Settings;
  16. import android.util.Log;
  17. import android.view.OrientationEventListener;
  18. import android.view.SurfaceHolder;
  19. import android.view.SurfaceView;
  20. import android.view.View;
  21. import android.view.WindowManager;
  22. import android.widget.Button;
  23. import androidx.annotation.NonNull;
  24. import androidx.core.app.ActivityCompat;
  25. import com.arcsoft.face.FaceEngine;
  26. import com.arcsoft.face.FaceFeature;
  27. import com.arcsoft.face.FaceInfo;
  28. import com.arcsoft.face.enums.DetectMode;
  29. import com.arcsoft.face.enums.DetectModel;
  30. import com.zg.massagerobot.R;
  31. import com.zg.massagerobot.base.BaseActivity;
  32. import com.zg.massagerobot.faceserver.CompareResult;
  33. import com.zg.massagerobot.faceserver.FaceServer;
  34. import com.zg.massagerobot.utils.ConfigUtil;
  35. import java.io.File;
  36. import java.io.FileInputStream;
  37. import java.io.FileNotFoundException;
  38. import java.io.FileOutputStream;
  39. import java.io.IOException;
  40. import java.util.ArrayList;
  41. import java.util.List;
  42. import java.util.concurrent.ExecutorService;
  43. import java.util.concurrent.Executors;
  44. import io.reactivex.Observable;
  45. import io.reactivex.ObservableEmitter;
  46. import io.reactivex.ObservableOnSubscribe;
  47. import io.reactivex.Observer;
  48. import io.reactivex.android.schedulers.AndroidSchedulers;
  49. import io.reactivex.disposables.Disposable;
  50. import io.reactivex.schedulers.Schedulers;
  51. public class Main2Activity extends BaseActivity implements Camera.PictureCallback {
  52. Button button;
  53. Camera camera;
  54. WindowManager wm;
  55. SurfaceView preview;
  56. String path = Environment.getExternalStorageDirectory().getAbsolutePath();
  57. File fileTest = new File(path + "/test.jpg");
  58. @Override
  59. protected void onCreate(Bundle savedInstanceState) {
  60. super.onCreate(savedInstanceState);
  61. setContentView(R.layout.activity_main2);
  62. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA,
  63. Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
  64. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  65. if (!Settings.canDrawOverlays(this)) {
  66. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
  67. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  68. startActivityForResult(intent, 1);
  69. } else {
  70. //TODO do something you need
  71. }
  72. }
  73. FaceServer.getInstance().init(this);
  74. initOrientate();
  75. button = findViewById(R.id.button);
  76. button.setOnClickListener(new View.OnClickListener() {
  77. @Override
  78. public void onClick(View v) {
  79. onTakePhotoClicked();
  80. }
  81. });
  82. }
  83. @SuppressLint("HandlerLeak")
  84. private Handler handler = new Handler() {
  85. @Override
  86. public void handleMessage(@NonNull Message msg) {
  87. super.handleMessage(msg);
  88. switch (msg.what) {
  89. case 1:
  90. wm.removeViewImmediate(preview);
  91. break;
  92. }
  93. }
  94. };
  95. public void onTakePhotoClicked() {
  96. preview = new SurfaceView(this);
  97. SurfaceHolder holder = preview.getHolder();
  98. // deprecated setting, but required on Android versions prior to 3.0
  99. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  100. holder.addCallback(new SurfaceHolder.Callback() {
  101. @Override
  102. //The preview must happen at or after this point or takePicture fails
  103. public void surfaceCreated(SurfaceHolder holder) {
  104. Log.d("zcf", "Surface created");
  105. camera = null;
  106. try {
  107. camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
  108. Log.d("zcf", "Opened camera");
  109. try {
  110. camera.setPreviewDisplay(holder);
  111. } catch (IOException e) {
  112. throw new RuntimeException(e);
  113. }
  114. camera.startPreview();
  115. Log.d("zcf", "Started preview");
  116. Log.e("zcf", "开始拍照");
  117. camera.takePicture(null, null, Main2Activity.this);
  118. } catch (Exception e) {
  119. if (camera != null)
  120. camera.release();
  121. throw new RuntimeException(e);
  122. }
  123. }
  124. @Override
  125. public void surfaceDestroyed(SurfaceHolder holder) {
  126. }
  127. @Override
  128. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  129. }
  130. });
  131. wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
  132. WindowManager.LayoutParams params = null;
  133. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
  134. params = new WindowManager.LayoutParams(
  135. 1, 1, //Must be at least 1x1
  136. WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
  137. 0,
  138. //Don't know if this is a safe default
  139. PixelFormat.UNKNOWN);
  140. }
  141. //Don't set the preview visibility to GONE or INVISIBLE
  142. wm.addView(preview, params);
  143. }
  144. @Override
  145. public void onPictureTaken(byte[] bytes, Camera camera) {
  146. /*Log.e("zcf", "拍照结束");
  147. try {
  148. //图片需要向右旋转90度,然后提取特征比较
  149. FileOutputStream fos = new FileOutputStream(fileTest);
  150. fos.write(bytes);
  151. fos.close();
  152. Log.e("zcf", "保存结束");
  153. Message message = handler.obtainMessage();
  154. message.what = 1;
  155. handler.sendEmptyMessageDelayed(1, 1500);
  156. } catch (FileNotFoundException e) {
  157. Log.d("zcf", "File not found: " + e.getMessage());
  158. } catch (IOException e) {
  159. Log.d("zcf", "Error accessing file: " + e.getMessage());
  160. }*/
  161. Log.e("zcf", "拍照结束");
  162. //图片需要向右旋转90度,然后提取特征比较
  163. getPhotoPath(bytes, takePhotoOrientation);
  164. }
  165. @Override
  166. protected void onDestroy() {
  167. super.onDestroy();
  168. }
  169. private ExecutorService threadPool = Executors.newCachedThreadPool();
  170. /**
  171. * @return 返回路径
  172. */
  173. private void getPhotoPath(final byte[] data, final int takePhotoOrientation) {
  174. threadPool.execute(new Runnable() {
  175. @Override
  176. public void run() {
  177. try {
  178. FileOutputStream fos = new FileOutputStream(fileTest);
  179. try {
  180. //将数据写入文件
  181. fos.write(data);
  182. } catch (IOException e) {
  183. e.printStackTrace();
  184. } finally {
  185. try {
  186. fos.close();
  187. } catch (IOException e) {
  188. e.printStackTrace();
  189. }
  190. }
  191. //将图片旋转
  192. rotateImageView(Camera.CameraInfo.CAMERA_FACING_FRONT, takePhotoOrientation, fileTest.getAbsolutePath());
  193. } catch (FileNotFoundException e) {
  194. e.printStackTrace();
  195. }
  196. Log.e("zcf", "保存结束");
  197. Message message = handler.obtainMessage();
  198. message.what = 1;
  199. handler.sendEmptyMessageDelayed(1, 1500);
  200. }
  201. });
  202. }
  203. /**
  204. * 旋转图片
  205. *
  206. * @param cameraId 前置还是后置
  207. * @param orientation 拍照时传感器方向
  208. * @param path 图片路径
  209. */
  210. private void rotateImageView(int cameraId, int orientation, String path) {
  211. Bitmap bitmap = BitmapFactory.decodeFile(path);
  212. Matrix matrix = new Matrix();
  213. matrix.postRotate(Float.valueOf(orientation));
  214. // 创建新的图片
  215. Bitmap resizedBitmap;
  216. if (cameraId == 1) {
  217. if (orientation == 90) {
  218. matrix.postRotate(180f);
  219. }
  220. }
  221. // 创建新的图片
  222. resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
  223. bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  224. //新增 如果是前置 需要镜面翻转处理
  225. if (cameraId == 1) {
  226. Matrix matrix1 = new Matrix();
  227. matrix1.postScale(-1f, 1f);
  228. resizedBitmap = Bitmap.createBitmap(resizedBitmap, 0, 0,
  229. resizedBitmap.getWidth(), resizedBitmap.getHeight(), matrix1, true);
  230. }
  231. File file = new File(path);
  232. //重新写入文件
  233. try {
  234. // 写入文件
  235. FileOutputStream fos;
  236. fos = new FileOutputStream(file);
  237. //默认jpg
  238. resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
  239. fos.flush();
  240. fos.close();
  241. resizedBitmap.recycle();
  242. } catch (Exception e) {
  243. e.printStackTrace();
  244. return;
  245. }
  246. }
  247. //增加传感器
  248. private OrientationEventListener mOrientationEventListener;
  249. //当前角度
  250. private float mCurrentOrientation = 0f;
  251. //拍照时的传感器方向
  252. private int takePhotoOrientation = 0;
  253. /**
  254. * 初始化传感器方向
  255. */
  256. private void initOrientate() {
  257. if (mOrientationEventListener == null) {
  258. mOrientationEventListener = new OrientationEventListener(this) {
  259. @Override
  260. public void onOrientationChanged(int orientation) {
  261. // i的范围是0-359
  262. // 屏幕左边在顶部的时候 i = 90;
  263. // 屏幕顶部在底部的时候 i = 180;
  264. // 屏幕右边在底部的时候 i = 270;
  265. // 正常的情况默认i = 0;
  266. if (45 <= orientation && orientation < 135) {
  267. takePhotoOrientation = 180;
  268. mCurrentOrientation = -180;
  269. } else if (135 <= orientation && orientation < 225) {
  270. takePhotoOrientation = 270;
  271. mCurrentOrientation = 90;
  272. } else if (225 <= orientation && orientation < 315) {
  273. takePhotoOrientation = 0;
  274. mCurrentOrientation = 0;
  275. } else {
  276. takePhotoOrientation = 90;
  277. mCurrentOrientation = -90;
  278. }
  279. }
  280. };
  281. }
  282. mOrientationEventListener.enable();
  283. }
  284. }

发表评论

表情:
评论列表 (有 0 条评论,226人围观)

还没有评论,来说两句吧...

相关阅读