相机Camera

Camera是直接操作摄像头硬件的工具类。常用的方法如下:

getNumberOfCameras : 获取本机的摄像头数目
open : 打开摄像头,默认打开后置摄像头。如果有多个摄像头,那么open(0)表示打开后置摄像头,open(1)表示打开前置摄像头。
以上两个方法是静态方法。

getParameters : 获取摄像头的拍照参数。
setParameters : 设置摄像头的拍照参数。
--setPreviewSize : 设置预览界面的尺寸。
--setPictureSize : 设置保存图片的尺寸。
--setPictureFormat : 设置图片格式。一般使用ImageFormat.JPEG表示jpg格式,
--setFocusMode : 设置对焦模式。一般使用FOCUS_MODE_AUTO表示自动对焦。
以上是Camera.Parameters的参数设置方法。

setPreviewDisplay : 设置预览界面,参数为SurfaceHolder类型。
startPreview : 开始预览。该方法在setPreviewDisplay之后调用。
stopPreview : 停止预览
unlock : 录像时需要对摄像头解锁,这样摄像头才能持续录像。该方法在startPreview之后调用。
lock : 录像完毕对摄像头加锁。该方法在stopPreview之后调用。
setDisplayOrientation : 设置预览的角度。因为Android的0角度都在三点钟位置,而手机画面都是六点钟的垂直位置,所以从三点钟到六点钟需要旋转90度。
autoFocus : 设置对焦事件,参数为AutoFocusCallback类型。比如说在对焦成功时显示一个图片提示用户可以拍照了。
takePicture : 拍照。第一个参数ShutterCallback用来控制按下快门时的事件,我们可在此播放拍照声音,默认就是咔嚓一声;后面的几个回调接口PictureCallback分别对应原始图像、缩放和压缩图像和JPG图像,图像数据可以在接口中的onPictureTaken方法中获得,通常我们只关心最后一个的JPG图像数据,所以前面的接口参数可以直接传null。
release : 释放摄像头。每次退出拍照都要释放,因为摄像头不能重复打开,要么就是把Camera对象做成单例模式。

预览视图SurfaceView/预览持有者SurfaceHolder

SurfaceView是Android中的一种特殊视图,它拥有独立的绘图表面,即它不与其宿主页面共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的界面就可以在一个独立的线程中进行绘制,我们称之为渲染线程。因为它不占用主线程资源,所以一方面可以实现复杂而高效的UI,另一方面也会及时响应用户输入。鉴于SurfaceView具备如上特性,故而它可用于拍照以及录像的预览界面,也可用于游戏的画面。

不过SurfaceView自身主要完成绘图功能,其他功能设置以及事件处理还有待于SurfaceHolder来操作。SurfaceView的getHolder方法把二者关联了起来,可获取预览界面当前干活的操纵者。SurfaceHolder应与SurfaceView配合使用,下面是SurfaceHolder的常用方法:
addCallback : 添加回调接口
removeCallback : 移除回调接口
isCreating : 判断预览界面是否有效
setFormat : 设置预览格式。PixelFormat.TRANSPARENT表示透明,PixelFormat.TRANSLUCENT表示半透明,PixelFormat.OPAQUE表示不透明。
setFixedSize : 设置预览界面的尺寸
setSizeFromLayout : 设置预览界面的尺寸为布局文件中的配置
getSurfaceFrame : 获取预览界面的尺寸
getSurface : 获取预览视图的对象。主要用于播放视频。

拍照的相关事件

下面是几个拍照用到的回调事件接口:

预览变化事件 
监听器类名 : SurfaceHolder.Callback
设置监听器的方法 : 
Camera.setPreviewDisplay : 添加预览持有者SurfaceHolder。该方法用于关联Camera和SurfaceHolder
SurfaceHolder.addCallback : 添加回调接口Callback。该方法用于关联SurfaceView和SurfaceHolder,它与Camera.setPreviewDisplay最终联合完成SurfaceView与Camera的关联,即摄像头的画面展示在预览界面上。
SurfaceHolder.removeCallback : 移除回调接口Callback
监听器需要重写的方法 : 
surfaceCreated : 预览创建。不管是拍照还是录像,通常在该方法中设置拍照预览Camera.setPreviewDisplay。
surfaceChanged : 预览变化
surfaceDestroyed : 预览结束。注意SurfaceView的渲染线程只在surfaceCreated和surfaceDestroyed之间有效,所以如果在别处操作SurfaceView画面,得判断当前预览界面是否有效,也就是调用SurfaceHolder.isCreating方法来判断。

自动对焦事件 
监听器类名 : Camera.AutoFocusCallback
设置监听器的方法 : Camera.autoFocus
监听器需要重写的方法 : onAutoFocus

快门按下事件 
监听器类名 : Camera.ShutterCallback
设置监听器的方法 : Camera.takePicture
监听器需要重写的方法 : onShutter

拍照事件 
监听器类名 : Camera.PictureCallback
设置监听器的方法 : Camera.takePicture
监听器需要重写的方法 : onPictureTaken

变焦事件 
监听器类名 : Camera.OnZoomChangeListener
设置监听器的方法 : Camera.setZoomChangeListener
监听器需要重写的方法 : onZoomChange

扫描二维码

这个功能最有名的应用就是微信里的“扫一扫”了,通过摄像头拍照从二维码中获取相关信息,然后再进行相应操作(比如说添加好友、下载文件、访问页面等等)。Android中的二维码扫描可用Google的zxing开源库,再结合zxing的使用框架MipcaActivityCapture。
下面是zxing+MipcaActivityCapture框架的代码集成例子:
1、给工程加入zxing3.2.1.jar;
2、把MipcaActivityCapture源码(com.app.zxing)加入到工程;
3、编写MipcaActivityCapture的布局文件activity_capture.xml,主要是加入SurfaceView和com.app.zxing.view.ViewfinderView两个视图,前一个视图是预览界面,后一个是扫码界面;
4、如果需要调整扫描界面的UI,则修改ViewfinderView的onDraw方法,可加入新的元素或者调整尺寸。
5、对扫码结果的处理见MipcaActivityCapture的handleDecode方法,视情况做相应处理,如添加好友、下载文件、访问页面等等。

代码示例

下面是相机视图CameraView的代码示例:

import com.example.exmcamera.util.BitmapUtil;
import com.example.exmcamera.util.MetricsUtil;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class CameraView extends SurfaceView implements SurfaceHolder.Callback {private static final String TAG = "CameraView";private Context mContext;private Camera mCamera;private Bitmap mBitmap = null;private SurfaceHolder mHolder = null;private boolean isPreviewing = false;private Point mCameraSize;private int mCameraType = CAMERA_BEHIND;public static int CAMERA_BEHIND = 0;public static int CAMERA_FRONT = 1;public CameraView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;mHolder = getHolder();mHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明//mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);mHolder.addCallback(this);}public CameraView(Context context) {this(context, null);}public int getCameraType() {return mCameraType;}public void setCameraType(int CameraType) {mCameraType = CameraType;}public Bitmap getPhoto() {if (mBitmap != null) {Log.d(TAG, "mBitmap.size="+(mBitmap.getByteCount()/1024)+"K");} else {Log.d(TAG, "mBitmap is null.");}return mBitmap;}public void doTakePicture() {if(isPreviewing && (mCamera != null)) {mCamera.takePicture(mShutterCallback, null, mPictureCallback);}}//快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。ShutterCallback mShutterCallback = new ShutterCallback() {public void onShutter() {Log.d(TAG, "myShutterCallback:onShutter...");}};PictureCallback mPictureCallback = new PictureCallback() {public void onPictureTaken(byte[] data, Camera camera) {Log.d(TAG, "mPictureCallback:onPictureTaken...");Bitmap b = null;if(null != data) {b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图mCamera.stopPreview();isPreviewing = false;}if (mCameraType == CameraView.CAMERA_BEHIND) {mBitmap = BitmapUtil.getRotateBitmap(b, 90);} else {mBitmap = BitmapUtil.getRotateBitmap(b, -90);}Log.d(TAG, "mBitmap.size="+(mBitmap.getByteCount()/1024)+"K");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//再次进入预览mCamera.startPreview();isPreviewing = true;}};@Overridepublic void surfaceCreated(SurfaceHolder mHolder) {// 当预览视图创建的时候开启相机mCamera = Camera.open(mCameraType);try {// 设置预览mCamera.setPreviewDisplay(mHolder);mCameraSize = MetricsUtil.getCameraSize(mCamera.getParameters(), MetricsUtil.getSize(mContext));Log.d(TAG, "width="+mCameraSize.x+", height="+mCameraSize.y);Camera.Parameters parameters = mCamera.getParameters();// 设置预览大小parameters.setPreviewSize(mCameraSize.x, mCameraSize.y);// 设置图片保存时的分辨率大小parameters.setPictureSize(mCameraSize.x, mCameraSize.y);// 设置格式parameters.setPictureFormat(ImageFormat.JPEG);// 设置自动对焦。前置摄像头似乎无法自动对焦if (mCameraType == CameraView.CAMERA_BEHIND) {parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);}mCamera.setParameters(parameters);} catch (Exception e) {Log.d(TAG, "setPreviewDisplay error: "+e.getMessage());// 释放相机资源并置空mCamera.release();mCamera = null;}return;}@Overridepublic void surfaceChanged(SurfaceHolder mHolder, int format, int width, int height) {Log.d(TAG, "surfaceChanged");mCamera.setDisplayOrientation(90);// 开始预览mCamera.startPreview();isPreviewing = true;mCamera.autoFocus(null);}@Overridepublic void surfaceDestroyed(SurfaceHolder mHolder) {Log.d(TAG, "surfaceDestroyed");mCamera.stopPreview();mCamera.release();mCamera = null;}}

下面是拍照页面CameraActivity的代码示例:

import java.text.SimpleDateFormat;
import java.util.Date;import com.example.exmcamera.R;
import com.example.exmcamera.util.BitmapUtil;
import com.example.exmcamera.util.MetricsUtil;
import com.example.exmcamera.widget.CameraView;import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageButton;public class CameraActivity extends Activity implements OnClickListener {private static final String TAG = "CameraActivity";private CameraView cameraView;private ImageButton shutterBtn;private int mCameraType;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.item_camera);mCameraType = getIntent().getIntExtra("type", CameraView.CAMERA_BEHIND);cameraView = (CameraView)findViewById(R.id.camera_view);cameraView.setCameraType(mCameraType);shutterBtn = (ImageButton)findViewById(R.id.btn_shutter);shutterBtn.setOnClickListener(this);initViewParams();}private void initViewParams(){LayoutParams paramsLayout = cameraView.getLayoutParams();Point size = MetricsUtil.getSize(this);paramsLayout.width = size.x;paramsLayout.height = size.y;cameraView.setLayoutParams(paramsLayout);LayoutParams paramsButton = shutterBtn.getLayoutParams();paramsButton.width = MetricsUtil.dip2px(this, 60);paramsButton.height = MetricsUtil.dip2px(this, 60);shutterBtn.setLayoutParams(paramsButton);}@Overridepublic void onBackPressed() {Intent intent = new Intent();Bundle bundle = new Bundle();Bitmap bitmap = cameraView.getPhoto();if (bitmap == null) {bundle.putString("is_null", "yes");} else {bundle.putString("is_null", "no");String path = String.format("%s%s.jpg", BitmapUtil.getCachePath(this),getNowDateTime());BitmapUtil.saveFile(cameraView.getPhoto(), path);bundle.putString("path", path);}intent.putExtras(bundle);setResult(Activity.RESULT_OK, intent);finish();}private String getNowDateTime() {SimpleDateFormat s_format = new SimpleDateFormat("yyyyMMddHHmmss");Date d_date = new Date();String s_date = "";s_date = s_format.format(d_date);return s_date;}@Overridepublic void onClick(View v) {if (v.getId() == R.id.btn_shutter) {cameraView.doTakePicture();}}}

点击下载本文用到的摄像头拍照与扫一扫的工程代码

点此查看Android开发笔记的完整目录

Android开发笔记(五十六)摄像头拍照相关推荐

  1. Android开发笔记(十六)秋千摇摆动画SwingAnimation

    上节博主介绍了AlphaAnimation和淡入淡出动画的使用,其实AlphaAnimation只是四种补间动画中的一种.那么为了加深对其他补间动画的理解,我想说说旋转动画RotateAnimatio ...

  2. Android开发笔记(一百六十五)利用红外发射遥控电器

    红外遥控是一种无线控制技术,它具有功耗小.成本低.易实现等诸多优点,因而被各种电子设备特别是家用电器广泛采用,像日常生活中的电视遥控器.空调遥控器等等基本都采用红外遥控技术. 不过遥控器并不都是红外遥 ...

  3. Android开发笔记(一百六十六)H5通过WebView录像上传

    前面的博文< Android开发笔记(一百五十二)H5通过WebView上传图片>介绍了如何拍照上传给网页,不料客户又要求再加个摄像上传给网页.既然如此,那么再探讨一下如何实现这个摄像上传 ...

  4. Android开发笔记(一百六十)休眠模式下的定时器控制

    定时器AlarmManager常常用于需要周期性处理的场合,比如闹钟提醒.任务轮询等等.并且定时器来源于系统服务,即使App已经不在运行了,也能收到定时器发出的广播而被唤醒.似此回光返照的神技,便遭到 ...

  5. Android开发笔记(一百六十九)利用BottomNavigationView实现底部标签栏

    在Android Studio上创建官方默认的首屏标签页面很方便,首先右击需要添加标签栏的模块,在弹出的右键菜单中依次选择"New"--"Activity"-- ...

  6. Android开发笔记(一百六十八)为应用绑定通知渠道并展示消息角标

    为了分清消息通知的轻重缓急,从Android8开始新增了通知渠道,并且必须指定通知渠道才能正常推送消息.一个应用允许拥有多个通知渠道,每个渠道的重要性各不相同,有的渠道消息在通知栏被折叠成小行,有的渠 ...

  7. Android开发笔记(一百六十四)仿京东首页的下拉刷新

    上一篇文章介绍了高仿京东的沉浸式状态栏,可是跟京东首页的头部轮播图相比,依然有三处缺憾: 1.京东的头部Banner上方,除了有悬浮着的状态栏,状态栏下面还有一行悬浮工具栏,内嵌扫一扫图标.搜索框,以 ...

  8. Android开发笔记(十五)淡入淡出动画TransitionDrawable

    说到淡入淡出动画,可能大家会想到补间动画里面的AlphaAnimation,不过这个深浅动画只能对透明度做渐变效果,也就是只能对一个图形做深浅的颜色变换.如果我们想要从A图片逐渐变为B图片,也就是要实 ...

  9. Android开发笔记(一百六十二)蓝牙设备的连接与配对

    蓝牙是一种短距离无线通信技术,它由爱立信公司于1994年创制,原本想替代连接电信设备的数据线,但是后来发现它也能用于移动设备之间的数据传输,所以蓝牙技术在手机上获得了长足发展. 因为手机内部的通讯芯片 ...

  10. Android开发笔记(一百六十七)Android8.0的画中画模式

    前面的博文< Android开发笔记(一百五十九)Android7.0的分屏模式>介绍了Android7.0的多窗口特性,但是这个分屏的区域是固定的,要么在屏幕的上半部分,要么在屏幕的下半 ...

最新文章

  1. java 解压与压缩代码_Java实现多文件压缩和解压缩代码详解
  2. 第29月第21天 ios android curl
  3. Leetcode题目:Rectangle Area
  4. 世界围棋人机大战、顶峰对决第一盘:围棋世界冠军Lee Sedol(李世石,围棋职业九段)对战Google DeepMind AlphaGo围棋程序,Google AlphaGo首战告捷
  5. 雅虎对提升网站性能的最佳实践(英文)
  6. Java单例模式实现方式
  7. cfar(Constant False-Alarm Rate)
  8. 安卓上的测试软件有哪些,手机硬件检测软件有哪些
  9. 苹果CMS v10模板:大橙子vfed完美版视频网站模板
  10. 录入人员照片注意事项无身份证人员录入
  11. 技术支持----用户和产研沟通的桥梁
  12. 计算机网络层次结构概要
  13. 美团新用户0.99充10元话费,秒到账,不实名不绑卡,超简单!
  14. prometheus监控mysql慢查询_使用Grafana+Prometheus监控mysql服务性能
  15. mybatis 中 if-test 判断详解
  16. windows安装IIS服务
  17. VirusTotal
  18. 罗辑思维八里庄沙龙:Cloud Native 的演进(—)--从零开始了解云原生架构
  19. HTML、HTML5、XHTML、XML、XSL、DTD、XML Schema 简单介绍
  20. Unity学习之常用事件函数Update深度解析

热门文章

  1. Leetcode每日一题:164.maximum-gap(最大间距)
  2. Redis基础(十三)——Jedis和Linux
  3. Java操作Json工具——Jackson
  4. 2018年上半年读者最喜爱的异步新书TOP50
  5. Android NDK开发:打包so库及jar包供他人使用
  6. python文本分类算法_python编写朴素贝叶斯用于文本分类
  7. big sur darwin6.iso下载_苹果macOS Big Sur 11.0 正式版系统适配机型 附升级教程和系统镜像下载...
  8. cnn 示意图_Two-Stream CNN(双流CNN)介绍(NIPS2014)
  9. 解决SQLServer占用80端口问题
  10. hadoop连接远程mysql_MySQL设置远程连接