实现功能:
自定义相机开发:支持前置,后置摄像头切换,可以自动聚焦,保存图片和显示图片
实现代码:
一,布局activity_camera.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.camerademo.view.CameraPreview
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/focusView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<Button
android:id="@+id/btn_take_picture"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="@drawable/btn_camera_default" />
<Button
android:id="@+id/btn_swich_camera"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:background="@drawable/ic_switch_camera" />
</RelativeLayout>
三,CameraPreview.java
package com.example.camerademo.view;
import java.io.IOException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
*@Description:
* @author zhuzhifeng
* @date 2016年3月18日 上午9:20:41
*/
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView
implements SurfaceHolder.Callback {
/** LOG标识 */
// private static final String TAG = "CameraPreview";
/** 分辨率 */
public static final int WIDTH = 1024;
public static final int HEIGHT = 768;
/** 监听接口 */
private OnCameraStatusListener listener;
private SurfaceHolder holder;
private Camera camera;
private int cameraPosition = 1;//0代表前置摄像头,1代表后置摄像头
// 创建一个PictureCallback对象,并实现其中的onPictureTaken方法
private PictureCallback pictureCallback = new PictureCallback() {
// 该方法用于处理拍摄后的照片数据
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 停止照片拍摄
camera.stopPreview();
camera = null;
// 调用结束事件
if (null != listener) {
listener.onCameraStopped(data);
}
}
};
private PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] _data, Camera _camera) {
/* 要处理raw data?写?否 */
}
};
/*为了实现拍照的快门声音及拍照保存照片需要下面三个回调变量*/
ShutterCallback myShutterCallback = new ShutterCallback()
//快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
{
public void onShutter() {
// TODO Auto-generated method stub
}
};
/*public AutoFocusCallback autoFocusCallback = new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
System.out.println("----> onAutoFocus");
}
};*/
// Preview类的构造方法
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
// 获得SurfaceHolder对象
holder = getHolder();
// 指定用于捕捉拍照事件的SurfaceHolder.Callback对象
// 只要是实现SurfaceHolder.Callback接口的对象都行
holder.addCallback(this);
// 设置SurfaceHolder对象的类型
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
// 在surface创建时激发
public void surfaceCreated(SurfaceHolder holder) {
// Log.e(TAG, "==surfaceCreated==");
try {
initCamera();
if (null != listener) {
listener.onTouchFocus(camera);
}
} catch (IOException e) {
e.printStackTrace();
// 释放手机摄像头
camera.release();
camera = null;
}
}
// 在surface销毁时激发
public void surfaceDestroyed(SurfaceHolder holder) {
// Log.e(TAG, "==surfaceDestroyed==");
if (camera != null) {
camera.setPreviewCallback(null); /*在启动PreviewCallback时这个必须在前不然退出出错。
这里实际上注释掉也没关系*/
camera.stopPreview();
// 释放手机摄像头
camera.release();
}
}
// 在surface的大小发生改变时激发
public void surfaceChanged(final SurfaceHolder holder, int format, int w, int h) {
}
/**
* @throws IOException
*
*/
protected void initCamera() throws IOException {
// 获得Camera对象
camera = Camera.open();
// 设置用于显示拍照摄像的SurfaceHolder对象
camera.setPreviewDisplay(holder);
// 获取照相机参数
Camera.Parameters parameters = camera.getParameters();
// 设置照片格式
parameters.setPictureFormat(PixelFormat.JPEG);
//parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);//加上闪光灯模式会报错
// 1连续对焦
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
// 设置预浏尺寸
parameters.setPreviewSize(WIDTH, HEIGHT);
// 设置照片分辨率
parameters.setPictureSize(WIDTH, HEIGHT);
//
// //设置大小和方向等参数
// parameters.setPictureSize(1280, 960);
// parameters.setPreviewSize(960, 720);
// 设置照相机参数
camera.setParameters(parameters);
// 开始拍照
camera.startPreview();
camera.cancelAutoFocus();// 一定要加上这句,才可以连续聚集
}
// 停止拍照,并将拍摄的照片传入PictureCallback接口的onPictureTaken方法
public void takePicture(boolean isAutoFocus) {
// Log.e(TAG, "==takePicture==");
if (camera != null) {
if (true == isAutoFocus) {
// 自动对焦
camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (null != listener) {
listener.onAutoFocus(success);
}
// 自动对焦成功后才拍摄
if (success) {
camera.takePicture(myShutterCallback, rawCallback, pictureCallback);
}
}
});
} else {
camera.takePicture(myShutterCallback, rawCallback, pictureCallback);
}
}
}
// 设置监听事件
public void setOnCameraStatusListener(OnCameraStatusListener listener) {
this.listener = listener;
}
/**
* 相机拍照监听接口
*/
public interface OnCameraStatusListener {
// 相机拍照结束事件
void onCameraStopped(byte[] data);
// 拍摄时自动对焦事件
void onAutoFocus(boolean success);
// 触摸屏幕对焦事件
void onTouchFocus(Camera mCamera);
}
/**
* 选择前置还是后置摄像头
*/
@SuppressLint("NewApi")
public void switchCamera() {
//切换前后摄像头
int cameraCount = 0;
CameraInfo cameraInfo = new 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后置
camera.stopPreview();//停掉原来摄像头的预览
camera.release();//释放资源
camera = null;//取消原来摄像头
camera = Camera.open(i);//打开当前选中的摄像头
try {
camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();//开始预览
cameraPosition = 0;
break;
}
} else {
//现在是前置, 变更为后置
if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置
camera.stopPreview();//停掉原来摄像头的预览
camera.release();//释放资源
camera = null;//取消原来摄像头
camera = Camera.open(i);//打开当前选中的摄像头
try {
camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();//开始预览
cameraPosition = 1;
break;
}
}
}
}
// /**
// * 打开默认摄像头
// */
// public void openCamera() {
// int cameraId = CameraHelper.getFutureCameraId(mActivity);
// openCamera(cameraId);
// }
}
四,CameraActivity.java
package com.example.camerademo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import com.example.camerademo.view.CameraPreview;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
/**
*@Description:
* @author zhuzhifeng
* @date 2016年3月18日 上午9:34:25
*/
public class CameraActivity extends Activity
implements CameraPreview.OnCameraStatusListener,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 AutoFocusCallback autofocuscallback = new 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 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(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 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(20, intent);
finish();
}
/**
* 拍摄时自动对焦事件
*/
@Override
public void onAutoFocus(boolean success) {
// 改变对焦状态图像
if (success) {
focusView.setImageResource(R.drawable.right);
} else {
focusView.setImageResource(R.drawable.wrong);
Toast.makeText(this, "焦距不准,请重拍!", Toast.LENGTH_SHORT).show();
isTaking = false;
}
}
@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 onTouchFocus(Camera mCamera){
camera = mCamera;
}
}
五,MainActivity.java
package com.example.camerademo;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends Activity {
private final int REQUEST_CAPTURE_PIC = 100;//拍照请求标识
private ImageView iv_show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_show = (ImageView)findViewById(R.id.iv_show);
startCapture();
}
/**
*
*/
private void startCapture() {
// TODO Auto-generated method stub
Intent intent = new Intent(this, CameraActivity.class);
startActivityForResult(intent, REQUEST_CAPTURE_PIC);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_CAPTURE_PIC){//拍照回来的
if(data != null){
Bundle bundle = data.getExtras();
// 获得照片uri
Uri uri = Uri.parse(bundle.getString("uriStr"));
// 获得拍照时间
long dateTaken = bundle.getLong("dateTaken");
try {
// 从媒体数据库获取该照片
Bitmap cameraBitmap = MediaStore.Images.Media.getBitmap(
getContentResolver(), uri);
previewBitmap(cameraBitmap); // 预览图像
// 从媒体数据库删除该照片(按拍照时间)
getContentResolver().delete(
CameraActivity.IMAGE_URI,
MediaStore.Images.Media.DATE_TAKEN + "="
+ String.valueOf(dateTaken), null);
} catch (Exception e) {
e.printStackTrace();
}
}else{
}
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* @param cameraBitmap
*/
private void previewBitmap(Bitmap cameraBitmap) {
// TODO Auto-generated method stub
iv_show.setImageBitmap(cameraBitmap);
}
public void BtnTakePicture(View v){
startCapture();
}
}
六:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.camerademo"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.camerademo.CameraActivity" >
</activity>
</application>
</manifest>
几点需要注意:
1)如果项目运行出错,也许是屏幕适配的问题
我这里用的是小米平板,如果你想用手机,需要修改在CameraPreview中的代码,修改如下:
// 设置预浏尺寸
// parameters.setPreviewSize(WIDTH, HEIGHT);
// // 设置照片分辨率
// parameters.setPictureSize(WIDTH, HEIGHT);
//
//设置大小和方向等参数
parameters.setPictureSize(1280, 960);
parameters.setPreviewSize(960, 720);
2)自动聚焦关键代码:
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
CameraPreview.java中,如果你去掉了上面这句代码,就不能自动聚焦,只能手动点击屏幕,聚集了
源码下载地址:
http://download.csdn.net/detail/shakdy/9476207