前言

  在开发Android应用的时候,如果需要调用摄像头获取拍摄的照片,除了通过Intent调用系统现有相机应用拍摄照片之外,还可以通过直接调用Camera硬件去去获取摄像头拍摄的照片。本篇博客将讲解如何在Android应用中通过Camera拍摄照片,这个对开发相机类应用尤为重要,同样最后也将以一个简单的Demo演示。

  本篇博客的主要内容:

  1. Camera
  2. 验证设备是否配备摄像头硬件
  3. Camera捕获画面的预览
  4. 使用Camera拍照
  5. 使用Camera拍照的Demo
  6. Camera的回调监听
  7. Camera的参数设置

Camera

  Camera是Android摄像头硬件的相机类,位于硬件包"android.hardware.Camera"下。它主要用于摄像头捕获图片、启动/停止预览图片、拍照、获取视频帧等,它是设备本地的服务,负责管理设备上的摄像头硬件。

  Camera既然用于管理设备上的摄像头硬件,那么它也为开发人员提供了相应的方法,并且这些方法大部分都是native的,用C++在底层实现,下面简单介绍一下Camera的一些方法:

  • static Camera open():打开Camera,返回一个Camera实例。
  • static Camera open(int cameraId):根据cameraId打开一个Camera,返回一个Camera实例。
  • final void release():释放掉Camera的资源。
  • static int getNumberOfCameras():获取当前设备支持的Camera硬件个数。
  • Camera.Parameters getParameters():获取Camera的各项参数设置类。
  • void setParameters(Camera.Parameters params):通过params把Camera的各项参数写入到Camera中。
  • final void setDisplayOrientation(int degrees):摄像预览的旋转度。
  • final void setPreviewDisplay(SurfaceHolder holder):设置Camera预览的SurfaceHolder。
  • final void starPreview():开始Camera的预览。
  • final void stopPreview():停止Camera的预览
  • final void autoFocus(Camera.AutoFocusCallback cb):自动对焦。
  • final takePicture(Camera.ShutterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback jpeg):拍照。
  • final void lock():锁定Camera硬件,使其他应用无法访问。
  • final void unlock():解锁Camera硬件,使其他应用可以访问。

  上面已经介绍了Camera的常用方法,下面根据这些方法详细讲解Android下使用Camera开发拍照应用最基本的过程:

  1. 使用open()方法获取一个Camera对象,鉴于Android设备可能配置了多个摄像头,open()方法可以通过摄像头Id开启指定的摄像头。
  2. 为Camera对象设置预览类,它是一个SurfaceHolder对象,通过setPreviewDisplay(SurfaceHolder)方法设置。
  3. 调用startPreview()方法开始Camera对象的预览。
  4. 调用takePicture()方法进行拍照,其中可以通过Camera.PictureCallback()回调获得拍摄的Image数据。
  5. 当拍摄完成后,需要调用stopPreview()方法停止预览,并使用release()释放Camera占用的资源。

  以上介绍的步骤都是最基本的过程,是必不可少的。Camera没有提供公开的构造函数,只能通过open()方法获取,并且必须设置一个预览类SurfaceHolder,如果不设置的话,将无法使用Camera。在使用完成Camera之后,必须使用release()释放Camera资源。

验证设备是否配备摄像头硬件

  因为Android的开源,所以其支持的设备多而杂,在使用Camera的时候,最好验证一下当前运行的设备上是否配备了摄像头硬件。这里需要用到一个PackageManager,它用于检测应用安装设备的各种信息,可以通过Context.getPackageManager()方法获取。可以通过PackageManager.hasSystemFeature(String name)方法检测设备是否支持摄像头操作,它传递的是一个String类型的参数,被PackageManager定义为了常量,返回一个Boolean数据,验证是否检测通过,对于Camera而言,可以检测如下信息:

  • FEATURE_CAMERA:设备是否有摄像头。
  • FEATURE_CAMERA_ANY:设备至少有一个摄像头。
  • FEATURE_CAMERA_AUTOFOCUS:设备支持的摄像头是否支持自动对焦
  • FEATURE_CAMERA_FLASH:设备是否配备闪光灯。
  • FEATURE_CAMERA_FRONT:设备是否有一个前置摄像头。

  一般而言,检测FEATURE_CAMERA即可:

 1     /** 检测设备是否存在Camera硬件 */
 2     private boolean checkCameraHardware(Context context) {
 3         if (context.getPackageManager().hasSystemFeature(
 4                 PackageManager.FEATURE_CAMERA)) {
 5             // 存在
 6             return true;
 7         } else {
 8             // 不存在
 9             return false;
10         }
11     }

Camera捕获画面的预览

  Camera的预览,需要放到一个SurfaceView中,出于安全的考虑,在设计Android的时候就规定,如果需要调用Camera,必须为其制定显示在屏幕上的SurfaceView预览,否则将无法使用Camera。关于SurfaceView和SurfaceHolder的内容,在之前的博客中已经详细讲解,这里不再赘述,不清楚的朋友可以看看之前的博客:Android--SurfaceView。

  下面我们直接使用一个类去继承SurfaceView当做Camera的预览类:

 1 package cn.bgxt.camerapicturedemo;
 2
 3 import java.io.IOException;
 4 import android.content.Context;
 5 import android.hardware.Camera;
 6 import android.util.Log;
 7 import android.view.SurfaceHolder;
 8 import android.view.SurfaceView;
 9
10 /**
11  * 定义一个预览类
12  */
13 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
14     private static final String TAG = "main";
15     private SurfaceHolder mHolder;
16     private Camera mCamera;
17
18     public CameraPreview(Context context, Camera camera) {
19         super(context);
20         mCamera = camera;
21
22         // 通过SurfaceView获得SurfaceHolder
23         mHolder = getHolder();
24         // 为SurfaceHolder指定回调
25         mHolder.addCallback(this);
26         // 设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到界面 在Android3.0之后弃用
27         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
28     }
29
30     public void surfaceCreated(SurfaceHolder holder) {
31         // 当Surface被创建之后,开始Camera的预览
32         try {
33             mCamera.setPreviewDisplay(holder);
34             mCamera.startPreview();
35         } catch (IOException e) {
36             Log.d(TAG, "预览失败");
37         }
38     }
39
40     public void surfaceDestroyed(SurfaceHolder holder) {
41
42     }
43
44     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
45         // Surface发生改变的时候将被调用,第一次显示到界面的时候也会被调用
46         if (mHolder.getSurface() == null){
47           // 如果Surface为空,不继续操作
48           return;
49         }
50
51         // 停止Camera的预览
52         try {
53             mCamera.stopPreview();
54         } catch (Exception e){
55             Log.d(TAG, "当Surface改变后,停止预览出错");
56         }
57
58         // 在预览前可以指定Camera的各项参数
59
60         // 重新开始预览
61         try {
62             mCamera.setPreviewDisplay(mHolder);
63             mCamera.startPreview();
64
65         } catch (Exception e){
66             Log.d(TAG, "预览Camera出错");
67         }
68     }
69 }

使用Camera拍照

  当指定了Camera的预览类,并开始预览之后,就可以通过takePicture()方法进行拍照了,下面是它的完整签名:

    public final void taskPicture(Camera.ShuffterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback postview,Camera.PictureCallback jpeg)

  它将以异步的方式从Camera中获取图像,具有多个回调类作为参数,并且都可以为null,下面分别介绍这些参数的意义:

  • shutter:在按下快门的时候回调,这里可以播放一段声音。
  • raw:从Camera获取到未经处理的图像。
  • postview:从Camera获取一个快速预览的图片,不是所有设备都支持。
  • jpeg:从Camera获取到一个经过压缩的jpeg图片。

  虽然raw、postview、jpeg都是Camera.PictureCallback回调,但是一般我们只需要获取jpeg,其他传null即可,Camera.PictureCallback里需要实现一个方法onPictureTaken(byte[] data,Camera camera),data及为图像数据。值得注意的是,一般taskPicture()方法拍照完成之后,SurfaceView都会停留在拍照的瞬间,需要重新调用startPreview()才会继续预览。

  如果直接使用taskPicture()进行拍照的话,Camera是不会进行自动对焦的,这里需要使用Camera.autoFocus()方法进行对焦,它传递一个Camera.AutoFocusCallback参数,用于自动对焦完成后回调,一般会在它对焦完成在进行taskPicture()拍照。

使用Camera拍照的Demo

   上面已经介绍了使用Camera的基本步骤以及涉及的内容,这里通过一个简单的Demo演示一下,使用上面附上代码的预览类进行Camera预览。代码中注释比较完整,这里不再赘述。

  布局代码:activity_main.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:orientation="horizontal"
 4     android:layout_width="fill_parent"
 5     android:layout_height="fill_parent"
 6     >
 7   <FrameLayout
 8     android:id="@+id/camera_preview"
 9     android:layout_width="fill_parent"
10     android:layout_height="fill_parent"
11     android:layout_weight="1"
12     />
13
14   <Button
15     android:id="@+id/button_capture"
16     android:text="拍照"
17     android:layout_width="wrap_content"
18     android:layout_height="wrap_content"
19     android:layout_gravity="center"
20     />
21 </LinearLayout>

View Code

  实现代码:MainActivity.java

  1 package cn.bgxt.camerapicturedemo;
  2
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5
  6 import android.os.Bundle;
  7 import android.util.Log;
  8 import android.view.View;
  9 import android.widget.Button;
 10 import android.widget.FrameLayout;
 11 import android.app.Activity;
 12 import android.content.Context;
 13 import android.content.pm.PackageManager;
 14 import android.hardware.Camera;
 15 import android.hardware.Camera.AutoFocusCallback;
 16 import android.hardware.Camera.PictureCallback;
 17
 18 public class MainActivity extends Activity {
 19     protected static final String TAG = "main";
 20     private Camera mCamera;
 21     private CameraPreview mPreview;
 22
 23     @Override
 24     protected void onCreate(Bundle savedInstanceState) {
 25         super.onCreate(savedInstanceState);
 26         setContentView(R.layout.activity_main);
 27
 28         mCamera = getCameraInstance();
 29
 30         // 创建预览类,并与Camera关联,最后添加到界面布局中
 31         mPreview = new CameraPreview(this, mCamera);
 32         FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
 33         preview.addView(mPreview);
 34
 35
 36         Button captureButton = (Button) findViewById(R.id.button_capture);
 37         captureButton.setOnClickListener(new View.OnClickListener() {
 38             @Override
 39             public void onClick(View v) {
 40                 // 在捕获图片前进行自动对焦
 41                 mCamera.autoFocus(new AutoFocusCallback() {
 42
 43                     @Override
 44                     public void onAutoFocus(boolean success, Camera camera) {
 45                         // 从Camera捕获图片
 46                         mCamera.takePicture(null, null, mPicture);
 47                     }
 48                 });
 49             }
 50         });
 51     }
 52
 53     /** 检测设备是否存在Camera硬件 */
 54     private boolean checkCameraHardware(Context context) {
 55         if (context.getPackageManager().hasSystemFeature(
 56                 PackageManager.FEATURE_CAMERA)) {
 57             // 存在
 58             return true;
 59         } else {
 60             // 不存在
 61             return false;
 62         }
 63     }
 64
 65     /** 打开一个Camera */
 66     public static Camera getCameraInstance() {
 67         Camera c = null;
 68         try {
 69             c = Camera.open();
 70         } catch (Exception e) {
 71             Log.d(TAG, "打开Camera失败失败");
 72         }
 73         return c;
 74     }
 75
 76     private PictureCallback mPicture = new PictureCallback() {
 77
 78         @Override
 79         public void onPictureTaken(byte[] data, Camera camera) {
 80             // 获取Jpeg图片,并保存在sd卡上
 81             File pictureFile = new File("/sdcard/" + System.currentTimeMillis()
 82                     + ".jpg");
 83             try {
 84                 FileOutputStream fos = new FileOutputStream(pictureFile);
 85                 fos.write(data);
 86                 fos.close();
 87             } catch (Exception e) {
 88                 Log.d(TAG, "保存图片失败");
 89             }
 90         }
 91     };
 92
 93     @Override
 94     protected void onDestroy() {
 95         // 回收Camera资源
 96         if(mCamera!=null){
 97             mCamera.stopPreview();
 98             mCamera.release();
 99             mCamera=null;
100         }
101         super.onDestroy();
102     }
103
104 }

  效果展示:

Camera的回调监听

  上面介绍Camera拍照的时候介绍了两个回调,Camera还提供了一些其他的回调的事件监听方法,这里简单介绍几个常用的:

  • final void setErrorCallback(Camera.ErrorCallback cb):Camera发送错误的时候回调,可以在其中进行错误的后续处理。
  • final void setPreviedCallback(Camera.PreviewCallback cb):Camera预览界面发生变化的时候回调,可以在其中获取到Camera捕获到的帧图像。

Camera的参数设置

  Camera作为一个摄像头硬件的调用类,还为我们提供了详细的设置摄像头各项参数的方法,比如闪光灯的模式、自动对焦的模式等。步骤是使用Camera.getParameters()方法获取到Camera.Parameters对象,在其中设置好摄像头的各项参数后,再通过Camera.setParameters()方法写入到Camera对象中即可。这个设置必须在使用startPreview()之前完成。关于Camera参数的设置,比较细致,不在本篇博客的内容之中,以后有机会再详细介绍。

  源码下载

  

  

转载于:https://www.cnblogs.com/plokmju/p/android_Camera.html

Android--使用Camera拍照相关推荐

  1. Android之Camera拍照

    一.看看调用时序图 1.拍照命令时序图 2.拍照数据回调时序图 二.看看源码分析 hardware/amlogic/camera/CameraHal.cpp [cpp] view plaincopy ...

  2. android 系统拍照 方向,Android 系统Camera拍照照片旋转

    读取图片旋转的角度,然后根据角度把图片旋转过来. /** * 读取图片属性:旋转的角度 * @param path 图片绝对路径 * @return degree旋转的角度 */ public sta ...

  3. Android 自定义Camera(一)如何预览相机

    Android Camera之如何预览相机 1.官方Api描述 翻译后为: 使用android.hardware.Camera拍照,请使用以下步骤: 1.从open(int)获取一个Camera实例. ...

  4. android Camera 拍照的两个问题

    2010.11.16---android Camera 拍照的两个问题 1.setParameters failed 异常信息如下 Java代码   11-16 11:21:33.902: WARN/ ...

  5. Android开发技巧——Camera拍照功能

    本篇是我对开发项目的拍照功能过程中,对Camera拍照使用的总结.由于camera2是在api level 21(5.0.1)才引入的,而Camera到6.0仍可使用,所以暂未考虑camera2. 文 ...

  6. Android Studio:使用Camera拍照(三)为相机增加取景蒙板/浮层

    写在前面的话:每一个实例的代码都会附上相应的代码片或者图片,保证代码完整展示在博客中.最重要的是保证例程的完整性!!!方便自己也方便他人~欢迎大家交流讨论~本文为博主原创文章,未经博主允许不得转载. ...

  7. Android最新相机(Camera)拍照、拍视频全面总结

    介绍 利用系统相机 调用系统相机拍照 获取小图标 获取全尺寸图片 添加到相册 系统相机拍视频 自定义相机 自定义相机拍照 监测设备是否有相机可使用 利用SurfaceView创建拍照时预览界面 拍照并 ...

  8. android系统如何在静音模式下关闭camera拍照声音(2)

    之前写过一篇"android系统如何在静音模式下关闭camera拍照声音"的博客,今天来写他的续篇,继续探讨这个问题. 公司新需求,要求在camera应用中添加一个开关,可以进行拍 ...

  9. android 后台服务拍照,Android实现后台开启服务默默拍照功能

    本文实例为大家分享了Android后台开启服务默默拍照的具体代码,供大家参考,具体内容如下 最近项目原因,需要编写一后台运行的程序,在给定时间间隔下进行拍照,关键技术主要是:1.开启服务:2.在不不预 ...

  10. Android 使用摄像头拍照

    2019独角兽企业重金招聘Python工程师标准>>> <!-- lang: xml --> 拍照必须设置权限: <uses-permission android: ...

最新文章

  1. Nginx反向代理负载均衡
  2. slidingmenu 中view使用练习
  3. java的同步块_Java 同步块
  4. 优酷在多模态内容理解上的研究及应用
  5. 获取打开文件的路径和文件名
  6. V210 系统时间设置
  7. java实验册_Java实验报告册Java实验报告册.doc
  8. java float 高效加减_java Double 进行加减乘除
  9. delphi 中 的 Split 函数
  10. iplat62--按钮使用规范
  11. SQL实战之查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
  12. 简易实现 TextView单行文本水平触摸滑动效果
  13. 计算机运算法则图鉴,AP微积分BC TI-Nspire计算器使用指南 正确使用计算器5分到手轻而易举...
  14. 精选了20个Python实战项目(附源码)
  15. 微信小程序签到考勤系统
  16. 平时收集的一些有关UED的团队和个人博客
  17. CCF-分蛋糕-Java
  18. IDEA模块名后面中括号中内容与模块名不一致的问题
  19. Docker - compose 邂逅
  20. HTML页面静态化技术

热门文章

  1. anaconda Pycharm jupyter环境配置教程(最后一次写了!!!)
  2. 从数学基础到贝叶斯理论到实践——深度AI科普团队
  3. Python数据分析模块 | pandas做数据分析(三):统计相关函数
  4. find python列表_Python基础知识(7)list列表各种操作
  5. matlab 正则化表达式_MATLAB 正则表达式(一)(转)
  6. python 网页版笔记_系统学习下python网络爬虫 笔记一
  7. php期末作业经验,期末作业.php
  8. java 信号量 互斥锁_线程同步(互斥锁与信号量的作用与区别)
  9. BootstrapTable 列隐藏
  10. 小汤学编程之JAVA基础day04——流程结构