介绍
这几天,写了一个自定义照相机的demo,支持连续拍照和摄像头切换。由于自己以前没接触过相关的编程,也算是一个学习的过程,在这里做一下记录,同时也分享出来,并附上源码和工程。
效果如图:
左上角switch切换摄像头,右边snap按钮进行拍照。
一般流程
Android进行拍照,需要调用摄像头类android.hardware.Camera。而要进行预览,则需要用android.view.SurfaceView对每一帧的预览图进行显示。
实现自定义相机一般流程为:
1、用addCallback给SurfaceView设置Callback接口对象,实现其中三个回调方法:surfaceCreated、surfaceChanged、surfaceDestroyed。
在surfaceCreated中打开摄像头,获得Camera对象,并设置其在surfaceview上预览;
在surfaceChanged中设置摄像头的参数;
在surfaceDestroyed释放摄像头,否则会导致退出之后其他应用无法调用摄像头,包括系统相机。
2、点击拍照按钮时,调用Camera对象的takePicture方法,其第三个参数为PictureCallback接口对象,其中的onPictureTaken回调方法参数中有一个byte数组,存储了拍摄到的图片数据,在方法中保存到本地即可。
这样,一个基本可用、带预览的自定义相机就做好了。但这样还远远不够,因为会出现各种各样的问题。
主要问题
预览变形
这个是最头疼的问题。首先要知道3个宽高比:摄像头分辨率(PictureSize)宽高比、预览分辨率(PreviewSize)宽高比以及用作预览的SurfaceView的宽高比。如果要让预览不变形,这三个宽高比需要保持一致。这种一致性的保持在设置摄像头参数时进行。代码如下:
|
|
方法里传进去的参数为SurfaceView现在的宽高。在保证surfaceview宽高比不变的情况下(比如为了保证全屏预览),分别去寻找符合条件的PictureSize和PreviewSize。如果找不到,就返回默认宽高比(我设置为4:3)的PictureSize和PreviewSize, 同时为保证3个宽高比一致,surfaceView的宽高比也要重设。
提供寻找合适的PictureSize和PreviewSize方法的类如下:
|
|
由于不同的手机返回的支持分辨率的排序不一样(我手中一款联想从小到大排序,而另一部nexus 4从大到小排序),所以需要先对列表统一进行从小到大排序。这样,方法返回的就是符合条件宽高比的最大分辨率,可以保证照片的清晰度。
照片方向错误
解决方法是监听手机方向的改变。监听到方向发生变化,就调用Camera.Parameters 对象(Camera对象调用getParameters()方法获得)的setRotation方法重新设置成像方向。
监听的方法是,在Activity设置一个实现了OrientationEventListener接口 的对象,并调用其enable()方法激活。
|
|
实现OrientationEventListener接口的类:
|
|
其中设置rotation的公式由google官方提供。
预览方向错误
由于我设置了相机的Activity的方向为ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,即横屏模式,所以没有遇到这个问题。
不过上一篇我转载的博文里,有提到相关问题的解决。相关代码摘录出来,供大家参考。以下代码放在surfaceview的callback中surfaceChanged方法里执行:
|
|
连续对焦
通过连续对焦,可以拍出清楚的照片。代码在上面的代码段里出现过
|
|
照相机Activity的代码就不全贴了,更具体的可以参考demo工程。
工程下载
由于本人手中测试机型只有两台,运行了上述demo的朋友方便的话可以 告知下运行效果。