您的位置:首页 > 移动开发 > Android开发

Android手机摄像头编程入门

2011-08-27 11:58 866 查看
 





本讲内容:Android手机摄像头编程入门

智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制,做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别,等等。本讲打算通过一个实例,来介绍一下摄像头编程,相关解释都写在代码中了,请注意看代码注释。

实例:窈窈照相机,功能很简单,就是点击程序弹出照相预览界面,点击相机按钮完成照相功能,所照相片会存储在手机存储卡根目录。

1、创建一个项目 Lesson36_Camera ,主程序文件为 MainActivity.java

2、AndroidManifest.xml 中设置屏幕为横屏,并且声明摄像头和存储卡的使用权限,具体代码如下:

01
<?xml version=
"1.0"

encoding=
"utf-8"
?>
02
<MANIFEST xmlns:android=
"http://schemas.android.com/apk/res/android"

android:versionname=
"1.0"

android:versioncode=
"1"

package
=
"basic.android.lesson36"
>
03
    
<APPLICATION android:icon=
"@drawable/icon"

android:label=
"@string/app_name"
>
04
        
<ACTIVITY android:label=
"@string/app_name"

android:configchanges=
"orientation|keyboardHidden|keyboard"

android:screenorientation=
"landscape"

android:name=
".MainActivity"
>
05
            
<INTENT -filter>
06
                
<ACTION android:name=
"android.intent.action.MAIN"

/>
07
                
<CATEGORY android:name=
"android.intent.category.LAUNCHER"

/>
08
            
</INTENT>
09
        
</ACTIVITY>
10
 
 
11
    
</APPLICATION>
12
    
<USES android:minsdkversion=
"8"

-sdk />
13
    
<USES android:name=
"android.permission.CAMERA"

-permission></USES>
14
    
<USES android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"

-permission></USES>
15
    
<USES android:name=
"android.hardware.camera"

-feature />
16
    
<USES android:name=
"android.hardware.camera.autofocus"

-feature />
17
</MANIFEST>
3、本例中不需要布局文件main.xml,因为本例中的UI组建都是动态添加上去的。

4、最后MainActivity.java的代码如下:

001
package

basic.android.lesson36;
002
 
 
003
import

java.io.BufferedOutputStream;
004
import

java.io.File;
005
import

java.io.FileOutputStream;
006
import

java.io.IOException;
007
import

java.util.Calendar;
008
import

java.util.Locale;
009
 
 
010
import

android.app.Activity;
011
import

android.content.Context;
012
import

android.graphics.Bitmap;
013
import

android.graphics.BitmapFactory;
014
import

android.graphics.PixelFormat;
015
import

android.hardware.Camera;
016
import

android.os.Bundle;
017
import

android.text.format.DateFormat;
018
import

android.util.Log;
019
import

android.view.KeyEvent;
020
import

android.view.SurfaceHolder;
021
import

android.view.SurfaceView;
022
import

android.view.Window;
023
import

android.view.WindowManager;
024
import

android.widget.FrameLayout;
025
import

android.widget.TextView;
026
import

android.widget.Toast;
027
 
 
028
public

class

MainActivity
extends

Activity {
029
 
 
030
    
private

CameraViewcv;
031
    
//准备一个相机对象
032
    
private

Camera mCamera =
null
;
033
    
//准备一个Bitmap对象
034
    
private

Bitmap mBitmap =
null
;  
035
 
 
036
    
//准备一个保存图片的PictureCallback对象
037
    
public

Camera.PictureCallback pictureCallback =
new

Camera.PictureCallback() {
038
 
 
039
        
public

void

onPictureTaken(
byte
[] data, Camera camera) {
040
            
Log.i(
"yao"
,
"onPictureTaken"
);
041
            
Toast.makeText(getApplicationContext(),
"正在保存……"
, Toast.LENGTH_LONG).show();
042
            
//用BitmapFactory.decodeByteArray()方法可以把相机传回的裸数据转换成Bitmap对象
043
            
mBitmap = BitmapFactory.decodeByteArray(data,
0
, data.length);
044
            
//接下来的工作就是把Bitmap保存成一个存储卡中的文件
045
            
File file =
new

File(
"/sdcard/YY"
+
new

DateFormat().format(
"yyyyMMdd_hhmmss"
, Calendar.getInstance(Locale.CHINA)) +
".jpg"
);
046
            
try

{
047
                
file.createNewFile();
048
                
BufferedOutputStream os =
new

BufferedOutputStream(
new

FileOutputStream(file));
049
                
mBitmap.compress(Bitmap.CompressFormat.PNG,
100
, os);
050
                
os.flush();
051
                
os.close();
052
                
Toast.makeText(getApplicationContext(),
"图片保存完毕,在存储卡的根目录"
, Toast.LENGTH_LONG).show();
053
            
}
catch

(IOException e) {
054
                
e.printStackTrace();
055
            
}
056
        
}
057
 
 
058
    
};

059
 
 
060
    
//Activity的创建方法
061
    
@Override
062
    
public

void

onCreate(Bundle savedInstanceState) {
063
        
super
.onCreate(savedInstanceState);
064
 
 
065
        
//窗口去掉标题
066
        
requestWindowFeature(Window.FEATURE_NO_TITLE);
067
        
//窗口设置为全屏
068
        
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
069
        
//设置窗口为半透明
070
        
getWindow().setFormat(PixelFormat.TRANSLUCENT);
071
 
 
072
        
//提供一个帧布局
073
        
FrameLayout  fl =
new

FrameLayout(
this
);      
074
 
 
075
        
//创建一个照相预览用的SurfaceView子类,并放在帧布局的底层
076
        
cv =
new

CameraView(
this
);
077
        
fl.addView(cv);
078
 
 
079
        
//创建一个文本框添加在帧布局中,我们可以看到,文字自动出现在了SurfaceView的前面,由此你可以在预览窗口做出各种特殊效果
080
        
TextView tv =
new

TextView(
this
);
081
        
tv.setText(
"请按\"相机\"按钮拍摄"
);
082
        
fl.addView(tv);
083
 
 
084
        
//设置Activity的根内容视图
085
        
setContentView(fl);
086
 
 
087
    
}

088
 
 
089
    
//相机按键按下的事件处理方法
090
    
public

boolean

onKeyDown(
int

keyCode, KeyEvent event) {
091
        
Log.i(
"yao"
,
"MainActivity.onKeyDown"
);
092
        
if

(keyCode == KeyEvent.KEYCODE_CAMERA) {
093
            
if

(mCamera !=
null
) {
094
                
Log.i(
"yao"
,
"mCamera.takePicture"
);
095
                
//当按下相机按钮时,执行相机对象的takePicture()方法,该方法有三个回调对象做入参,不需要的时候可以设null
096
                
mCamera.takePicture(
null
,
null
, pictureCallback);
097
            
}
098
        
}
099
        
return

cv.onKeyDown(keyCode, event);
100
    
}

101
 
 
102
    
// 照相视图
103
    
class

CameraView
extends

SurfaceView {
104
 
 
105
        
private

SurfaceHolder holder =
null
;
106
 
 
107
        
//构造函数
108
        
public

CameraView(Context context) {
109
            
super
(context);
110
            
Log.i(
"yao"
,
"CameraView"
);
111
 
 
112
            
// 操作surface的holder
113
            
holder =
this
.getHolder();
114
            
// 创建SurfaceHolder.Callback对象
115
            
holder.addCallback(
new

SurfaceHolder.Callback() {
116
 
 
117
                
@Override
118
                
public

void

surfaceDestroyed(SurfaceHolder holder) {
119
                    
// 停止预览
120
                    
mCamera.stopPreview();
121
                    
// 释放相机资源并置空
122
                    
mCamera.release();
123
                    
mCamera =
null
;
124
                
}
125
 
 
126
                
@Override
127
                
public

void

surfaceCreated(SurfaceHolder holder) {
128
                    
//当预览视图创建的时候开启相机
129
                    
mCamera = Camera.open();
130
                    
try

{
131
                        
//设置预览
132
                        
mCamera.setPreviewDisplay(holder);
133
                    
}
catch

(IOException e) {
134
                        
// 释放相机资源并置空
135
                        
mCamera.release();
136
                        
mCamera =
null
;
137
                    
}
138
 
 
139
                
}
140
 
 
141
                
//当surface视图数据发生变化时,处理预览信息
142
                
@Override
143
                
public

void

surfaceChanged(SurfaceHolder holder,
int

format,
int

width,
int

height) {
144
 
 
145
                    
//获得相机参数对象
146
                    
Camera.Parameters parameters = mCamera.getParameters();
147
                    
//设置格式
148
                    
parameters.setPictureFormat(PixelFormat.JPEG);
149
                    
//设置预览大小,这里我的测试机是Milsstone所以设置的是854x480
150
                    
parameters.setPreviewSize(
854
,
480
);
151
                    
//设置自动对焦
152
                    
parameters.setFocusMode(
"auto"
);
153
                    
//设置图片保存时的分辨率大小
154
                    
parameters.setPictureSize(
2592
,
1456
);
155
                    
//给相机对象设置刚才设定的参数
156
                    
mCamera.setParameters(parameters);
157
                    
//开始预览
158
                    
mCamera.startPreview();
159
                
}
160
            
});
161
            
// 设置Push缓冲类型,说明surface数据由其他来源提供,而不是用自己的Canvas来绘图,在这里是由摄像头来提供数据
162
            
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
163
        
}
164
 
 
165
    
}

166
 
 
167
}
5、连接Milestone,编译并运行程序:悲剧的是,截图只能看到黑黑的一片,无法截取到摄像头传输过来SurfaceView信息,而在真机中是能看到预览效果的。





还是上一张照好的图片给大家吧,



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息