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
- Android 自定义相机开发(支持前置,后置摄像头,可以自动聚焦,保存和显示图片)
- android打开前置摄像头和后置摄像头
- android打开前置摄像头和后置摄像头 .
- android打开前置摄像头和后置摄像头
- Android自定义相机(二) —— 前置摄像头
- 前置摄像头、后置摄像头
- android自定义相机 前置摄像头拍照,照片旋转180
- OpenCV Android 打开前置后置摄像头
- HTML5调用手机前置摄像头或后置摄像头拍照,canvas显示,经过Android测试
- Android 自定义相机保存图片
- Android 自定义相机保存图片
- android自定义相机、连续(自动)聚焦、点击(触摸)聚焦、变焦、拍照后自定义裁剪、旋转
- 自定义相机,使用前置摄像头实现自拍
- IOS获取设备的前置摄像头和后置摄像头
- Android自定义相机定点聚焦
- 重载 ++ , - - (前置 和 后置)
- 安卓自动选择调用前置或后置摄像头
- Android开发 摄像头自动聚焦完美实现 --------------续上
- 抽象类和接口
- Spring与redis的集成的笔记
- LayoutInflater
- spring实现AOP的两种方式以及实现动态代理方式
- 数据转换工具类汇总
- Android 自定义相机开发(支持前置,后置摄像头,可以自动聚焦,保存和显示图片)
- Linux安装Tomcat
- 数据库SQL优化大总结之 百万级数据库优化方案
- OSG播放fbx动画
- mysql_cluster体系结构
- C# System.DateTime.Now.ToString("yyyyMMdd")
- SSL认证填平免费WiFi的陷阱
- Struts表单校验插件:Validator框架
- LINUX 段错误查找记录 -- segfault at fffffffffffffff9 ip 0000003c97e7b81c sp 00007fffad7c0638 error 4 in lib