CameraAPI中的 自定义照相功能

前几天的项目需要使用CameraAPI自己定义照相机,之前用过的二维码也要自己写底层代码,于是总结一下使用CameraAPI的几点事项。现在由于JDK7.0及其以上版本的官方文档已经不再推荐使用camera包而是camera2包,但这次还是先讲camera的使用,至于camera2等以后再讲。

首先是添加照相机权限,在清单文件中必须添加摄像头硬件权限和使用功能,其中功能可以根据项目需求选择性放入。

 1     <uses-permission android:name="android.permission.CAMERA"/>
 2     <!--使用摄像头硬件功能-->
 3     <uses-feature android:name="android.hardware.camera"/>
 4     <!--自动对焦功能-->
 5     <uses-feature android:name="android.hardware.camera.autofocus"/>
 6     <!--闪光灯功能-->
 7     <uses-feature android:name="android.hardware.camera.flash"/>
 8     <!--前置摄像头-->
 9     <uses-feature android:name="android.hardware.camera.front"/>

关于权限和对应的功能可以参考文章 http://www.cnblogs.com/BobGo/articles/5646751.html;

我在项目中需要两个功能,一是在显示摄像头的SurfaceView上添加一层ImageView,可以在ImageView上绘制不同的遮罩层;还有一个功能是摄像头拍摄照片之后显示及保存图片。

第一是摄像头简单的使用,在这里可能会遇到在SurfaceView中摄像头的预览出现变形问题,下面会提到解决措施:

1         SurfaceHolder surfaceHolder = surfaceView.getHolder();
2         surfaceHolder.addCallback(this);
3         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

在当前类中实现SurfaceHolder.Callback 接口,重写三个方法 surfaceCreated(), surfaceChanged(), surfaceDestroy(),这三个方法就是SurfaceView对应的生命周期;

surfaceCreated()中执行Camera.open()返回一个Camera对象,打开摄像头硬件,在surfaceDestroy()中,Camera对象调用release()释放摄像头;在surfaceChanged()中,设置摄像头参数,其中getBestSize()是确定手机摄像头硬件可以使用的最合适大小,这个算法是官方提供的。我在之前不采用这个算法而直接设置大小,导致在测试机运行时SurfaceView显示的图片出现变形。

 1 @Override
 2     public void surfaceCreated(SurfaceHolder holder) {
 3         camera = Camera.open();
 4     }
 5
 6     @Override
 7     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 8         //已经获得Surface的width和height,设置Camera的参数
 9         Camera.Parameters parameters = camera.getParameters();
10         Camera.Size size=getBestSize(parameters.getSupportedPreviewSizes());
11         int w=size.width;
12         int h=size.height;
13         parameters.setPreviewSize(w, h);
14         parameters.setPictureSize(w, h);
15 //        List<Camera.Size> vSizeList = parameters.getSupportedPictureSizes();
16 //        for (int num = 0; num < vSizeList.size(); num++) {
17 //            Camera.Size vSize = vSizeList.get(num);
18 //        }
19 //        if (t?his.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
20             //强制竖屏模式
21             parameters.set("orientation", "portrait");
22             //在2.2以上可以使用,预览显示旋转90
23 //        parameters.setRotation(90);
24             camera.setDisplayOrientation(90);
25 //        } else {
26 //            parameters.set("orientation", "landscape");
27             //在2.2以上可以使用
28 //            camera.setDisplayOrientation(90);
29 //        }
30         camera.setParameters(parameters);
31         try {
32             //设置显示
33             camera.setPreviewDisplay(holder);
34         } catch (IOException exception) {
35             camera.release();
36             camera = null;
37         }
38         //开始预览
39         camera.startPreview();
40         //设置自动对焦
41         camera.autoFocus(new Camera.AutoFocusCallback() {
42             @Override
43             public void onAutoFocus(boolean success, Camera camera) {
44                 if (success) {
45                     // success为true表示对焦成功,改变对焦状态图像
46                 }
47             }
48         });
49     }
50
51     private Camera.Size getBestSize(List<Camera.Size> supportedPreviewSizes) {
52         Camera.Size largestSize=supportedPreviewSizes.get(0);
53         int largestArea= supportedPreviewSizes.get(0).height*supportedPreviewSizes.get(0).width;
54         for (Camera.Size s:supportedPreviewSizes){
55             int area=s.width*s.height;
56             if(area>largestArea){
57                 largestArea=area;
58                 largestSize=s;
59             }
60         }
61         return largestSize;
62
63     }
64
65     @Override
66     public void surfaceDestroyed(SurfaceHolder holder) {
67         // 释放手机摄像头
68         camera.release();
69     }

也可以在surfaceChanged()中设置闪光灯等功能:

1 parameters.setFlashMode(isChecked?Camera.Parameters.FLASH_MODE_ON:Camera.Parameters.FLASH_MODE_OFF);

最后在需要摄像的点击监听中调用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)函数来完成拍照,这个函数中可以四个回调接口,ShutterCallback是快门按下的回调,在这里我们可以设置播放“咔嚓”声之类的操作,后面有三个PictureCallback接口,分别对应三份图像数据:原始图像、缩放和压缩图像和JPG图像,图像数据可以在PictureCallback接口的void onPictureTaken(byte[] data, Camera camera)中获得,三份数据相应的三个回调正好按照参数顺序调用,通常我们只关心JPG图像数据,此时前面两个PictureCallback接口参数可以直接传null

每次调用takePicture() 获取图像后,摄像头会停止预览,假如需要继续拍照,则我们需要在上面的PictureCallbackonPictureTaken() 函数末尾,Camera对象再次调用startPreview() 函数;在不需要拍照的时候,Camera对象需要主动调用stopPreview() 停止预览功能;

第二个功能是摄像图片的显示和保存,在这个功能中可能会出现两个问题,一个是拍摄图片横屏显示,另一个是将上边SurfaceView上方的ImageView遮罩层一同保存到用户手机,实现类似于图像合成的效果;

关于图片横屏显示的问题,是因为Android官方认为手机横屏才是摄像头的正确打开方式,所以保存的图片也是横屏保存的,所以如果想竖屏显示图片,就要把图片顺时针旋转90度,调整到竖屏显示模式,具体代码如下:

1 private void setImageByte(ImageView showImage, byte[] data) {
2         Bitmap bitmap= BitmapFactory.decodeByteArray(data, 0, data.length);
3         showImage.setImageBitmap(bitmap);
4         Matrix matrix = showImage.getImageMatrix();
5         matrix.setRotate(90);
6         showImage.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true));
7     }

还有一个问题是解决两个控件内容同时保存的问题,这个其实想到了方法就很简单了,自定义一个FrameLayout的子布局,在该布局中只加入一个方法

1     public Bitmap getBitmap(){
2         //设置缓存
3         setDrawingCacheEnabled(true);
4         buildDrawingCache();
5         //从缓存中获取当前屏幕的图片
6         return getDrawingCache();
7     }

然后在上文用到的xml布局中将该布局作为要同时保存图像的父控件。

最后在java代码中需要保存合成图片的地方,只需要实例化刚刚自定义的FrameLayout对象调用getBitmap(),就能返回合成之后的Bitmap对象;

所以我们的功能就能完全实现了。

时间: 2024-11-02 18:22:23

CameraAPI中的 自定义照相功能的相关文章

Delphi中ListView中实现自定义删除功能的方法

Delphi中ListView中实现自定义删除功能的方法 第一种:有时删除文件会出现文件删不掉现象 if lvMain.InnerListView.ItemIndex <> -1 then begin // DoContextMenuVerb(lvMain.SelectedFolder, 'delete'); DoContextMenuVerbB(lvMain.Folders[lvMain.InnerListView.ItemIndex], 'delete'); 第二种:删除功能很强大,建议使

ASP.NET中利用DataGrid的自定义分页功能

ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页 ASP.Net中的DataGrid有内置分页功能, 但是它的默认的分页方式效率是很低的,特别是在数据量很大的时候,用它内置的分页功能几乎是不可能的事,因为它会把所有的数据从数据库读出来再进行分页, 这种只选取了一小部分而丢掉大部分的方法是不可去取的. 在最进的一个项目中因为一个管理页面要管理的数据量非常大,所以必须分页显示,并且不能用DataGrid的内置分页功能,于是自己实现分页. 下面介绍一下我在项目中用到的分页

如何在App中实现朋友圈功能之二快速实现用户信息的自定义——箭扣科技Arrownock

如何在App中实现朋友圈功能 之二 快速实现用户信息的自定义 自我关联社交元素: anSocial中很多的社交元素API,如帖子(Post).相册(Album).文件(File)等,这些API的可选参数中允许传入其他社交元素的id. 当我们传了这些id时,服务器数据库里保存的是id,但是在返回结果里,会将这些id以对象的形式返回. 这样就大大提升了查询效率,原本需要查询两次的功能,现在可以一次实现,比如接下来要说的用户头像功能开发里可以利用的字段. 用户头像: 当我们在APP上创建用户,需要调用

jeecg3.5中为dgCol标签增加自定义格式化列中的数值的功能

jeecg3.5中只有formatter属性,只支持格式化时间格式的数据,不支持自定义格式化列中的值的功能,比如想把列中的的一个int或long型的值除以100转成float或doulbe值,jeecg3.5版本就不支持类似customFormatter这样属性,本文为jeecg3.5增加这个功能,主要修改的代码如下: org.jeecgframework.tag.core.easyui.DataGridColumnTag //51行  private String customFormatte

制作类似ThinkPHP框架中的PATHINFO模式功能(二)

距离上一次发布的<制作类似ThinkPHP框架中的PATHINFO模式功能>(文章地址:http://www.cnblogs.com/phpstudy2015-6/p/6242700.html)已经过去好多天了,今晚就将剩下的一些东西扫尾吧. 上一篇文章已经实现了PATHINFO模式的URL,即我们访问MVC模式搭建的站点时,只需要在域名后面加上(/module/controller/action)即可,很智能化.并且通过new Object时的自动触发函数实现类文件的自动载入,因此只要我们搭

KM盒子V6.2自定义模版功能教程

KM盒子从V6.2版开始将原来的自定义首页功能升级为自定义模版功能,增加{img}文档缩图.{lit}标题.{liurl}链接.{descr}描述等模版标签的调用. 1.怎样使用自定义模版功能 我们在根目录节点"内容项目"节点上右键,在弹出的菜单中选择最下面的"自定义模版设置"菜单选项. 2.设置自定义模版 首先我们需要选择index.html首页文件,然后将"是否定制首页"选项选为"是". 3.了解模版目录结构 首页模版为根

Matlab中plot函数全功能解析

Matlab中plot函数全功能解析 功能 二维曲线绘图 语法 plot(Y)plot(X1,Y1,...)plot(X1,Y1,LineSpec,...)plot(...,'PropertyName',PropertyValue,...)plot(axes_handle,...)h = plot(...)hlines = plot('v6',...) 描述 plot(Y)如果Y是m×n的数组,以1:m为X横坐标,Y中的每一列元素为Y坐标,绘制n条曲线:如果Y是n×1或者1×n的向量,则以1:n

SharePoint中开发自定义Timer Job

 SharePoint中开发自定义Timer Job 1. Timer Job简介 在SharePoint中有一个服务SharePoint timer service(owstimer.exe),这个服务用来进行异步处理一些SharePoint的数据,创建web application等等,为了缓解站点w3wp.exe的压力,而且Timer 服务可以说是占据了SharePoint的半边天,没有他那么SharePoint将不能正常工作 2. Timer Job 作用 很多时候我们需要定期自动去处理

升级IOS8游戏上传自定义头像功能失效的问题

为了支持arm64,之前已经折腾了很久,昨晚打包准备提交苹果审核时,测试那边的同事反馈说游戏上传自定义头像功能不可用了. 游戏上传自定义功能的简介:卡牌游戏最初是<比武招亲>中有一个充VIP之后就可使用了上传自定义功能的特权,我们的游戏就"复制"了该功能.   具体实现就是点击游戏内换自定义头像的按钮后,调用不同平台相应的方法,获取用户选择的图片数据,然后将图片裁剪再传给后台保存至特定的目录下.   测试设备是ipad air2,系统版本IOS 8.0.1,点击游戏内的按钮