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