安卓自定义相机的实现
2016-07-04 15:27
411 查看
安卓本身封装了相机Camera类,一般情况下应用如果有拍照的需求,实现可以分为两种:
1.通过调用系统相机来实现拍照功能
2.通过实现自定义相机来实现拍照功能。
第一种我们就不阐述了,主要讲第二种自定义相机。
1.定义CameraPreview
不懂SurfaceView用法的请先熟悉SurfaceView再继续读这篇文章。
CameraPreview的定义大致分为以下几步:
在构造方法中得到Holder和为holder添加callBack
定义相机状态的回调接口
在surfaceCreated的时候初始化相机
在surfaceDestroyed的时候释放相机
切换相机
拍照
需要定义几个回调:
2.定义CameraActivity调用
xml:
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; } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories