Android 自定义Camera全屏拍照,支持前后摄像头

最近项目中一直在调用系统相机拍照,而产品总是要求拍照页面向iOS看齐,真是很头疼啊。但问题还是存在,有必要搞一个自定义的啦。在网上搜索了一段时间后,发现还真不是那么好实现的,实践之后,总结一些要点如下:

1.camera的parameters设置总是会提示出setParamters failed的异常

2.预览和图片的尺寸设置

3.预览图片变形

4.自动聚焦

5.保存的图片旋转角度

以上是我遇到的难点,并将之一一解决后的总结。


第1个问题,setPreviewFrameRate和setPreviewSize不能放在一起使用,否则set的时候必然报错,这个也是在查看了源代码后发现的。

第2个问题,每个手机都有自己支持的尺寸集合,并不是设置一个固定的宽高就可以的,所以要想设置尺寸,一定是先获取手机支持的尺寸,而且排序也不一样,有的从大到小,有的从小到大。没办法,开源嘛。

第3个问题就是surfaceview的尺寸大小,设置的不对的话,会导致预览变形,这个要和预览尺寸配合着设置

第4个问题比较容易解决一点,网上有很多种设置方式,但是最好用的就是使用重力加速度类型的传感器来实现,这个效果是最好的,在配合上触屏操作时也加上自动聚焦功能,就能保证自动聚焦这个功能完美的实现了。

第5个问题就是拍照会转动手机在各种角度拍照,那么获取的图片显示的时候有要求的需要根据角度重新生成bitmap,然后再显示啦。这个使用Matrix类就能实现,但是难点在于如何获取到正确的旋转角度。通常都会使用getWindowManager().getDefaultDisplay().getRotation();这个方法,但是当我将这个相机Activity设置成portrait时,这个方法是无效的,因此必须使用OrientationEventListener这个监听器,其实这个也是利用传感器实现的方向监听。


好了,以上总是我遇到的一些问题,以及一些总结,下面直接贴出代码,就不上传工程啦。所有的代码都写在一个activity里面了,还没有做架构抽象,感兴趣的小伙伴可以抽象一下,反馈给我,呵呵。


CameraManager.java

import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.SurfaceHolder;
import android.widget.Toast;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by zouguibao on 2017/11/23.
 */

public class CameraManger {
    private static CameraManger instance;
    private Camera camera;
    private MediaPlayer mShootSound;

    public static final int TYPE_PREVIEW = 0;
    public static final int TYPE_PICTURE = 1;
    public static final int ALLOW_PIC_LEN = 2000;       //最大允许的照片尺寸的长度   宽或者高

    private int cameraPosition;

    private CameraManger() {

    }

    public static CameraManger getInstance() {
        if (instance == null) {
            instance = new CameraManger();
        }
        return instance;
    }

    /**
     * 打开摄像头
     *
     * @param holder
     * @param autoFocusCallback
     * @param degree
     */
    public void openCamera(SurfaceHolder holder, Camera.AutoFocusCallback autoFocusCallback, int degree) {
        try {
            //初始化摄像头
            cameraPosition = Camera.CameraInfo.CAMERA_FACING_BACK;
            // 打开摄像头
            camera = Camera.open(cameraPosition);
            // 设置用于显示拍照影像的SurfaceHolder对象
            camera.setPreviewDisplay(holder);
            camera.setDisplayOrientation(degree);
            camera.autoFocus(autoFocusCallback);

        } catch (Exception e) {
//                e.printStackTrace();
            camera.release();
            camera = null;
        }
    }

    /**
     * 设置参数
     */
    public void setCameraParameters(int screenWidth, int screenHeight) {
        try {
            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();//获取各项参数
                Camera.Size previewSize = findFitPreResolution(parameters);
                parameters.setPreviewSize(previewSize.width, previewSize.height);// 设置预览大小

                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                parameters.setPictureFormat(PixelFormat.JPEG);//设置图片格式
                //不能与setPreviewSize一起使用,否则setParamters会报错
//                    parameters.setPreviewFrameRate(5);//设置每秒显示4帧
                parameters.setJpegQuality(80);// 设置照片质量
                Camera.Size pictureSize = null;
                if (equalRate(screenWidth, screenHeight, 1.33f)) {
                    pictureSize = findFitPicResolution(parameters, (float) 4 / 3);
                } else {
                    pictureSize = findFitPicResolution(parameters, (float) 16 / 9);
                }

                parameters.setPictureSize(pictureSize.width, pictureSize.height);// 设置保存的图片尺寸
                camera.setParameters(parameters);
                camera.startPreview();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean equalRate(int width, int height, float rate) {
        float r = (float) width / (float) height;
        if (Math.abs(r - rate) <= 0.2) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 摄像头切换
     *
     * @param holder
     * @param autoFocusCallback
     * @param degree
     */
    public void turnCamera(SurfaceHolder holder, Camera.AutoFocusCallback autoFocusCallback, int degree, int screenWidth, int screenHeight) {
        //切换前后摄像头
        //现在是后置,变更为前置
        if (camera != null && cameraPosition == Camera.CameraInfo.CAMERA_FACING_BACK) {
            camera.stopPreview();//停掉原来摄像头的预览
            camera.release();//释放资源
            camera = null;//取消原来摄像头
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);//打开当前选中的摄像头
            try {
                camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面
                camera.setDisplayOrientation(degree);
                camera.autoFocus(autoFocusCallback);
                setCameraParameters(screenWidth, screenHeight);
            } catch (IOException e) {
                e.printStackTrace();
            }
            camera.startPreview();//开始预览
            cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT;
            DataUtils.isBackCamera = false;
        } else if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            //代表摄像头的方位,CAMERA_FACING_FRONT前置
            // CAMERA_FACING_BACK后置
            //现在是前置, 变更为后置
            camera.stopPreview();//停掉原来摄像头的预览
            camera.release();//释放资源
            camera = null;//取消原来摄像头
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);//打开当前选中的摄像头
            try {
                camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面
                camera.setDisplayOrientation(degree);
                camera.autoFocus(autoFocusCallback);
                setCameraParameters(screenWidth, screenHeight);
            } catch (IOException e) {
                e.printStackTrace();
            }
            camera.startPreview();//开始预览
            cameraPosition = Camera.CameraInfo.CAMERA_FACING_BACK;
            DataUtils.isBackCamera = true;
        }
    }

    public void setCameraZoom(int scale) {
        Camera.Parameters parameters = camera.getParameters();
        int zoom = parameters.getZoom() + scale;
        if (zoom < 0) zoom = 0;
        if (zoom > parameters.getMaxZoom())
            zoom = parameters.getMaxZoom();
        parameters.setZoom(zoom);
        camera.setParameters(parameters);
    }

    public boolean setCameraFocusAreas(Point point) {
        if (camera == null) {
            return false;
        }

        Camera.Parameters parameters = null;
        try {
            parameters = camera.getParameters();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        //不支持设置自定义聚焦,则使用自动聚焦,返回
        if (parameters.getMaxNumFocusAreas() <= 0) {
            return false;
        }
        List<Camera.Area> areas = new ArrayList<Camera.Area>();

        int left = point.x - 300;
        int top = point.y - 300;
        int right = point.x + 300;
        int bottom = point.y + 300;

        left = left < -1000 ? -1000 : left;
        top = top < -1000 ? -1000 : top;
        right = right > 1000 ? 1000 : right;
        bottom = bottom > 1000 ? 1000 : bottom;

        areas.add(new Camera.Area(
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,我会尽力回答你的问题。首先,让我们来看一下如何实现自定义Camera和前后置摄像头切换。 1. 自定义Camera 首先,在AndroidManifest.xml文件中添加以下权限: ``` <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.CAMERA" /> ``` 然后,在你的Activity中,创建一个Preview类,继承SurfaceView,并实现SurfaceHolder.Callback接口。 ``` public class Preview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public Preview(Context context, Camera camera) { super(context); mCamera = camera; mHolder = getHolder(); mHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d("Preview", "Error setting camera preview: " + e.getMessage()); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (mHolder.getSurface() == null) { return; } try { mCamera.stopPreview(); } catch (Exception e) { Log.d("Preview", "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Log.d("Preview", "Error starting camera preview: " + e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); mHolder.removeCallback(this); } } ``` 然后,在你的Activity中,创建一个Camera对象,并将其设置给Preview类。 ``` public class CameraActivity extends Activity { private Camera mCamera; private Preview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mCamera = getCameraInstance(); mPreview = new Preview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } public static Camera getCameraInstance() { Camera c = null; try { c = Camera.open(); } catch (Exception e) { Log.d("CameraActivity", "Error opening camera: " + e.getMessage()); } return c; } } ``` 2. 前后置摄像头切换 为了实现前后置摄像头的切换,你需要先判断设备是否支持前置摄像头。如果支持,你可以通过Camera.getNumberOfCameras()方法来获取设备上可用的摄像头数量。然后,你可以通过Camera.open()方法打开指定的摄像头。 ``` public void switchCamera() { if (Camera.getNumberOfCameras() > 1) { mCamera.stopPreview(); mCamera.release(); mCamera = null; if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT; } else { currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK; } mCamera = Camera.open(currentCameraId); mPreview.setCamera(mCamera); try { mCamera.setPreviewDisplay(mHolder); } catch (IOException e) { Log.d("CameraActivity", "Error setting camera preview: " + e.getMessage()); } mCamera.startPreview(); } } ``` 3. 图片缩小放大预览 为了实现图片的缩小和放大预览,你可以使用Matrix类来对Bitmap进行缩放操作。 ``` public void zoom(float scale) { Matrix matrix = new Matrix(); matrix.postScale(scale, scale); Bitmap scaledBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true); mImageView.setImageBitmap(scaledBitmap); } ``` 这样,你就可以实现自定义Camera和前后置摄像头切换以及图片缩小放大预览了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值