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

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

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

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

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

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

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

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

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

 @Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//已经获得Surface的width和height,设置Camera的参数
Camera.Parameters parameters = camera.getParameters();
Camera.Size size=getBestSize(parameters.getSupportedPreviewSizes());
int w=size.width;
int h=size.height;
parameters.setPreviewSize(w, h);
parameters.setPictureSize(w, h);
// List<Camera.Size> vSizeList = parameters.getSupportedPictureSizes();
// for (int num = 0; num < vSizeList.size(); num++) {
// Camera.Size vSize = vSizeList.get(num);
// }
// if (t?his.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
//强制竖屏模式
parameters.set("orientation", "portrait");
//在2.2以上可以使用,预览显示旋转90
// parameters.setRotation(90);
camera.setDisplayOrientation(90);
// } else {
// parameters.set("orientation", "landscape");
//在2.2以上可以使用
// camera.setDisplayOrientation(90);
// }
camera.setParameters(parameters);
try {
//设置显示
camera.setPreviewDisplay(holder);
} catch (IOException exception) {
camera.release();
camera = null;
}
//开始预览
camera.startPreview();
//设置自动对焦
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
// success为true表示对焦成功,改变对焦状态图像
}
}
});
} private Camera.Size getBestSize(List<Camera.Size> supportedPreviewSizes) {
Camera.Size largestSize=supportedPreviewSizes.get(0);
int largestArea= supportedPreviewSizes.get(0).height*supportedPreviewSizes.get(0).width;
for (Camera.Size s:supportedPreviewSizes){
int area=s.width*s.height;
if(area>largestArea){
largestArea=area;
largestSize=s;
}
}
return largestSize; } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 释放手机摄像头
camera.release();
}

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

 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度,调整到竖屏显示模式,具体代码如下:

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

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

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

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

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

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

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

  1. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

  2. Windows 10 版本 1507 中的新 AppLocker 功能

    要查看 Windows 10 版本信息,使用[运行]> dxdiag  回车 下表包含 Windows 10 的初始版本(版本 1507)中包括的一些新的和更新的功能以及对版本 1511 的 W ...

  3. WPF中实现自定义虚拟容器(实现VirtualizingPanel)

    WPF中实现自定义虚拟容器(实现VirtualizingPanel) 在WPF应用程序开发过程中,大数据量的数据展现通常都要考虑性能问题.有下面一种常见的情况:原始数据源数据量很大,但是某一时刻数据容 ...

  4. Android中制作自定义dialog对话框的实例

    http://www.jb51.net/article/83319.htm   这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继 ...

  5. WPFMediaKit照相功能

    最近写的一个WPF照相功能,往各位吐槽,提供优化 在WPF 设计器中添加如下代码 xmlns:wpfmedia="clr-namespace:WPFMediaKit.DirectShow.C ...

  6. 【原创】Matlab中plot函数全功能解析

    [原创]Matlab中plot函数全功能解析 该帖由Matlab技术论(http://www.matlabsky.com)坛原创,更多精彩内容参见http://www.matlabsky.com 功能 ...

  7. GridView控件中插入自定义删除按钮并弹出确认框

    GridView控件中插入自定义删除按钮,要实现这个功能其实有多种方法,这里先记下我使用的方法,以后再添加其他方法. 一.实现步骤 1.在GridView中添加模板列(TemplateField). ...

  8. C程序中引用自定义的C函数模块

    原文:C程序中引用自定义的C函数模块 我们知道,刚开始接触C语言编程,一般都是在一个.c或者.cpp(以下只说.c)的文件中编写代码,其中一定会有一个入口函数, 也就是main()函数,你可以将程序代 ...

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

    距离上一次发布的<制作类似ThinkPHP框架中的PATHINFO模式功能>(文章地址:http://www.cnblogs.com/phpstudy2015-6/p/6242700.ht ...

随机推荐

  1. log4jdbc 与 logback 集合打印日志过多的解决

    在项目中使用了log4jdbc,可以很方便的把sql的参数也打印出来,便于问题调试.比如原始sql: select * from t_order where order_id = ? : 经过log4 ...

  2. 请读下面的这句绕口令:ResourceManager中的Resource Estimator框架介绍与算法剖析

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由宋超发表于云+社区专栏 本文首先介绍了Hadoop中的ResourceManager中的estimator service的框架与运行 ...

  3. 解决U盘拷贝时提示文件过大问题(不能拷贝超过4个g的文件)

    为什么一个16G的U盘却拷不进一个4G大点的文件呢,想必很多朋友们都在疑问? 其实这跟U盘的磁盘格式有关,目前市面上常用的U盘大都是FAT32格式,我们可以查看U盘属性. 那么FAT32是什么呢? F ...

  4. POJ 2349 Arctic Network(最小生成树中第s大的边)

    题目链接:http://poj.org/problem?id=2349 Description The Department of National Defence (DND) wishes to c ...

  5. 并发编程之 Fork-Join 分而治之框架

    前言 "分而治之" 一直是一个有效的处理大量数据的方法.著名的 MapReduce 也是采取了分而治之的思想.简单来说,就是如果你要处理1000个数据,但是你并不具备处理1000个 ...

  6. Python的两种运行方式

    从2015年5月19日注册博客园,立志于要通过写博客的方式,记录自己编程的点点滴滴,由于自己太懒,一直拖到现在,“拖延症”是病得改,今天终于写自己第一篇博客了,有点小激动! Python是由Guido ...

  7. AutoFac实现WebAPI依赖注入(EF以及Mysql)

    什么是依赖注入? 我们以实际的例子来加以介绍 实体如下 public class Product { public int ID { get; set; } public string Name { ...

  8. Linux常用基本命令[find]用法(1)

    find是个很强大的命令,用法很多. 作用:查找目录下的文件,同时也可以调用其他命令执行相应的操作 用法: find [选项] [路径][操作语句] find [-H] [-L] [-P] [-D d ...

  9. POJ1661(KB12-M DP)

    Help Jimmy Description "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无 ...

  10. js 复制粘贴

    input输入框<div id="top-title" style="position: relative"> <img class=&quo ...