安卓自定义相机的实现

安卓本身封装了相机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;
    }


}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值