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自定义拍照程序的更多相关文章

  1. 摄像头标定GML Camera Calibration

    摄像头标定GML Camera Calibration GML Camera Calibration官方版是一款十分优秀出色的相机标定软件,GML Camera Calibration官方版界面友好, ...

  2. .Net 自定义应用程序配置

    .Net 自定义应用程序配置 引言 几乎所有的应用程序都离不开配置,有时候我们会将配置信息存在数据库中(例如大家可能常会见到名为Config这样的表):更多时候,我们会将配置写在Web.config或 ...

  3. VS2010制作网站自定义安装程序 转

    最近在把一个网站打包成安装程序,这方面的文章网上有很多,也看了不少,但因为开发环境的不同,遇到了一些问题,便写下这篇文章记下整个流程(有很多资源都来自互联网,由于条目颇多,所以无法说明其来处,敬请谅解 ...

  4. 自定义VS程序异常处理及调试Dump文件(一)

    自定义VS程序异常处理及调试Dump文件(一) 1. Dump文件 1. Dump文件介绍 Dump文件(Dump File),也叫转储文件,以.DMP为文件后缀.dump文件是进程在内存中的镜像文件 ...

  5. C#自定义应用程序上下文对象+IOC自己实现依赖注入

    以前的好多代码都丢失了,加上最近时间空一些,于是想起整理一下以前的个人半拉子项目,试试让它们重生.自从养成了架构师视觉 搭建框架之后,越来 越看不上以前搭的框架了.先撸个上下文对象加上实现依赖注入.由 ...

  6. 在Oracle电子商务套件版本12.2中创建自定义应用程序(文档ID 1577707.1)

    在本文档中 本笔记介绍了在Oracle电子商务套件版本12.2中创建自定义应用程序所需的基本步骤.如果您要创建新表单,报告等,则需要自定义应用程序.它们允许您将自定义编写的文件与Oracle电子商务套 ...

  7. windows系统定时重启自定义exe程序

    工作需要, Windows系统定时重启自定义exe程序. 写了如下程序, 按照说明(readme.txt)修改批处理文件中的四个参数即可: 1.readme.txt 第一个参数:进程名(不用带exe) ...

  8. 自定义wordCount程序、

    1.MyWordCount代码: package com.hadoop.mr; import java.io.IOException; import org.apache.hadoop.conf.Co ...

  9. 常用的windows小工具指令和如何打开自定义的程序

    windows可以通过 开始->运行->输入程序名 或 windows键+R键 两种方式来启动windows中自带的程序或手动安装的程序.下面介绍一些常用的windows工具的指令和如何打 ...

随机推荐

  1. c# 类型初始值设定项引发异常

    今天使用VS2010编译c#程序,编译顺利通过,点击运行启动程序,弹框提示如题错误.断点调试,程序甚至都没有进入main函数!!查阅网上资料,几种分析如下(1)反射机制 (2)app.config文件 ...

  2. 【Qt】Qt环境搭建(Visual Studio)【转】

    简述 经常有人问我编写Qt程序时使用什么IDE,其实这个真的很难回答(各有所长),只能说看个人爱好了,因为我两个都用,而且两个都很喜欢(比较多情吧O(∩_∩)O~)! 下面将进行Qt Creator与 ...

  3. IOS 四种保存数据的方式

    在iOS开发过程中,不管是做什么应用,都会碰到数据保存的问题.将数据保存到本地,能够让程序的运行更加流畅,不会出现让人厌恶的菊花形状,使得用户体验更好.下面介绍一下数据保存的方式: 1.NSKeyed ...

  4. 让Dock自动 显示/隐藏 不再有延迟

    Safari 5.2 Mac OS X 10.7.2 <ignore_js_op> 可能很多朋友使用Mac的时候都会选择将Dock隐藏(可以在系统偏好设置-Dock中选择),等到使用的时候 ...

  5. C#调用IOS推送

    C#调用IOS推送 使用的是 PushSharp 开源库 源码代码如下 点我

  6. jQuery阻止冒泡和HTML默认操作

    1:jQuery是一个快捷简便的JavaScript框架,说道框架可以直接理解为就是对原来底层的东西进行了封装使得开发者能够利用这个框架快速开发. 2:在当今的各个浏览器中都支持事件的冒泡,所谓的冒泡 ...

  7. redis使用watch完成秒杀抢购功能:

    redis使用watch完成秒杀抢购功能: 使用redis中两个key完成秒杀抢购功能,mywatchkey用于存储抢购数量和mywatchlist用户存储抢购列表. 它的优点如下: 1. 首先选用内 ...

  8. Spark Streaming揭秘 Day10 从BlockGenerator看接收数据的生命周期

    Spark Streaming揭秘 Day10 从BlockGenerator看接收数据的生命周期 昨天主要介绍了SparkStreaming中对于Receiver的生命周期管理,下面让我们进入到Re ...

  9. iOS 通览(二)

    一.关键词 extern:C语言的函数外部声明. 如果你要在一个.c或者.m中使用另外一个.c文件的函数的话,需要在文件中写入目标函数的外部引用的声明. 二.自定义View 自定义View添加控件对象 ...

  10. 微软职位内部推荐-Sr Development Lead-OSG-IPX

    微软近期Open的职位: Job Summary:Be part of Microsoft's strategy to deliver a great input experience across ...