第一步必须加入调用摄像头硬件的权限,拍完照后我们要将图片保存在SD卡中,必须加入SD卡读写权限,所以第一步,我们应该在Android清单文件中加入以下代码
摄像头权限:
1
|
<
uses-permission
android:name
=
"android.permission.CAMERA"
/>
|
SD卡读写权限:
1
2
|
<
uses-permission
android:name
=
"android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
/>
<
uses-permission
android:name
=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>
|
第二步,要将摄像头捕获的图像实时地显示在手机上。
我们是用SurfaceView这个视图组件来实现的,因此在main.xml中加入下列代码
1
2
3
4
5
|
<
SurfaceView
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:id
=
"@+id/surfaceview"
/>
|
第三步,设置窗口的显示方式
首先获得当前窗口
1
|
Window window = getWindow();
//得到窗口
|
接着设置没有标题
1
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
//没有标题
|
接着设置全屏
当然,我们在拍照过程中,屏幕必须一致处于高亮状态,因此接着加入下面代码
至此,我们将窗口的显示方式规定死了,然后才能设置窗口上显示的组件(顺序非常重要)
1
|
setContentView(R.layout.main);
|
第四步,设置SurficeView显示控件的属性
找到surficeView
1
|
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
|
设置它的像素为800x600
1
2
3
|
surfaceView.getHolder().setFixedSize(
800
,
480
);
//下面设置surfaceView不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
第五步,就是为surficeView加入回调方法(callBack)
1
|
surfaceView.getHolder().addCallback(
new
SurfaceCallback());
|
上面的回调类是我们自己定义的,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
private
class
SurfaceCallback
implements
SurfaceHolder.Callback{
@Override
public
void
surfaceCreated(SurfaceHolder holder) {
try
{
camera = Camera.open();
//打开硬件摄像头,这里导包得时候一定要注意是android.hardware.Camera
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
//得到窗口管理器
Display display = wm.getDefaultDisplay();
//得到当前屏幕
Camera.Parameters parameters = camera.getParameters();
//得到摄像头的参数
parameters.setPreviewSize(display.getWidth(), display.getHeight());
//设置预览照片的大小
parameters.setPreviewFrameRate(
3
);
//设置每秒3帧
parameters.setPictureFormat(PixelFormat.JPEG);
//设置照片的格式
parameters.setJpegQuality(
85
);
//设置照片的质量
parameters.setPictureSize(display.getHeight(), display.getWidth());
//设置照片的大小,默认是和 屏幕一样大
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceView.getHolder());
//通过SurfaceView显示取景画面
camera.startPreview();
//开始预览
isPreview =
true
;
//设置是否预览参数为真
}
catch
(IOException e) {
Log.e(TAG, e.toString());
}
}
@Override
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
int
height) {
// TODO Auto-generated method stub
}
@Override
public
void
surfaceDestroyed(SurfaceHolder holder) {
if
(camera!=
null
){
if
(isPreview){
//如果正在预览
camera.stopPreview();
camera.release();
}
}
}
}
|
第六步,我们必须对按键事件进行监听,如是拍照还是聚焦,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
boolean
onKeyDown(
int
keyCode, KeyEvent event) {
//处理按键事件
if
(camera!=
null
&&event.getRepeatCount()==
0
)
//代表只按了一下
{
switch
(keyCode){
case
KeyEvent.KEYCODE_BACK:
//如果是搜索键
camera.autoFocus(
null
);
//自动对焦
break
;
case
KeyEvent.KEYCODE_DPAD_CENTER:
//如果是中间键
camera.takePicture(
null
,
null
,
new
TakePictureCallback());
//将拍到的照片给第三个对象中,这里的TakePictureCallback()是自己定义的,在下面的代码中
break
;
}
}
return
true
;
//阻止事件往下传递,否则按搜索键会变成系统默认的
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
private
final
class
TakePictureCallback
implements
PictureCallback{
public
void
onPictureTaken(
byte
[] data, Camera camera) {
try
{
Bitmap bitmap = BitmapFactory.decodeByteArray(data,
0
, data.length);
File file =
new
File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+
".jpg"
);
FileOutputStream outputStream =
new
FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG,
100
, outputStream);
outputStream.close();
camera.stopPreview();
camera.startPreview();
//处理完数据之后可以预览
}
catch
(Exception e) {
Log.e(TAG, e.toString());
}
}
}
|
注意,代码中有两个回调类,一个是SurfaceCallback(),另外一个是TakePictureCallback(),初学者可能一时难以理解,通俗地讲,前者是用来监视surficeView这个暂时存放图片数据的显示控件的,根据它的显示情况调用不同的方法,包括surfaceCreated(),surfaceChanged(),surfaceDestroyed(),也就不难理解为什么会有这三个回调方法了(注意,在surfaceDestroyed()方法中必须释放摄像头,详细代码参见上方)。TakePictureCallback()是为了监视是否拍照而设计的接口,期中也仅有一个方法,camera将拍照得到的数据传入方法,我们便可以对拍照得到的数据进行进一步处理了。
至此,简单的拍照功能介绍完毕!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
package
cn.camera.rxm;
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.util.Calendar;
import
java.util.Locale;
import
org.apache.commons.logging.Log;
import
android.text.format.DateFormat;
import
android.util.*;
import
android.app.Activity;
import
android.content.Context;
import
android.graphics.Bitmap;
import
android.graphics.Bitmap.CompressFormat;
import
android.graphics.BitmapFactory;
import
android.graphics.PixelFormat;
import
android.hardware.Camera;
import
android.hardware.Camera.PictureCallback;
import
android.os.Bundle;
import
android.os.Environment;
import
android.view.LayoutInflater;
import
android.view.Menu;
import
android.view.MenuItem;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
//import android.widget.Toast;
public
class
MycamActivity
extends
Activity {
private
Preview mPreview;
private
Camera mCamera;
Bitmap CameraBitmap;
SurfaceHolder mHolder;
private
static
final
int
OPTION_SNAPSHOT =
0
;
private
static
final
int
OPTION_STOPCAMERA =
1
;
private
View viewStart;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
LayoutInflater flater =
this
.getLayoutInflater();
viewStart = flater.inflate(R.layout.main,
null
);
setContentView(viewStart);
Button btn1 = (Button)findViewById(R.id.button1);
btn1.setOnClickListener(
new
OnClickListener(){
public
void
onClick(View v){
mPreview =
new
Preview(getBaseContext());
setContentView(mPreview);
};
}
);
}
public
boolean
onCreateOptionsMenu(Menu menu){
//
menu.add(
0
, OPTION_SNAPSHOT,
0
, R.string.take);
//
menu.add(
0
, OPTION_STOPCAMERA,
1
, R.string.back);
//
return
true
;
//super.onCreateOptionsMenu(menu);
}
public
boolean
onOptionsItemSelected(MenuItem item) {
//
int
itemId = item.getItemId();
//
switch
(itemId){
case
OPTION_SNAPSHOT:
//拍摄照片
mCamera.takePicture(
null
,
null
, jpegCallback);
try
{
Thread.sleep(
4000
);
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
break
;
case
OPTION_STOPCAMERA:
mPreview =
null
;
setContentView(viewStart);
break
;
}
return
true
;
}
private
PictureCallback jpegCallback =
new
PictureCallback(){
//
public
void
onPictureTaken(
byte
[] data, Camera camera) {
try
{
String name =
new
DateFormat().format(
"yyyyMMdd_hhmmss"
,
Calendar.getInstance(Locale.CHINA)) +
".jpg"
;
FileOutputStream fileout =
new
FileOutputStream(
"/mnt/sdcard/sdcard/DCIM/"
+ name);
System.out.println(name);
fileout.write(data,
0
,data.length);
fileout.flush();
fileout.close();
}
catch
(IOException e) {
// TODO: handle exception
System.out.println(e);
}
}
};
class
Preview
extends
SurfaceView
implements
SurfaceHolder.Callback
{
Preview(Context context)
{
super
(context);
mHolder=getHolder();
mHolder.addCallback(
this
);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public
void
surfaceCreated(SurfaceHolder holder)
{
mCamera=Camera.open();
try
{
mCamera.setPreviewDisplay(holder);
}
catch
(IOException exception)
{
mCamera.release();
mCamera=
null
;
}
}
public
void
surfaceDestroyed(SurfaceHolder holder)
{
mCamera.stopPreview();
mCamera.release();
}
@Override
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
w,
int
h) {
// TODO Auto-generated method stub
Camera.Parameters parameters=mCamera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPreviewSize(
1024
,
1024
);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(
90
);
mCamera.startPreview();
}
}
}
|