Android 自定义相机开发(支持前置,后置摄像头,可以自动聚焦,保存和显示图片)

来源:互联网 发布:什么天气软件最准确 编辑:程序博客网 时间:2024/04/30 10:03

实现功能:
自定义相机开发:支持前置,后置摄像头切换,可以自动聚焦,保存图片和显示图片

实现代码:
一,布局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() {// 该方法用于处理拍摄后的照片数据@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {// TODO Auto-generated method stubSystem.out.println("----->> onAutoFocus ");}};private Button mSwitchCamera;@Overridepublic 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() {@Overridepublic 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);}/** * 触屏事件 */@Overridepublic 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);}/** * 相机拍照结束事件 */@Overridepublic 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();}/** * 拍摄时自动对焦事件 */@Overridepublic 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;}}@Overridepublic 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;}}/*  * 触摸屏幕对焦事件 */@Overridepublic 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;@Overrideprotected 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 stubIntent intent = new Intent(this, CameraActivity.class);startActivityForResult(intent, REQUEST_CAPTURE_PIC);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if(requestCode == REQUEST_CAPTURE_PIC){//拍照回来的if(data != null){Bundle bundle = data.getExtras();// 获得照片uriUri 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 stubiv_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






1 1