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

安卓自定义相机的实现

2016-07-04 15:27 411 查看
安卓本身封装了相机Camera类,一般情况下应用如果有拍照的需求,实现可以分为两种:

1.通过调用系统相机来实现拍照功能



2.通过实现自定义相机来实现拍照功能。

第一种我们就不阐述了,主要讲第二种自定义相机。

1.定义CameraPreview

public class CameraPreview extends SurfaceView  implements SurfaceHolder.Callback{


不懂SurfaceView用法的请先熟悉SurfaceView再继续读这篇文章。

CameraPreview的定义大致分为以下几步:

在构造方法中得到Holder和为holder添加callBack
// Preview类的构造方法
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
// 获得SurfaceHolder对象
mHolder = getHolder();
// 指定用于捕捉拍照事件的SurfaceHolder.Callback对象
// 只要是实现SurfaceHolder.Callback接口的对象都行
mHolder.addCallback(this);
// 设置SurfaceHolder对象的类型
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

定义相机状态的回调接口
/** 相机拍照监听接口 */
private OnCameraStatusListener listener;

public interface OnCameraStatusListener {

// 相机拍照结束事件
void onCameraStopped(byte[] data);

// 拍摄时自动对焦事件
void onAutoFocus(boolean success);

// 触摸屏幕对焦事件
void onTouchFocus(Camera mCamera);
}

在surfaceCreated的时候初始化相机
// 在surface创建时激发
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG, "==surfaceCreated==");
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
// 释放手机摄像头
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}

protected void initCamera() throws IOException {
initCamera(0);
}

protected void initCamera(int i) throws IOException{
// 获得Camera对象
mCamera = Camera.open(i);
// 设置竖屏
mCamera.setDisplayOrientation(90);
// 获取照相机参数
Camera.Parameters parameters = mCamera.getParameters();
// 设置照片格式
parameters.setPictureFormat(PixelFormat.JPEG);
//parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);//加上闪光灯模式会报错
// 1连续对焦
//        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
// 设置预浏尺寸
//        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);//获取窗口的管理器
//        Display display = wm.getDefaultDisplay();//获得窗口里面的屏幕
List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();// 选择合适的预览尺寸
if (sizeList.size() >= 1) {
Iterator<Camera.Size> itor = sizeList.iterator();
while (itor.hasNext()) {
Camera.Size cur = itor.next();
if (cur.width >= previewWidth
&& cur.height >= previewHeight) {
previewWidth = cur.width;
previewHeight = cur.height;
break;
}
}
}
parameters.setPreviewSize(previewWidth, previewHeight);
// 设置照片分辨率
parameters.setPictureSize(previewWidth, previewHeight);
// 设置照相机参数
mCamera.setParameters(parameters);
// 设置用于显示拍照摄像的SurfaceHolder对象
mCamera.setPreviewDisplay(mHolder);
// 开始拍照
mCamera.startPreview();
mCamera.cancelAutoFocus();// 一定要加上这句,才可以连续聚集

if (null != listener) {
listener.onTouchFocus(mCamera);
}
}

在surfaceDestroyed的时候释放相机
// 在surface销毁时激发
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "==surfaceDestroyed==");
if (mCamera != null) {
mCamera.setPreviewCallback(null); /*在启动PreviewCallback时这个必须在前不然退出出错。
这里实际上注释掉也没关系*/
mCamera.stopPreview();
// 释放手机摄像头
mCamera.release();
mCamera = null;
}
}

切换相机
public void switchCamera() {
//切换前后摄像头
int cameraCount = 0;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数

for(int i = 0; i < cameraCount; i++) {
Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
if(cameraPosition == 1) {
//现在是后置,变更为前置
if(cameraInfo.facing  == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置
mCamera.setPreviewCallback(null);
mCamera.stopPreview();//停掉原来摄像头的预览
mCamera.release();//释放资源
mCamera = null;//取消原来摄像头

try {
initCamera(i);//打开当前选中的摄像头
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cameraPosition = 0;
break;
}
} else {
//现在是前置, 变更为后置
if(cameraInfo.facing  == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位,CAMERA_FACING_FRONT前置      CAMERA_FACING_BACK后置
mCamera.setPreviewCallback(null);
mCamera.stopPreview();//停掉原来摄像头的预览
mCamera.release();//释放资源
mCamera = null;//取消原来摄像头

try {
initCamera(i);//打开当前选中的摄像头
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cameraPosition = 1;
break;
}
}

}
}


拍照

需要定义几个回调:

/*为了实现拍照的快门声音及拍照保存照片需要下面三个回调变量*/
Camera.ShutterCallback myShutterCallback = new Camera.ShutterCallback()
//快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
{

public void onShutter() {
// TODO Auto-generated method stub

}
};

private Camera.PictureCallback rawCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] _data, Camera _camera) {
/* 要处理raw data?写?否 */
}
};

// 创建一个PictureCallback对象,并实现其中的onPictureTaken方法
private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {

// 该方法用于处理拍摄后的照片数据
@Override
public void onPictureTaken(byte[] data, Camera camera) {

// 停止照片拍摄
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;

// 调用结束事件
if (null != listener) {
listener.onCameraStopped(data);
}
}
};


// 停止拍照,并将拍摄的照片传入PictureCallback接口的onPictureTaken方法
public void takePicture(boolean isAutoFocus) {
Log.e(TAG, "==takePicture==");
if (mCamera != null) {
if (true == isAutoFocus) {
// 自动对焦
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (null != listener) {
listener.onAutoFocus(success);
}
// 自动对焦成功后才拍摄
if (success) {
camera.takePicture(myShutterCallback, rawCallback, pictureCallback);
}
}
});
} else {
mCamera.takePicture(myShutterCallback, rawCallback, pictureCallback);
}
}
}


2.定义CameraActivity调用

xml:

<?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">

<com.example.myapp.view.CameraPreview
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button android:id="@+id/btn_take_picture"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/circle_blue_trans"
android:layout_marginBottom="20dp"/>

<Button android:id="@+id/btn_swich_camera"
android:layout_width="60dp"
android:layout_height="30dp"
android:background="@drawable/blue_cornor_bg"
android:text="Switch"
android:layout_alignParentRight="true"
android:layout_margin="20dp"/>

<ImageView android:id="@+id/focusView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerInParent="true"/>
</RelativeLayout>

public class CameraActivity extends Activity implements CameraPreview.OnCameraStatusListener,View.OnClickListener {

public static final Uri IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
public static final String PATH = Environment.getExternalStorageDirectory().toString() + "/AndroidMedia/";

private CameraPreview mCameraPreview;
private ImageView focusView;
private boolean isTaking = false; // 拍照中
private boolean isAutoFocus;// 是否自动对焦
private Button mBtnTakePicture;
private Camera camera;
private Camera.AutoFocusCallback autofocuscallback = new Camera.AutoFocusCallback() {

@Override
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
System.out.println("----->> onAutoFocus ");
}
};
private Button mSwitchCamera;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置横屏
//        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 照相预览界面
setContentView(R.layout.activity_camera);
// 照相预览界面
mCameraPreview = (CameraPreview) findViewById(R.id.preview);
mBtnTakePicture = (Button)findViewById(R.id.btn_take_picture);
mSwitchCamera = (Button)findViewById(R.id.btn_swich_camera);
mSwitchCamera.setOnClickListener(this);

mCameraPreview.setOnCameraStatusListener(this);
mCameraPreview.setOnTouchListener(new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isTaking) {
if(camera != null){
camera.autoFocus(autofocuscallback);
System.out.println("----> onTouch");
}

}
return false;

}
});

mBtnTakePicture.setOnClickListener(this);
// 焦点图片
focusView = (ImageView) findViewById(R.id.focusView);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
isAutoFocus = prefs.getBoolean("preferences_autoFocus", false);
}

/**
* 触屏事件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && !isTaking) {
//          isTaking = true;
//          mCameraPreview.takePicture(isAutoFocus);
}
return super.onTouchEvent(event);
}

/**
* 存储图像并将信息添加入媒体数据库
*/
private Uri insertImage(ContentResolver cr, String name, long dateTaken, String directory, String filename,
Bitmap source, byte[] jpegData) {

OutputStream outputStream = null;
String filePath = directory + filename;
try {
File dir = new File(directory);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(directory, filename);
if (file.createNewFile()) {
outputStream = new FileOutputStream(file);
if (source != null) {
source.compress(Bitmap.CompressFormat.JPEG, 75, outputStream);
} else {
outputStream.write(jpegData);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
}
}
}
ContentValues values = new ContentValues(7);
values.put(MediaStore.Images.Media.TITLE, name);
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATA, filePath);
return cr.insert(IMAGE_URI, values);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_take_picture:
isTaking = true;
mCameraPreview.takePicture(isAutoFocus);
break;
case R.id.btn_swich_camera:
mCameraPreview.switchCamera();
break;
default:
break;
}

}

/**
* 相机拍照结束事件
*/
@Override
public void onCameraStopped(byte[] data) {
Log.e("onCameraStopped", "==onCameraStopped==");

// 创建图像
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// 系统时间
long dateTaken = System.currentTimeMillis();
// 图像名称
String filename = DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken).toString() + ".jpg";
// 存储图像(PATH目录)
Uri uri = insertImage(getContentResolver(), filename, dateTaken, PATH, filename, bitmap, data);
// 返回结果
Intent intent = getIntent();
intent.putExtra("uriStr", uri.toString());
intent.putExtra("dateTaken", dateTaken);
// intent.putExtra("filePath", PATH + filename);
// intent.putExtra("orientation", orientation);  // 拍摄方向
setResult(Activity.RESULT_OK, intent);

finish();
}

/**
* 拍摄时自动对焦事件
*/
@Override
public void onAutoFocus(boolean success) {
// 改变对焦状态图像
if (success) {
focusView.setImageResource(R.drawable.f000);
} else {
focusView.setImageResource(R.drawable.f006);
Toast.makeText(this, "焦距不准,请重拍!", Toast.LENGTH_SHORT).show();
isTaking = false;
}
}

/**
* 触摸屏幕对焦事件
*/
@Override
public void onTouchFocus(Camera mCamera){
camera = mCamera;
}

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