Camera开发—如何自定义相机

1,118 阅读2分钟

自定义摄像头预览功能

github源码

权限

动态权限略

<uses-permission android:name="android.permission.CAMERA" />

代码

  1. 使用SurfaceView

这里不能使用普通的View,因为要实时地显示摄像头捕获到的图像,简单来说View适合被动刷新的情况,SurfaceView适合主动刷新(在子线程里),其余的不多说了

  1. 获取相机

import android.hardware.Camera;

注意camera导包到这个,虽然过时了

    private Camera getCamera() {
        Camera camera;
        try {
            camera = Camera.open();
        } catch (Exception e) {
            camera = null;
        }

        return camera;
    }
  1. 开始预览图像
    private void setStartPreView(Camera camera, SurfaceHolder holder) {
        try {
            //把camera捕获到的图像显示在SurfaceView里
            camera.setPreviewDisplay(holder);
            //将预览效果横屏转为竖直的camera
            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  1. 释放相机,必须在ondestroy销毁
    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
  1. 把相机的操作与SurfaceView生命周期绑定起来
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //开始预览
        setStartPreView(mCamera, mHolder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 当改变时候,先停止预览
        mCamera.stopPreview();
        //再次开始预览
        setStartPreView(mCamera, mHolder);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 释放掉相机
        releaseCamera();
    }

  1. Camera绑定Activity生命周期
    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();
    }


    @Override
    protected void onResume() {
        super.onResume();
        if (mCamera == null) {
            mCamera = getCamera();
            if (mHolder != null) {
                setStartPreView(mCamera, mHolder);
            }
        }
    }
  1. 调用这些方法
public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private SurfaceView mPreview;
    private Camera mCamera;
    private SurfaceHolder mHolder;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        mPreview = (SurfaceView) findViewById(R.id.surface);

        mHolder = mPreview.getHolder();
        mHolder.addCallback(this);
        mPreview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCamera.autoFocus(null);//点击屏幕自动对焦
            }
        });

    }

至此,你的应用已经具备摄像头预览功能了,点击屏幕会自动对焦

拍照功能

  1. 开始拍照
 public void capture(View view) {

        Camera.Parameters parameters = mCamera.getParameters();

        parameters.setPictureFormat(ImageFormat.JPEG);
        // 设定预览尺寸
        parameters.setPreviewSize(900, 300);
        // 对焦模式 自动
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        // 自动对焦的回调
        mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                if (success) {
                    // 自动对焦成功后,拍照,会走mPictureCallback回调
                    mCamera.takePicture(null, null, mPictureCallback);
                }
            }
        });
    }
  1. 拍照成功后的回调
private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {


            String mFilePath = Environment.getExternalStorageDirectory().getPath();
            mFilePath = mFilePath + "/" + "temp.png";
            File tempFile = new File(mFilePath);

            try {
                // 拿着byte[] data,写入图片文件
                FileOutputStream fos = new FileOutputStream(tempFile);
                fos.write(data);
                fos.close();

                // 我们将打开新的activity,把图片地址传递给下一个activity
                Intent intent = new Intent(CameraActivity.this, ResultActivity.class);
                intent.putExtra("picPatch", tempFile.getAbsolutePath());
                startActivity(intent);

                finish();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };
  1. 在新的activity里显示照片
public class ResultActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_result);
        
        String path = getIntent().getStringExtra("picPatch");
        ImageView iv = (ImageView) findViewById(R.id.iv);

        try {
    // 通过matrix把原图旋转90度,因为在拍照的时候,旋转了90度  
    //,所以现在也要旋转,不然图片是横着的
            FileInputStream fis = new FileInputStream(path);
            Bitmap bitmap = BitmapFactory.decodeStream(fis);
            Matrix matrix = new Matrix();
            matrix.setRotate(90);
            
            bitmap = Bitmap.createBitmap(
                bitmap, 0, 0, 
                bitmap.getWidth(), 
                bitmap.getHeight(), 
                matrix, 
                true);
            
            iv.setImageBitmap(bitmap);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}