本文主要是Apress.Pro.Android.Media.Dec.2010书籍的读书笔记,加上自己的一些理解
要创建一个自定义的摄像机应用,就需要调用android的Camera这个类。这个类可以帮助我们调用手机的内置摄像头,并通过设置各种参数达到我们的要求,比如显示的大小,曝光度等。
摄像头权限
为了能够调用Camera类捕捉画面,我们需要在AndroidManifest.xml文件中指定权限
<uses-permission android:name="android.permission.CAMERA" />
预览界面
在布局中利用surfaceView控件来展示摄像头界面,以下是一个基本的布局(surfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SurfaceView android:id="@+id/CameraView" android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView> </LinearLayout>
在代码中利用surfaceholder来监听摄像头的创建、销毁、改变的事件
创建预览界面分一下几个步骤
1、在surfaceCreated中获取Camera对象
2、设置camera的预览监听
3、启动摄像头预览
4、在surfaceDestroyed中当控件销毁时,关闭摄像头预览,并释放资源
package com.camerademo;
import java.util.Iterator; import java.util.List;
import android.app.Activity; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.hardware.Camera; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout;
public class Main extends Activity implements SurfaceHolder.Callback{
SurfaceView cameraView; SurfaceHolder surfaceHolder; Camera camera; public static final int LARGEST_WIDTH = 300; public static final int LARGEST_HEIGHT = 300; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); setContentView(R.layout.main); cameraView = (SurfaceView) this.findViewById(R.id.CameraView); surfaceHolder = cameraView.getHolder(); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceHolder.addCallback(this); System.out.println("oncreate"); }
/* (non-Javadoc) * @see android.app.Activity#onStart() */ @Override protected void onStart() { super.onStart(); System.out.println("onstart"); } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { System.out.println("surfaceChanged"); }
@Override public void surfaceCreated(SurfaceHolder holder) { System.out.println("surfaceCreated"); camera = Camera.open();//获取Camera对象 try{ camera.setPreviewDisplay(holder);//设置预览监听 Camera.Parameters parameters = camera.getParameters(); if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE){ parameters.set("orientation", "portrait"); camera.setDisplayOrientation(90);//针对android2.2和之前的版本 parameters.setRotation(90);//去掉android2.0和之前的版本 }else{ parameters.set("orientation", "landscape"); camera.setDisplayOrientation(0); parameters.setRotation(0); } camera.setParameters(parameters); int bestWidth = 0; int bestHeight = 0; List<Camera.Size> previewSizes = parameters.getSupportedPictureSizes(); if(previewSizes.size()>1){ Iterator<Camera.Size> cei = previewSizes.iterator(); while(cei.hasNext()){ Camera.Size aSize = cei.next(); System.out.println(aSize.width+","+aSize.height); if(aSize.width>bestWidth && aSize.width<=LARGEST_WIDTH && aSize.height>bestHeight && aSize.height<=LARGEST_HEIGHT){ bestWidth = aSize.width; bestHeight = aSize.height; } if(bestHeight!=0 && bestWidth != 0){ Log.v("SNAPSHOT", "Using"+bestWidth+"x"+bestHeight); parameters.setPreviewSize(bestWidth, bestHeight); cameraView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth,bestHeight)); } } }
camera.startPreview();//启动摄像头预览 }catch(Exception e){ camera.release();//如果在设置摄像头的时候出现异常,在这里释放资源 } }
@Override public void surfaceDestroyed(SurfaceHolder arg0) {//当要销毁时,先停止预览,并释放资源 System.out.println("surfaceDestroyed"); camera.stopPreview(); camera.release(); } }
这里要注意下,手机的摄像头资源是唯一的,如果你不需要再使用时,应及时释放其资源,不然会导致其应用程序无法调用摄像头的。
所以在上上面的代码中,当控件要销毁时surfacedestroyed方法中,释放了资源。在设置设置摄像头预览监听时有可能发生io异常所以用try/catch包裹camera.setPreviewDisplay(holder);方法,如果出现异常也释放资源。 刚才指介绍了创建预览界面,那么如何创建我们要求的预览界面呢,比如大小什么的,关键就在surfaccreated方法中设置camera的属性了。
1、预览界面的横竖屏展示
在进行摄像头的相关开发时,最常遇到的就是如何设置摄像头的正确方向是横向的或是竖向的。可以通过设置carmera的属性的来实现,由于官方并没有提供统一的方法进行设置,所以不同版本的设置方法都不太一样。
camera.setPreviewDisplay(holder); Camera.Parameters parameters = camera.getParameters(); if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE){ parameters.set("orientation", "portrait"); camera.setDisplayOrientation(90);//针对android2.2和之前的版本 parameters.setRotation(90);//去掉android2.0和之前的版本 }else{ parameters.set("orientation", "landscape"); camera.setDisplayOrientation(0); parameters.setRotation(0); } camera.setParameters(parameters);
先判断当前的界面是横向还是竖向的,针对2.2以上的版本可以设置parameters.set("orientation", "portrait")或 parameters.set("orientation", "landscape"); 2.2和之前的版本可以设置camera.setDisplayOrientation(90)和camera.setDisplayOrientation(0)2.0和之前的可以设置parameters.setRotation(90) 和parameters.setRotation(0)2、预览界面的效果设置android api中可选择的颜色效果有许多种:
EFFECT_NONE 无效果 EFFECT_MONO 黑白效果 EFFECT_NEGATIVE 负面效果 EFFECT_SOLARIZE 曝光效果 EFFECT_SEPIA Sephia效果 EFFECT_POSTERIZE 多色调分色印效果 EFFECT_WHITEBOARD 白板效果 EFFECT_BLACKBOARD 黑板效果 EFFECT_AQUA 浅绿色效果这么多的效果专业名词对于我这种非图像专业的还是看不懂啊,只有没有都试下才明白,不过要注意的是这么多效果并不是没款手机都支持的,因此我们在调用的时候应当先获取该手机支持的效果类型,再来设置,这些效果在不同的手机上还不太一样,比如在我的G7上这样设置都没有效果。如下:List<String> colorEffects = parameters.getSupportedColorEffects(); Iterator<String> cei = colorEffects.iterator(); while(cei.hasNext()){ String currentEffect = cei.next(); System.out.println("Checking:"+currentEffect); if(currentEffect.equals(Camera.Parameters.EFFECT_SOLARIZE)){ parameters.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);//曝光效果 break; } }
3、预览界面的大小设置预览界面大小的设置和效果设置类似,你也必须先判断手机支持哪几种比例的大小在进行设置,不然获得的图像会变形的。如下:int bestWidth = 0; int bestHeight = 0; List<Camera.Size> previewSizes = parameters.getSupportedPictureSizes(); if(previewSizes.size()>1){ Iterator<Camera.Size> cei = previewSizes.iterator(); while(cei.hasNext()){ Camera.Size aSize = cei.next(); System.out.println(aSize.width+","+aSize.height); if(aSize.width>bestWidth && aSize.width<=LARGEST_WIDTH && aSize.height>bestHeight && aSize.height<=LARGEST_HEIGHT){ bestWidth = aSize.width; bestHeight = aSize.height; } if(bestHeight!=0 && bestWidth != 0){ Log.v("SNAPSHOT", "Using"+bestWidth+"x"+bestHeight); parameters.setPreviewSize(bestWidth, bestHeight); cameraView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth,bestHeight)); } } }
LARGEST_WIDTH 和 LARGEST_HEIGHT 为我们设置的预期的预览界面的大小比如300*300。