完成一个拍照功能需要完成两个部分,一个是预览(preview),一个是拍照。
1.预览功能
我们使用SurfaceView在屏幕上渲染出一片区域,然后将摄像头捕捉到的画面显示在该区域内。Surface的设置有以下5个步骤:
1. 创建一个SurfaceView
2. 获得操作对象
3. 获得SurfaceHolder对象
4. 实现SurfaceHolder.CallBack接口,并传递给SurfaceHolder
5. 设置SurfaceHolder类型
(1)在xml文件中创建SurfaceView
<SurfaceView
android:id="@+id/surfaceView1"
android:layout_width="320px"
android:layout_height="240px"/>
(2)获得对象SurfaceView sv=(SurfaceView) findViewById(R.id.surfaceView1);
(3)holder=sv.getHolder(); //获得holder对象
(4)回调接口
public void surfaceChanged(SurfaceHolder arg0,int arg1,int arg2,int arg3)
{
if(camera!=null){
camera.release();
}
}
public void surfaceCreated(SurfaceHolder arg0)
{
}
public void surfaceDestroyed(SurfaceHolder arg0)
{
if(camera!=null){
camera.release();
camera=null;
}
}
之后使用holder.addCallback(this); 便实现了将参数传递给了SurfaceHolder
(5)设置类型
2.配置Camera预览参数
有以下5个步骤:
1. 获得Camera对象
2. 获得相机参数
3. 设置预览大小
4. 绑定SurfaceView
5. 开始预览
3.拍摄功能
Camera.takePicture(ShutterCalback shutter,PictureCallback raw,
PictureCallback jpeg),可以只实现第三个回调函数实现拍照功能。
实现PictureCallback jpeg接口:
在该接口中要实现方法: public void onPictureTaken(byte[] data, Camera camera)
第一个参数是照片原始数据,用位图表示 Bitmap bm=BitmapFactory.decodeByteArray(data, 0, data.length);
之后可以保存为文件了 bm.compress(CompressFormat format, int quality, OutputStream stream);
实现简易相机
首先要在注册文件中获得相应权限:
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
实现代码:
public class MainActivity extends Activity implements SurfaceHolder.Callback {//实现callback接口
SurfaceView sv;
SurfaceHolder holder;
Button preview_btn;
Button take_btn;
ImageView iv;
Camera camera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//横向屏幕
initView();
preview_btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO 自动生成的方法存根
preview();//开始预览
//camera.autoFocus(afc);//可实现自动对焦功能
}
});
take_btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO 自动生成的方法存根
takePicture();
}
});
}
private AutoFocusCallback afc=new Camera.AutoFocusCallback() {//自动对焦的接口,对焦完毕则拍照
@Override
public void onAutoFocus(boolean success, Camera camera) {
// TODO 自动生成的方法存根
if(success)
{
takePicture();
// camera.cancelAutoFocus();
}
}
};
private void initView() {
// TODO 自动生成的方法存根
sv=(SurfaceView) findViewById(R.id.surfaceView1);
iv=(ImageView)findViewById(R.id.imageView1);
preview_btn=(Button)findViewById(R.id.button1);
take_btn=(Button)findViewById(R.id.button2);
holder=sv.getHolder(); //获得holder对象
holder.addCallback(this); //添加回调函数接口
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
}
//预览函数
protected void preview() {
// TODO 自动生成的方法存根
camera=Camera.open();//打开相机,获得相机对象
try
{
Camera.Parameters param=camera.getParameters();//获得支持的一些参数
//获得支持的预览大小,设置不支持的大小会出现异常
List<Camera.Size> preSizes=param.getSupportedPreviewSizes();
for(Camera.Size s:preSizes){
Log.i("SupportedPreviewSize:", s.height+"X"+s.width);
}//可以在日志中看到支持的预览大小,从而根据数值设置正确的预览大小
//设置支持的照片大小,设置不支持的大小会出现异常
List<Camera.Size> picSizes=param.getSupportedPictureSizes();
for(Camera.Size s:picSizes){
Log.i("SupportedPictureSize:", s.height+"X"+s.width);
}//可以在日志中看到支持的预览大小
param.setPreviewSize(320, 240); //设置预览大小
param.setPictureFormat(PixelFormat.JPEG);//设置照片格式
param.setPictureSize(800, 480);//设置照片大小
param.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setParameters(param);//参数传递给相机对象
camera.setPreviewDisplay(holder);//相机预览显示在SurfaceView上
camera.startPreview();
}
catch(IOException e)
{
e.printStackTrace();
}
}
protected void takePicture() {
// TODO 自动生成的方法存根
if(camera!=null)
camera.takePicture(null, null, jpeg);
}
//jpg格式的照片处理接口,作为一个参数传递给takePicture()函数
PictureCallback jpeg = new PictureCallback() {
//第一个参数是照片的字节数组数据,强转为位图类型
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO 自动生成的方法存根
Bitmap bm=BitmapFactory.decodeByteArray(data, 0, data.length);
String path="/sdcard/camera.jpg";
File file=new File(path);
try
{
FileOutputStream fos=new FileOutputStream(file);
BufferedOutputStream bos=new BufferedOutputStream(fos);//流对象
bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);//保存图片
bos.flush();
bos.close();//关闭流
iv.setImageBitmap(bm);//显示照片
camera.stopPreview();
camera.release();
}
catch(Exception e){
e.printStackTrace();
}
}
};
//SurfaceHolder的3个回调接口
public void surfaceChanged(SurfaceHolder arg0,int arg1,int arg2,int arg3)
{
if(camera!=null){
camera.release();
}
}
public void surfaceCreated(SurfaceHolder arg0)
{
}
public void surfaceDestroyed(SurfaceHolder arg0)
{
if(camera!=null){
camera.release();
camera=null;
}
}
}
特别注意:Activity要实现SurfaceHolder.callback的回调接口。
另外,照片预览的大小设置必须设置正确,不同机型可能会有差异,在日志中查看正确值。
自动对焦功能,可在preview后自动对焦,并拍照。但此处运用的效果不是很好。