前言:
在android开发中intent启动系统默认相机就能解决打不分的需求。但是对于一些有特殊要求的app,我们就需要自己实现一个拍照页面了。
其中重要知识点:
SurfaceView:用来显示拍照前预览的图像,使用方法让Activity继承SurfaceHolder.Callback接口,并实现他的三个方法(surfaceCreated,surfaceCreated和surfaceDestroyed)。
Camera:Camera对象用来获取显示的图像,其中camera.takePicture()是拍照方法,他的参数中PictureCallback()的回掉函数中的byte[] data是返回的图片数据
public classMainActivity extends Activityimplements SurfaceHolder.Callback{
布局文件:
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<SurfaceView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/surfaceview"/>
<Button
android:id="@+id/aaa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="100dp"
android:layout_marginStart="100dp"
android:text="拍照"/>
<Button
android:id="@+id/bbb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="聚焦"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/aaa"
android:layout_toEndOf="@+id/aaa"/>
</RelativeLayout>
java代码文件:
packagecom.example.administrator.xiaofang_jinan;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Environment;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class MainActivityextends Activity implementsSurfaceHolder.Callback{
private staticContext context =null;
private SurfaceViewsurfaceview;
private SurfaceHoldersurfaceholder;
private Cameracamera =null;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context= this;
surfaceview= (SurfaceView)findViewById(R.id.surfaceview);
surfaceholder= surfaceview.getHolder();
surfaceholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceholder.addCallback(MainActivity.this);
init();
}
private voidinit() {
//拍照
Button button= (Button) findViewById(R.id.aaa);
button.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View v) {
camera.takePicture(newCamera.ShutterCallback() {
@Override
public voidonShutter() {
}
}, newCamera.PictureCallback() {
@Override
public voidonPictureTaken(byte[] data,Camera camera) {
}
}, newCamera.PictureCallback() {
@Override
public voidonPictureTaken(byte[] data,Camera camera) {
String path = Environment.getExternalStorageDirectory() +"/test.jpg";
try {
data2file(data,path);
}catch (Exception e) {
Log.d("aabccdd","进入catch");
e.printStackTrace();
}
}
});
}
});
//聚焦
Button bbb= (Button) findViewById(R.id.bbb);
bbb.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View v) {
//自动聚焦
camera.autoFocus(null);
}
});
}
@Override
public voidsurfaceCreated(SurfaceHolder holder) {
//获取camera对象
camera= Camera.open();
try {
//获取camera参数(参数集合)
Camera.Parameters parameters =camera.getParameters();
//判断手机横向或纵向(手机竖着时图像是反的,需要旋转图像)
if(this.getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation","portrait");
camera.setDisplayOrientation(90);
parameters.setRotation(90);
}else {
parameters.set("orientation","landscape");
camera.setDisplayOrientation(0);
parameters.setRotation(0);
}
//获取图片分辨率(拍照的图片的分辨率是需要设置的,而且不能随便设置,不同的摄像头支持的分辨率不同,随便设置会报错)
Camera.Size psize=parameters(camera);
if(psize!=null)
//设置照片的分辨率(不设置照片可能会模糊)
parameters.setPictureSize(psize.width,psize.height);
//将参数设置给camera对象
camera.setParameters(parameters);
//设置预览监听
camera.setPreviewDisplay(holder);
//启动摄像头预览
camera.startPreview();
}catch (IOException e) {
e.printStackTrace();
camera.release();
}
}
@Override
public voidsurfaceChanged(SurfaceHolder holder, intformat, intwidth, intheight) {
}
@Override
public voidsurfaceDestroyed(SurfaceHolder holder) {
if(camera!= null) {
//停止浏览
camera.stopPreview();
camera.release();
}
}
/**
* 将数据保存为文件
* @paramw
*@param fileName
*@throws Exception
*/
private voiddata2file(byte[] w,String fileName) throws Exception {//将二进制数据转换为文件的函数
FileOutputStream out =null;
try {
out =newFileOutputStream(fileName);
out.write(w);
out.close();
}catch (Exception e) {
Log.d("aabccdd","进入catch222");
if (out !=null)
out.close();
throw e;
}
}
/**
* 获取要保存的图片的分辨率(这里在相机支持的分辨率中,找了个最大的)(分辨率一般都是宽>高)
* @paramcamera
*@return
*/
publicCamera.Size parameters(Camera camera) {
//照片支持的分辨率列表
List<Camera.Size> pictureSizes = camera.getParameters().getSupportedPictureSizes();
//预览画面的分辨率列表
//List<Camera.Size> previewSizes = camera.getParameters().getSupportedPreviewSizes();
Camera.Size psize;
Camera.Size maxpsize=null;
for (inti = 0;i < pictureSizes.size();i++) {
psize = pictureSizes.get(i);
Log.i("pictureSize","aaaaa"+psize.width+" x "+psize.height);
if(maxpsize==null||maxpsize.width<psize.width){
maxpsize=psize;
}
}
// for (int i = 0; i < previewSizes.size(); i++) {
// psize = previewSizes.get(i);
// Log.i("previewSize","bbbbb"+psize.width+" x "+psize.height);
// }
returnmaxpsize;
}
}
遇到的问题:
在开发时发现预览时画面是清楚的,但是拍照保存后,照片迷糊不清,就像被高度压缩了似得。
在网上查了查觉得应该是因为图片分辨率问题,于是手动设置了几个分辨率,也通过windowmessge获取屏幕分辨率,但是一到camera.setParameters(parameters);就会报异常。
最后找到原因,是因为自己设置的分辨率,相机不一定支持。
解决方法:
List<Camera.Size> pictureSizes = camera.getParameters().getSupportedPictureSizes();
获取相机支持像素列表,从中选一个,就不报错了。运行拍照,保存的图片是清除的。
效果图: