现在,我们来实现一个简单的Android手机拍照的实例。
该实例只是将Camera最基本的功能连接起来,即能够预览,将摄像头与手机屏幕联系起来。重在解释原理。如果想开发功能完善的相机应用,还需要添加更多功能代码。请继续关注博主的后续关于Android相机那点事儿的更新。
你们最喜欢的代码来啦!!!
首先我们应该授予程序是用摄像头的权限,所以在AndroidManifest.xml文件中增加如下代码:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
然后,我们建立一个简单的拍照界面布局:
/AndroidCamera01/res/layout/activity_main.xml
代码清单:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/Linear01"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/surfCamera"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<ImageButton
android:id="@+id/button_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:background="#00000000"
android:src="@drawable/button"/>
</RelativeLayout>
最后,我们来编写最重要的MainActivity.java文件
/AndroidCamera01/src/com/example/androidcamera01/MainActivity.java
代码清单:
packagecom.example.androidcamera01;
importjava.io.IOException;
importjava.util.List;
importandroid.app.Activity;
importandroid.content.res.Configuration;
importandroid.hardware.Camera;
importandroid.hardware.Camera.PictureCallback;
importandroid.hardware.Camera.Size;
importandroid.os.Bundle;
importandroid.view.SurfaceHolder;
importandroid.view.SurfaceView;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.view.WindowManager;
importandroid.widget.ImageButton;
importandroid.widget.Toast;
public classMainActivity extends Activity implementsSurfaceHolder.Callback {
//拍照预览
private SurfaceView surfaceView;//定义视图控件
private SurfaceHolder surfaceHolder;//定义控件
//照相机
private Camera mCamera;
//图片地址
private ImageButton btn_camera;
public voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置布局
setContentView(R.layout.activity_main);
//绑定视图
surfaceView =(SurfaceView) findViewById(R.id.surfCamera);
btn_camera =(ImageButton) findViewById(R.id.button_camera);
//从SurfaceView中获得SurfaceHolder
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(surfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mCamera = isCameraAvailiable();
if(mCamera==null) Toast.makeText(getApplicationContext(),"相机设备被占用", Toast.LENGTH_SHORT).show();
//设置事件监听 btn_camera.setOnClickListener(new OnClickListener() {
@Override
public voidonClick(View v) {
// TODOAuto-generated method stub
mCamera.takePicture(null, null, capturedIt);
}
});
}//end of onCreate
//判断照相机设备是否可用
public static CameraisCameraAvailiable(){
Camera object = null;
try {
object = Camera.open();
}
catch(Exception e){
}
return object;
}
//picture显示
private PictureCallback capturedIt = newPictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};//end ofclass PictureCallback
@Override
public voidsurfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
try {
Camera.Parameters parameters = mCamera.getParameters();
if(this.getResources().getConfiguration().orientation!=Configuration.ORIENTATION_LANDSCAPE)
{
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
}else {
parameters.set("orientation", "landscape");
//对于Android 2.2及以上版本
mCamera.setDisplayOrientation(0);
//对于Android 2.2及以上版本取消注释
parameters.setRotation(0);
}
Size largestSize =getBestSupportedSize(parameters.getSupportedPreviewSizes());
parameters.setPreviewSize(largestSize.width, largestSize.height);// 设置预览图片尺寸
parameters.setPictureSize(largestSize.width, largestSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
mCamera.release();
}
}
@Override
public voidsurfaceDestroyed(SurfaceHolder arg0) {
mCamera.stopPreview();
mCamera.release();
}
private SizegetBestSupportedSize(List<Size> sizes) {
// 取能适用的最大的SIZE
Size largestSize = sizes.get(0);
int largestArea = sizes.get(0).height * sizes.get(0).width;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
largestArea = area;
largestSize = s;
}
}
return largestSize;
}
}
最后谈几点注意事项:
要理解Camera,SurfaceView和SurfaceHolder三者的意义,SurfaceHolder是一个接口,通过SurfaceView类实现,其三个回调方法在是进行将相机参数设置以及和预览容器相连接的重要方法;当进行相机参数设置时要先实例化Camera,然后实例化camera.Preview对象对相机参数进行设置。
要注意相机预览尺寸和照片尺寸一致,否则会出现照相时看到的图片并非真实存储到本地的照片,这样就很尴尬了。这段代码当中的getBestSupportedSize(List<Size> sizes)方法就是用来寻找最适合的尺寸,使相机预览尺寸和照片尺寸保持一致的方法,Android手机都会提供多个照片和预览的尺寸,这些尺寸可能和手机屏幕一致,也可能不一致,因机型不同而定,所以在实际开发时要注意这个问题。具体如何解决,我会在后续的系列博文中和大家分享我在开发是遇到的问题。
本文中的代码只是简单的实现预览,旨在向大家展示Android相机开发的最基本原理。希望对大家的开发有所帮助。