摄像头(4)用Camera和SurfaceView自定义拍照程序
1.定制拍照程序的基本步骤
1,打开照相机:Camera.open 这是独占方式打开的
2,创建SurfaceView对象 多缓冲,多线程view
3,添加回调事件监听器(SurfaceHolder.addCallback)
4,预览(Camera.startPreview)
5,拍照(Camera.takePicture),它是异步的,要在参数中指定回调函数
2.示例
2.1 主activity
- import android.app.Activity;
- import android.content.pm.PackageManager;
- import android.hardware.Camera;
- import android.os.Bundle;
- import android.view.Window;
- import android.view.WindowManager;
- /*
- * 定制拍照程序
- * 注意Camera从5.0开始过期.用Camera2
- */
- public class CustomCameraActivity extends Activity {
- //定制拍照 第1步,加权限
- //定制拍照 第2步,准备相关api
- private Camera mCamera;//用来拍照
- private Preview mPreview;//用来预览和处理拍照事件.它是一个自定义surfaceView
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //定制拍照 第3步,设置全屏.
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
- protected void onResume() {
- super.onResume();
- //定制拍照 第4步, 打开 Camera并得到Camera实例,注意这是独占的,打开后其它程序不能打开.
- mCamera = Camera.open();
- mPreview.setCamera(mCamera);
- //定制拍照 第5步,构造预览view,这是一个自定义的surfaceView,拍照事件,及预览都在它内部实现.
- mPreview = new Preview(this);
- setContentView(mPreview);
- }
- //定制拍照 第6步,释放camera
- @Override
- protected void onPause() {
- super.onPause();
- if (mCamera != null) {
- mCamera.release();
- mCamera = null;
- mPreview.setCamera(null);
- }
- }
- //检测Android设备是否支持照相机
- private boolean checkCameraHardware(){
- if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
- return true;
- }else{
- return false;
- }
- }
- }
2.2 用来预览和处理拍照事件的类,关键
- import java.io.File;
- import java.io.FileOutputStream;
- import java.util.List;
- import android.content.Context;
- import android.hardware.Camera;
- import android.hardware.Camera.PictureCallback;
- import android.hardware.Camera.Size;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.View.OnClickListener;
- /*
- * 它是一个自定义surfaceView,
- * 用来预览和处理拍照事件.
- * 注意它实现的接口
- */
- class Preview extends ViewGroup implements SurfaceHolder.Callback,OnClickListener {
- //自定义预览和处理拍照事件 第1步, 准备相关成员
- SurfaceView mSurfaceView; //surface view
- SurfaceHolder mHolder; //SurfaceHolder
- Size mPreviewSize; //当前预览窗口尺寸.
- List<Size> mSupportedPreviewSizes; //当前设备支持的所有预览尺寸
- Camera mCamera; //摄像头对象
- Context mContext; //上下文
- public Preview(Context context) {
- super(context);
- mContext = context;
- //自定义预览和处理拍照事件 第2步,创建surface view
- mSurfaceView = new SurfaceView(context);
- addView(mSurfaceView);
- //自定义预览和处理拍照事件 第3步,得到 SurfaceHolder
- mHolder = mSurfaceView.getHolder();
- //自定义预览和处理拍照事件 第4步,添加SurfaceHolder回调
- mHolder.addCallback(this);
- }
- public void setCamera(Camera camera) {
- mCamera = camera;
- if (mCamera != null) {
- //自定义预览和处理拍照事件 第5步,得到支持的预览尺寸,注意Camera是在本类外打开的.
- mSupportedPreviewSizes = mCamera.getParameters().getSupportedPictureSizes();
- //更新 layout
- requestLayout();
- }
- }
- //from SurfaceHolder.Callback
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- try {
- if (mCamera != null) {
- //自定义预览和处理拍照事件 第6步,在SurfaceView创建时,设置camera的预览view
- mCamera.setPreviewDisplay(holder);
- }
- } catch (Exception e) {
- }
- }
- //from SurfaceHolder.Callback
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- if (mCamera != null) {
- //自定义预览和处理拍照事件 第7步,在SurfaceView销毁时,停止预览
- mCamera.stopPreview();
- }
- }
- //from SurfaceHolder.Callback
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- //自定义预览和处理拍照事件 第8步,在SurfaceView窗口大小变化时,设置预览尺寸,大小不可随意写.
- //一定要注意 预览尺寸不是实际尺寸,
- Camera.Parameters parameters = mCamera.getParameters();
- parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
- mCamera.setParameters(parameters);
- mCamera.startPreview();
- }
- //from ViewGroup
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- //自定义预览和处理拍照事件 第9步,是本类是ViewGroup,预览view是它上面的一个view,这里设置ViewGroup的layout
- if (changed && getChildCount() > ) {
- final View child = getChildAt();
- int parentWidth = r - l;
- int parentHeight = b - t;
- int previewWidth = parentWidth;
- int previewHeight = parentHeight;
- if (mPreviewSize != null) {
- previewWidth = mPreviewSize.width;
- previewHeight = mPreviewSize.height;
- }
- //外层的宽高比大于采集预览的宽高比.
- if (parentWidth * previewHeight > parentHeight * previewWidth) {
- final int scaledChildWidth = previewWidth * parentHeight
- / previewHeight;
- // child.layout((width - scaledChildWidth)/2,
- // 0,(width+scaledChildWidth)/2,height);
- //child 就是surface view
- child.layout(, , , );
- } else {
- final int scaledChildHeight = previewHeight * parentWidth
- / previewWidth;
- //child 就是surface view
- child.layout(, (parentHeight - scaledChildHeight) / , parentWidth,
- (parentHeight + scaledChildHeight) / );
- }
- }
- }
- //自定义预览和处理拍照事件 第10步,从所有预览尺寸中选一个最优的.
- private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
- double ASPECT_TOLERANCE = 0.1;
- double targetRatio = w / h;
- if (sizes == null)
- return null;
- Size optimalSize = null;
- double minDiff = Double.MAX_VALUE;
- int targetHeight = h;
- for (Size size : sizes) {
- double ratio = size.width / size.height;
- if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
- continue;
- }
- if (Math.abs(size.height - targetHeight) < minDiff) {
- optimalSize = size;
- minDiff = Math.abs(size.height - targetHeight);
- }
- }
- if (optimalSize == null) {
- minDiff = Double.MAX_VALUE;
- for (Size size : sizes) {
- if (Math.abs(size.height - targetHeight) < minDiff) {
- optimalSize = size;
- minDiff = Math.abs(size.height - targetHeight);
- }
- }
- }
- return optimalSize;
- }
- //自定义预览和处理拍照事件 第11步,在onMeasure中处理最佳预览尺寸
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = resolveSize(getSuggestedMinimumWidth(),
- widthMeasureSpec);
- int height = resolveSize(getSuggestedMinimumHeight(),
- heightMeasureSpec);
- setMeasuredDimension(width, height);
- if (mSupportedPreviewSizes != null) {
- mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes,width, height);
- }
- }
- //自定义预览和处理拍照事件 第12步, 在预览view上点击屏幕时,拍照
- //注意回调函数
- public void onClick(View view) {
- //它是异步的.
- mCamera.takePicture(null, null, mPictureCallback);
- }
- //自定义预览和处理拍照事件 第13步, 拍照的回调.
- private PictureCallback mPictureCallback = new PictureCallback() {
- @Override
- public void onPictureTaken(byte[] data, Camera camera) {
- mCamera.startPreview();//再次启动预览,这步可选.
- File pictureFile = new File("/sdcard/image.jpg");
- try {
- FileOutputStream fos = new FileOutputStream(pictureFile);
- fos.write(data);
- fos.close();
- } catch (Exception e) {
- }
- }
- };
- }
摄像头(4)用Camera和SurfaceView自定义拍照程序的更多相关文章
- 摄像头标定GML Camera Calibration
摄像头标定GML Camera Calibration GML Camera Calibration官方版是一款十分优秀出色的相机标定软件,GML Camera Calibration官方版界面友好, ...
- .Net 自定义应用程序配置
.Net 自定义应用程序配置 引言 几乎所有的应用程序都离不开配置,有时候我们会将配置信息存在数据库中(例如大家可能常会见到名为Config这样的表):更多时候,我们会将配置写在Web.config或 ...
- VS2010制作网站自定义安装程序 转
最近在把一个网站打包成安装程序,这方面的文章网上有很多,也看了不少,但因为开发环境的不同,遇到了一些问题,便写下这篇文章记下整个流程(有很多资源都来自互联网,由于条目颇多,所以无法说明其来处,敬请谅解 ...
- 自定义VS程序异常处理及调试Dump文件(一)
自定义VS程序异常处理及调试Dump文件(一) 1. Dump文件 1. Dump文件介绍 Dump文件(Dump File),也叫转储文件,以.DMP为文件后缀.dump文件是进程在内存中的镜像文件 ...
- C#自定义应用程序上下文对象+IOC自己实现依赖注入
以前的好多代码都丢失了,加上最近时间空一些,于是想起整理一下以前的个人半拉子项目,试试让它们重生.自从养成了架构师视觉 搭建框架之后,越来 越看不上以前搭的框架了.先撸个上下文对象加上实现依赖注入.由 ...
- 在Oracle电子商务套件版本12.2中创建自定义应用程序(文档ID 1577707.1)
在本文档中 本笔记介绍了在Oracle电子商务套件版本12.2中创建自定义应用程序所需的基本步骤.如果您要创建新表单,报告等,则需要自定义应用程序.它们允许您将自定义编写的文件与Oracle电子商务套 ...
- windows系统定时重启自定义exe程序
工作需要, Windows系统定时重启自定义exe程序. 写了如下程序, 按照说明(readme.txt)修改批处理文件中的四个参数即可: 1.readme.txt 第一个参数:进程名(不用带exe) ...
- 自定义wordCount程序、
1.MyWordCount代码: package com.hadoop.mr; import java.io.IOException; import org.apache.hadoop.conf.Co ...
- 常用的windows小工具指令和如何打开自定义的程序
windows可以通过 开始->运行->输入程序名 或 windows键+R键 两种方式来启动windows中自带的程序或手动安装的程序.下面介绍一些常用的windows工具的指令和如何打 ...
随机推荐
- js数字格式化-四舍五入精简版
搜索网上的,数字格式化过余复杂,自己想了个简单方法,欢迎吐槽. 简化说明: '123333' => 12.3万 parseInt('123333') 字符串转整型 parseInt('12333 ...
- [Oracle]Oracle学习小结(1)
1.查看Oracle数据库中的所有用户: (1)使用具有DBA权限的账户登录数据库: (2)执行select username from dba_users. SQL> conn sys 输入口 ...
- FireDAC如何连接ORACLE数据库
UniDac对Oracle的Direct连接,不需要安装Oracle客户端dll,deploy时真的是方便又快捷. FireDac连接Oracle,在没有Oracle Client的情况下,是可以连接 ...
- C++中delete和delete[]的区别
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]. 关于 new[] 和 delete[],其中又 ...
- jsp日期控件My97DatePicker的使用
My97DatePicker是一款非常灵活好用的日期控件.使用非常简单. 1.下载My97DatePicker组件包 2.将My97DatePicker包放在项目WebContent目录下 3.在页面 ...
- EXTJS 3.0 资料 控件之 combo 用法
EXTJS combo 控件: 1.先定义store //年款 var comboData_ReleasYear = [ ['], ['], ['], ['] ]; 2.定义combo控件 { lay ...
- 微软职位内部推荐-Pricipal Dev Manager for Application Ecosystem & Service
微软近期Open的职位: Location: China, BeijingDivision: Operations System Group Engineering Group OverviewOSG ...
- Java程序员的发展前景
不知道什么时候开始,IT业初级程序员的工作性质与进城打工的"农民工"变得如此惊人的相似.很多IT公司的高管认为"人便宜,就是要用到坏掉,然后再找更便宜.更年轻的" ...
- 3111: [Zjoi2013]蚂蚁寻路 - BZOJ
题目描述 Description在一个 n*m 的棋盘上,每个格子有一个权值,初始时,在某个格子的顶点处一只面朝北的蚂蚁,我们只知道它的行走路线是如何转弯,却不知道每次转弯前走了多长.蚂蚁转弯是有一定 ...
- Extjs4.2——bbar的默认类型(xtype)
bbar:在Panel经常使用的工具栏 如下面的示例——这将牵涉本文要追寻的问题:在下面的Panel中的bbar第一个组件明确指定的xtype:'button',第二个没有明确指出,那么它是何类型,为 ...