Android 项目需求Camera + SurfaceView实现自定义拍照,遇到的问题

本文介绍如何在Android项目中结合Camera和SurfaceView实现自定义拍照功能。通过自定义SurfaceView来实现实时显示摄像头画面,同时探讨在实现过程中可能遇到的问题和解决方案。文章还提醒读者检查设备摄像头的存在,并提供了Camera开发的相关资源。

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

首先要自定义SurfaceView实时显示摄像头捕获的画面

SurfaceView非常强大,有双缓存机制,可以在子线程更新ui,在游戏开发中最常用,下面是自定义SurfaceView

仿照别人的博客写的地址忘记了

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {


    private static final String TAG = "MySurfaceView";
    public Camera mCamera;
    private final SurfaceHolder mHolder;


    public MySurfaceView(Context context, Camera camera) {
        super(context);

        mCamera = camera;
        mHolder = getHolder();
        mHolder.addCallback(this);

        // 设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到界面 在Android3.0之后弃用
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


    }


    /**
     * 在SurviceView创建的时候调用
     *
     * @param holder
     */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    /**
     * 在SurviceView大小改变是调用
     *
     * @param holder
     * @param format
     * @param width
     * @param height
     */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mHolder.getSurface() == null) {
            // 如果Surface为空,不继续操作
            return;
        }
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            Log.d(TAG, "当Surface改变后,停止预览出错");
        }
        // 在预览前可以指定Camera的各项参数

        // 重新开始预览
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "预览Camera出错");
        }



    }

    /**
     * 在SurviceView销毁的时候调用
     *
     * @param holder
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

下面就是使用相机了

首先检查设备是否有摄像头

/** 检查相机硬件 */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            //设备有摄像头
            return true;
        } else {
            //设备没有摄像头
            return false;
        }
    }
获取摄像头

 /**
     * 安全的方式获取摄像头
     */
    public Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e) {
            Toast.makeText(this, "摄像头不可用", Toast.LENGTH_SHORT).show();
            return null;
        }
        return c;
    }

 if (checkCameraHardware(this)){
            camera = getCameraInstance();
            if (camera != null) {
                //根据手机支持的图片的宽高,拍摄制定宽高的图片
                Camera.Parameters parameters = camera.getParameters();
                List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
                Camera.Size size = pictureSizes.get(0);
                parameters.setPictureSize(size.width, size.height);
                camera.setParameters(parameters);

                mySurfaceView = new MySurfaceView(this, camera);
                FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
                preview.addView(mySurfaceView);
            }else {
                Toast.makeText(this, "摄像头不可用", Toast.LENGTH_SHORT).show();
                return;
            }
        }else {
            Toast.makeText(this, "没有找到摄像头", Toast.LENGTH_SHORT).show();
            return;
        }

拍照

 		//自动聚焦
                camera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {
                        //开始拍照
                        camera.takePicture(null, null, mPicture);
                        Toast.makeText(MainActivity.this, "拍照成功", Toast.LENGTH_SHORT).show();

                    }
                });

拍完照片的照片数据通过回调方法获取

 /**
     * 拍照回调方法
     */
    private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

            // 获取Jpeg图片,并保存在sd卡上
            file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");

            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(data);
                fos.close();
                Log.d(TAG, "onPictureTaken: 保存图片成功" + file.getAbsolutePath());
            } catch (Exception e) {
                Log.d(TAG, "保存图片失败");
            }
            //重新预览
            camera.startPreview();
        }
    };
最后别忘了释放相机资源

 @Override
    protected void onDestroy() {
        // 回收Camera资源
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
        
        super.onDestroy();
    }

在开发的时候我遇到的最大的问题就是这段代码
		//根据手机支持的图片的宽高,拍摄制定宽高的图片
                Camera.Parameters parameters = camera.getParameters();
                List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
                Camera.Size size = pictureSizes.get(0);
                parameters.setPictureSize(size.width, size.height);
                camera.setParameters(parameters);

拍摄的图片太大了,保存浪费时间拍摄界面会卡顿 ,指定拍摄照片的大小就可以了



希望能帮到你,有错误请提出来谢谢,

最后在加一个Camera开发文档  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值