在android中应用相机功能,一般有两种:一种是直接调用系统相机,一种自己写的相机。我将分别演示两种方式的使用:
第一种:是使用Intent跳转到系统相机,action为:android.media.action.STILL_IMAGE_CAMERA
关键代码:
Java代码:
01.Intent intent = new Intent(); //调用照相机
02.intent.setAction("android.media.action.STILL_IMAGE_CAMERA");
03.startActivity(intent);
复制代码 例子:CameraTest_2.java
Java代码:
01.import android.app.Activity;
02.import android.content.Intent;
03.import android.os.Bundle;
04.
05.public class CameraTest_2 extends Activity {
06./** Called when the activity is first created. */
07.@Override
08.public void onCreate(Bundle savedInstanceState) {
09.super.onCreate(savedInstanceState);
10.setContentView(R.layout.main);
11.Intent intent = new Intent(); //调用照相机
12.intent.setAction("android.media.action.STILL_IMAGE_CAMERA");
13.startActivity(intent);
14.}
15.
16.}
复制代码
想要测试的,可以直接新建一个项目,并且把主activity的代码换成上面的,然后运行,我测试了一下,上面这个代码并不需要权限,毕竟只是调用系统自带的程序。
当然网上还有一些其他相关的调用方法,只要设置对了action,那么系统就会调用系统自带的相机.
第二种:
(1)首先我们要自己创建一个照相,必须考虑用什么控件显示照相机中的预览效果,显然android已经帮我们做好了选择,那就是SurfaceView,而控制SurfaceView则需要一个surfaceHolder,他是系统提供的一个用来设置surfaceView的一个对象,而它通过surfaceView.getHolder()这个方法来获得。而Camera提供一个setPreviewDisplay(SurfaceHolder)的方法来连接.surfaceHolder,并通过他来控制surfaceView,而我们则使用android的Camera类提供了startPreview()和stopPreview()来开启和关闭预览.
关系如下:
Camera -- -->SurfaceHolder------>SurfaceView.
(2)知道怎么预览,当然也要知道怎么开启相机.Camera.open()这是个静态方法,如果相机没有别人用着,则会返回一个 相机引用,如果被人用着,则会抛出异常。很奇怪的是,这个方法,不能随便放,如放在构造方法或者onCreate()方法中,都会照成没有预览效果.
(3)SurfaceHolder.Callback,这是个holder用来显示surfaceView 数据的接口,他分别必须实现3个方法
surfaceCreated()这个方法是surface 被创建后调用的
surfaceChanged()这个方法是当surfaceView发生改变后调用的
surfaceDestroyed()这个是当surfaceView销毁时调用的.
surfaceHolde通过addCallBack()方法将响应的接口绑定到他身上.
surfaceHolder还必须设定一个setType()方法,查看api的时候,发现这个方法已经过时,但是没有写,又会报错。。各种奇怪。
(4)我用以上知识写了一个MySurfaceView类,他继承于SurfaceView,并在里面实现了照相机的预览功能.这个我觉得最简单的照相机预览代码:
MySurfaceView.java
Java代码:
01.import java.io.IOException;
02.import android.content.Context;
03.import android.graphics.PixelFormat;
04.import android.hardware.Camera;
05.import android.util.Log;
06.import android.view.SurfaceHolder;
07.import android.view.SurfaceView;
08.
09.public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
10.SurfaceHolder holder;
11.Camera myCamera;
12.
13.public MySurfaceView(Context context) {
14.super(context);
15.holder = getHolder();//获得surfaceHolder引用
16.holder.addCallback(this);
17.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
18.}
19.
20.@Override
21.public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
22.myCamera.startPreview();
23.}
24.@Override
25.public void surfaceCreated(SurfaceHolder holder) {
26.// TODO Auto-generated method stub
27.if(myCamera == null) {
28.myCamera = Camera.open();//开启相机,不能放在构造函数中,不然不会显示画面.
29.try {
30.myCamera.setPreviewDisplay(holder);
31.} catch (IOException e) {
32.// TODO Auto-generated catch block
33.e.printStackTrace();
34.}
35.}
36.}
37.
38.@Override
39.public void surfaceDestroyed(SurfaceHolder holder) {
40.// TODO Auto-generated method stub
41.myCamera.stopPreview();//停止预览
42.myCamera.release();//释放相机资源
43.myCamera = null;
44.Log.d("ddd", "4");
45.}
46.}
复制代码
CameraTest_3.java
Java代码:
01.import android.app.Activity;
02.import android.os.Bundle;
03.import android.view.View;
04.import android.view.View.OnClickListener;
05.
06.public class CameraTest_3 extends Activity {
07./** Called when the activity is first created. */
08.MySurfaceView mySurface;
09.@Override
10.public void onCreate(Bundle savedInstanceState) {
11.super.onCreate(savedInstanceState);
12.mySurface = new MySurfaceView(this);
13.setContentView(mySurface);
14.}
15.
16.}
而且必须给应用添加权限: <uses-permission android:name="android.permission.CAMERA"></uses-permission>
(5)能够预览了,接下来就是拍照了,拍照用到了一个camera.tackPiture()这个方法,这个方法,有三个参数分别是ShutterCallBack shutter,PictureCallBack raw,PictureCallBack jpeg.
下面是对他们的实现
Java代码:
01.private ShutterCallback shutter = new ShutterCallback() {
02.@Override
03.public void onShutter() {
04.// TODO Auto-generated method stub
05.Log.d("ddd", "shutter");
06.}
07.};
08.
09.private PictureCallback raw = new PictureCallback() {
10.@Override
11.public void onPictureTaken(byte[] data, Camera camera) {
12.// TODO Auto-generated method stub
13.Log.d("ddd", "raw");
14.}
15.};
16.
17.
18.private PictureCallback jpeg = new PictureCallback() {
19.@Override
20.public void onPictureTaken(byte[] data, Camera camera) {
21.// TODO Auto-generated method stub
22.Log.d("ddd","jpeg");
23.}
24.};
复制代码
当开始拍照时,会依次调用shutter的onShutter()方法,raw的onPictureTaken方法,jpeg的onPictureTaken方法.三个参数的作用是shutter--拍照瞬间调用,raw--获得没有压缩过的图片数据,jpeg---返回jpeg的图片数据
当你不需要对照片进行处理,可以直接用null代替.
注意,当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览。
我用以上知识,加到上面的那个例子,就形成了下面的代码:
MySurfaceView.java
Java代码:
01.package eoe.wjh.camera;
02.
03.import java.io.IOException;
04.import android.content.Context;
05.import android.graphics.PixelFormat;
06.import android.hardware.Camera;
07.import android.hardware.Camera.PictureCallback;
08.import android.hardware.Camera.ShutterCallback;
09.import android.util.Log;
10.import android.view.SurfaceHolder;
11.import android.view.SurfaceView;
12.
13.
14.public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
15.SurfaceHolder holder;
16.Camera myCamera;
17.private ShutterCallback shutter = new ShutterCallback() {
18.@Override
19.public void onShutter() {
20.// TODO Auto-generated method stub
21.Log.d("ddd", "shutter");
22.}
23.};
24.
25.private PictureCallback raw = new PictureCallback() {
26.@Override
27.public void onPictureTaken(byte[] data, Camera camera) {
28.// TODO Auto-generated method stub
29.Log.d("ddd", "raw");
30.}
31.};
32.private PictureCallback jpeg = new PictureCallback() {
33.@Override
34.public void onPictureTaken(byte[] data, Camera camera) {
35.// TODO Auto-generated method stub
36.Log.d("ddd","jpeg");
37.}
38.};
39.public MySurfaceView(Context context) {
40.super(context);
41.holder = getHolder();//获得surfaceHolder引用
42.holder.addCallback(this);
43.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
44.}
45.public void tackPicture() {
46.myCamera.takePicture(null,null,null);
47.}
48.public void voerTack() {
49.myCamera.startPreview();
50.}
51.@Override
52.public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
53.myCamera.startPreview();
54.}
55.@Override
56.public void surfaceCreated(SurfaceHolder holder) {
57.// TODO Auto-generated method stub
58.if(myCamera == null) {
59.myCamera = Camera.open();//开启相机,不能放在构造函数中,不然不会显示画面.
60.try {
61.myCamera.setPreviewDisplay(holder);
62.} catch (IOException e) {
63.// TODO Auto-generated catch block
64.e.printStackTrace();
65.}
66.}
67.}
68.
69.@Override
70.public void surfaceDestroyed(SurfaceHolder holder) {
71.// TODO Auto-generated method stub
72.myCamera.stopPreview();//停止预览
73.myCamera.release();//释放相机资源
74.myCamera = null;
75.}
76.}
复制代码
CameraTest_3.java
Java代码:
01.import android.app.Activity;
02.import android.os.Bundle;
03.import android.view.View;
04.import android.view.View.OnClickListener;
05.
06.public class CameraTest_3 extends Activity implements OnClickListener {
07./** Called when the activity is first created. */
08.MySurfaceView mySurface;
09.boolean isClicked = false;
10.@Override
11.public void onCreate(Bundle savedInstanceState) {
12.super.onCreate(savedInstanceState);
13.mySurface = new MySurfaceView(this);
14.setContentView(mySurface);
15.mySurface.setOnClickListener(this);
16.}
17.
18.@Override
19.public void onClick(View v) {
20.// TODO Auto-generated method stub
21.if(!isClicked)
22.{
23.mySurface.tackPicture();
24.isClicked = true;
25.}else {
26.mySurface.voerTack();
27.isClicked = false;
28.}
29.
30.}
这样就是实现了拍照的功能,那么怎样要图片保存呢?那么这是就需要在那个参数中的jpeg的
方法里面进行处理了,那个方法的data参数,就是相片的数据。
我们通过BitmapFactory.decodeByteArray(data, 0, data.length)来获得图片并通过io处理,将图片保存到想要保存的位置
下面这段代码,是将照片保存到/sdcard/wjh.jpg;并把一些没有用到的代码全部删掉,剩下一些必须的代码
MySurfaceView.java
Java代码:
01.package eoe.wjh.camera;
02.
03.import java.io.BufferedInputStream;
04.import java.io.BufferedOutputStream;
05.import java.io.File;
06.import java.io.FileOutputStream;
07.import java.io.OutputStream;
08.import android.content.Context;
09.import android.graphics.Bitmap;
10.import android.graphics.BitmapFactory;
11.import android.graphics.PixelFormat;
12.import android.hardware.Camera;
13.import android.hardware.Camera.PictureCallback;
14.import android.hardware.Camera.ShutterCallback;
15.import android.util.Log;
16.import android.view.SurfaceHolder;
17.import android.view.SurfaceView;
18.
19.public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
20.SurfaceHolder holder;
21.Camera myCamera;
22.private PictureCallback jpeg = new PictureCallback() {
23.@Override
24.public void onPictureTaken(byte[] data, Camera camera) {
25.// TODO Auto-generated method stub
26.try {
27.Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
28.File file = new File("/sdcard/wjh.jpg");
29.BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
30.bm.compress(Bitmap.CompressFormat.JPEG,100,bos);
31.bos.flush();
32.bos.close();
33.}catch(Exception e) {
34.e.printStackTrace();
35.}
36.};
37.public MySurfaceView(Context context) {
38.super(context);
39.holder = getHolder();//获得surfaceHolder引用
40.holder.addCallback(this);
41.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
42.}
43.public void tackPicture() {
44.myCamera.takePicture(null,null,jpeg);
45.}
46.public void voerTack() {
47.myCamera.startPreview();
48.}
49.
50.@Override
51.public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
52.myCamera.startPreview();
53.}
54.@Override
55.public void surfaceCreated(SurfaceHolder holder) {
56.if(myCamera == null) {
57.myCamera = Camera.open();//开启相机,不能放在构造函数中,不然不会显示画面.
58.try {
59.myCamera.setPreviewDisplay(holder);
60.} catch (IOException e) {
61.// TODO Auto-generated catch block
62.e.printStackTrace();
63.}
64.}
65.}
66.@Override
67.public void surfaceDestroyed(SurfaceHolder holder) {
68.// TODO Auto-generated method stub
69.myCamera.stopPreview();//停止预览
70.myCamera.release();//释放相机资源
71.myCamera = null;
72.}
73.}
复制代码
注意,这是必须添加在sd卡上写数据的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(7)能够拍照了,这下子要考虑如何让图片更好看了,这显然是专业人士的强项,但是我们在程序上,也可以做一些处理,
向上面的那些,因为我直接把surfaceView当做整体布局,就可能出现屏幕被拉开了,不是很好看,所以这时,就可以不要把surfaceView弄成整体布局,把他弄到到一个布局管理器,在设置相关的参数.这是需要注意的是有些参数不能随便乱设,
如以下代码:
Java代码:
01.Camera.Parameters parames = myCamera.getParameters();//获得参数对象
02.parames.setPictureFormat(PixelFormat.JPEG);//设置图片格式
03.parames.setPreviewSize(640,480);//这里面的参数只能是几个特定的参数,否则会报错.(176*144,320*240,352*288,480*360,640*480)
04.myCamera.setParameters(parames);
复制代码 还有自动对焦,当然有些手机没有这个功能,自动对焦是通过autoFocus()这个方法调用一个自动对焦的接口,并在里面进行处理。
注意,这个方法必须在startPreview()和stopPreview()中间。
AutoFocusCallback是自动对焦的接口,实现它必须实现public void onAutoFocus(boolean success, Camera camera)这个方法,所以我们可以将拍照方法放在这里面,然后对焦后再进行拍摄。效果会好很多。
注意自动对焦需要添加<uses-feature android:name="android.hardware.camera.autofocus" />下面我叫直接把上面的使用例子直接写出。
CameraTest_4.java
Java代码:
01.import java.io.BufferedOutputStream;
02.import java.io.File;
03.import java.io.FileOutputStream;
04.import java.io.IOException;
05.import android.app.Activity;
06.import android.content.pm.ActivityInfo;
07.import android.graphics.Bitmap;
08.import android.graphics.BitmapFactory;
09.import android.graphics.PixelFormat;
10.import android.hardware.Camera;
11.import android.hardware.Camera.AutoFocusCallback;
12.import android.hardware.Camera.PictureCallback;
13.import android.os.Bundle;
14.import android.view.SurfaceHolder;
15.import android.view.SurfaceView;
16.import android.view.View;
17.import android.view.Window;
18.import android.view.SurfaceHolder.Callback;
19.import android.view.View.OnClickListener;
20.
21.
22.public class CameraTest_4 extends Activity implements
23.Callback, OnClickListener, AutoFocusCallback{
24.SurfaceView mySurfaceView;//surfaceView声明
25.SurfaceHolder holder;//surfaceHolder声明
26.Camera myCamera;//相机声明
27.String filePath="/sdcard/wjh.jpg";//照片保存路径
28.boolean isClicked = false;//是否点击标识
29.//创建jpeg图片回调数据对象
30.PictureCallback jpeg = new PictureCallback() {
31.@Override
32.public void onPictureTaken(byte[] data, Camera camera) {
33.// TODO Auto-generated method stub
34.try {// 获得图片
35.Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
36.File file = new File(filePath);
37.BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
38.bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中
39.bos.flush();//输出
40.bos.close();//关闭
41.}catch(Exception e) {
42.e.printStackTrace();
43.}
44.}
45.};
46./** Called when the activity is first created. */
47.@Override
48.public void onCreate(Bundle savedInstanceState) {
49.super.onCreate(savedInstanceState);
50.requestWindowFeature(Window.FEATURE_NO_TITLE);//无标题
51.//设置拍摄方向
52.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
53.setContentView(R.layout.main);
54.//获得控件
55.mySurfaceView = (SurfaceView)findViewById(R.id.surfaceView1);
56.//获得句柄
57.holder = mySurfaceView.getHolder();
58.//添加回调
59.holder.addCallback(this);
60.//设置类型
61.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
62.//设置监听
63.mySurfaceView.setOnClickListener(this);
64.}
65.@Override
66.public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
67.// TODO Auto-generated method stub
68.//设置参数并开始预览
69.Camera.Parameters params = myCamera.getParameters();
70.params.setPictureFormat(PixelFormat.JPEG);
71.params.setPreviewSize(640,480);
72.myCamera.setParameters(params);
73.myCamera.startPreview();
74.}
75.@Override
76.public void surfaceCreated(SurfaceHolder holder) {
77.// TODO Auto-generated method stub
78.//开启相机
79.if(myCamera == null) {
80.myCamera = Camera.open();
81.try {
82.myCamera.setPreviewDisplay(holder);
83.} catch (IOException e) {
84.// TODO Auto-generated catch block
85.e.printStackTrace();
86.}
87.}
88.}
89.@Override
90.public void surfaceDestroyed(SurfaceHolder holder) {
91.// TODO Auto-generated method stub
92.//关闭预览并释放资源
93.myCamera.stopPreview();
94.myCamera.release();
95.myCamera = null;
96.}
97.@Override
98.public void onClick(View v) {
99.// TODO Auto-generated method stub
100.if(!isClicked) {
101.myCamera.autoFocus(this);//自动对焦
102.isClicked = true;
103.}else {
104.myCamera.startPreview();//开启预览
105.isClicked = false;
106.}
107.}
108.@Override
109.public void onAutoFocus(boolean success, Camera camera) {
110.// TODO Auto-generated method stub
111.if(success) {
112.//设置参数,并拍照
113.Camera.Parameters params = myCamera.getParameters();
114.params.setPictureFormat(PixelFormat.JPEG);
115.params.setPreviewSize(640,480);
116.myCamera.setParameters(params);
117.myCamera.takePicture(null, null, jpeg);
118.}
119.}
120.
121.}
复制代码
main.xml
Java代码:
01.<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
02.androidrientation="vertical"
03.android:layout_width="fill_parent"
04.android:layout_height="fill_parent"
05.>
06.<surfaceview android:id="@+id/surfaceView1"
07.android:layout_width="640px"
08.android:layout_height="480px"
09.android:layout_gravity="center">
复制代码
AndroidManifest.xml
Java代码:
01.<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
02.package="com.wjh.camera"
03.android:versionCode="1"
04.android:versionName="1.0">
05.<uses-sdk android:minSdkVersion="7" />
06.<uses-permission android:name="android.permission.CAMERA"></uses-permission>
07.<uses-feature android:name="android.hardware.camera.autofocus" />
08.<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
09.<application android:icon="@drawable/icon" android:label="@string/app_name">
10.<activity android:name=".CameraTest_4" android:label="@string/app_name">
11.<intent-filter>
12.<action android:name="android.intent.action.MAIN" />
13.<category android:name="android.intent.category.LAUNCHER" />
14.</intent-filter>
15.</activity>
16.</application>
17.</manifest>