Android常用控件之 - Camera

本文详细介绍了在Android中如何调用系统相机以及自定义相机的实现步骤,包括通过startActivityForResult获取拍照原图,使用SurfaceView与SurfaceHolder绑定相机,设置拍照参数并处理拍照后的图像旋转问题。同时强调了自定义相机需要获取相机权限,而调用系统相机则不需要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处amoscxy的博客:https://mp.youkuaiyun.com/mdeditor/79117522

一 调用系统相机

(1)调用系统相机是用过滤规则匹配的方式,系统相机设置了 规则,因此调用相机秩序action匹配:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivity(intent);

(2)想要获取拍照图片,可以通过startActivityForResult … onActivityResult来实现

public void aCamera(View view) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, REQ_1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == REQ_1) {
                if (data != null) {
                    Bundle bundle = data.getExtras();
                    Bitmap bitmap = (Bitmap) bundle.get("data");
                    mImageView.setImageBitmap(bitmap);
                }
            }
        }
    }

需要注意的是,为防止图片太大,导致内存溢出,bundle.get(“data”)返回的图片只是缩略图,质量比较差,要想通过系统相机获得拍照原图,需要通过intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);修改系统相机拍照图片保存的路径,再从路径获取原图。

public void aCamera2(View view) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    Uri photoUri = Uri.fromFile(new File(mFilePath));
    intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);
    startActivityForResult(intent, REQ_2);
}

mFIlePath最好是sd卡中的目录,如:mFilePath = Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".png";,要将图片保存到sd卡上需要读写权限

可以通过文件流读写方式获取图片流,并转换成图片:

FileInputStream fis = new FileInputStream(mFilePath);
Bitmap bitmap = BitmapFactory.decodeStream(fis);

此处得到的图片bitmap是拍照的原图。
具体为:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        ...
        if(requestCode == REQ_2){
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(mFilePath);
                Bitmap bitmap = BitmapFactory.decodeStream(fis);
                mImageView.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }finally {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

大部分时候系统相机不能满足我们的需求,因此掌握自定义相机是很必要的

二 自定义相机

需要完成三步:
(1)通过Camera.open()获取相机(Camera)对象,

/**
* 获取Camera对象
* @return
*/
private Camera getCamera(){
   Camera camera;
   try {
       camera = Camera.open();
   } catch (Exception e) {
       camera = null;
       e.printStackTrace();
   }
   return camera;
}

(2)通过camera.setPreviewDisplay(holder),将Camera与SurfaceHolder进行绑定,开始预览相机内容,

/**
 * 开始预览相机内容
 */
private void setStartPreview(Camera camera,SurfaceHolder holder){
    try {
        // 将Camera与SurfaceHolder进行绑定
        camera.setPreviewDisplay(holder);
        // 将系统Camera预览角度进行调整(默认预览是横屏的)
        camera.setDisplayOrientation(90);
        // 开始预览
        camera.startPreview();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

(3)释放相机资源

/**
 * 释放相机资源
 */
private void releaseCamera(){
    if(mCamera != null){
        mCamera.setPreviewCallback(null); // 将相机的回调置空
        try {
            mCamera.setPreviewDisplay(null); // 取消Camera与SurfaceHolder的关联
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.stopPreview(); // 取消相机取景功能
        mCamera.release(); // 释放相机占用的系统资源
        mCamera = null;
    }
}

由于相机是系统持有的资源,因此以上三个步骤需要与Activity的生命周期onResume()和onPause()进行绑定:

@Override
protected void onResume() {
    super.onResume();
    if(mCamera == null){
        mCamera = getCamera(); // 获取Camera对象
        if(mHolder != null){
            setStartPreview(mCamera,mHolder); // 开始预览相机内容
        }
    }
}

@Override
protected void onPause() {
    super.onPause();
    releaseCamera(); // 释放相机资源
}

注意要用SurfaceView来实现相机的预览功能,并通过SurfaceHolder来对SurfaceView进行管理:

实现SurfaceHolder.Callback接口,来对相机预览进行回调,

SurfaceView mPreview = findViewById(R.id.preview);
SurfaceHolder mHolder = mPreview.getHolder();
mHolder.addCallback(this);

实现回调的三个方法:

// 开始预览是调用
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
    setStartPreview(mCamera,mHolder); // 开始预览
}

// 预览改变是调用
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
    mCamera.stopPreview(); // 停止预览
    setStartPreview(mCamera,mHolder); // 开始预览
}

// 预览结束时调用
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    releaseCamera(); // 释放相机资源
}

实现自定义相机的拍照功能:
与我们拿着单反拍照时要设置光圈、快门等相同,自定义相机拍照前也要通过Camera.Parameters的各种set***方法设置拍照参数:

/**
 * 实现拍照功能
 * @param view
 */
public void capture(View view){
    // 拍照前要对Camera进行参数设置
    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setPictureFormat(ImageFormat.JPEG); // 设置拍照的模式
    parameters.setPreviewSize(800,400); // 设置预览大小
    if(parameters.getFocusMode().contains(Camera.Parameters.FOCUS_MODE_AUTO)){
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 设置为自动对焦
    }
    mCamera.autoFocus(new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean b, Camera camera) {
            if(b){ // 对焦完全准确
                mCamera.takePicture(null,null,mPictureCallback);
            }
        }
    });
}

完全对焦后就开始拍照,mPictureCallback是拍照回调借口的实现:

private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] bytes, Camera camera) {
        File tempFile = new File(filePath);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(tempFile);
            fos.write(bytes);
            fos.flush();
            Intent intent = new Intent(CustomCamera.this,ResultActivity.class);
            intent.putExtra("picPath",tempFile.getPath());
            startActivity(intent);
            CustomCamera.this.finish();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
};

filePath最好设置成sd卡的路径,

private String filePath = Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".png";

此处要对sd卡进行读写操作,因此要获取sd卡的读写权限
另外调用系统相机不需要获取相机权限,但自定义相机需要获取系统相机权限

由于预览时对相机进行了90度旋转,因此拍照回调获得的图片也进行了90度翻转,要获得正立的图片需要通过Matrix类的matrix.setRotate(90)对回调图片(Bitmap)进行90旋转

Matrix matrix = new Matrix();
matrix.setRotate(90);
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);

点击查看本文相关代码

转载请注明出处amoscxy的博客:https://mp.youkuaiyun.com/mdeditor/79117522

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值