Android相机开发中遇到的坑(注意事项)

Android相机开发中遇到的坑(注意事项)

相机预览界面方向的设定

在默认情况下有些相机用户看到的预览界面和真实世界的情况是颠倒的,所以我们需要设定预览界面的方向,如下所示:

    public static int getDisplayRotation(Activity activity) {
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
            case Surface.ROTATION_0:
                return 0;
            case Surface.ROTATION_90:
                return 90;
            case Surface.ROTATION_180:
                return 180;
            case Surface.ROTATION_270:
                return 270;
        }
        return 0;
    }
    public static int getDisplayOrientation(int degrees, int cameraId) {
        // See android.hardware.Camera.setDisplayOrientation for
        // documentation.
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        return result;
    }

最后设定预览界面的方向

mDisplayRotation = CameraUtils.getDisplayRotation(mActivity);
mDisplayOrientation = CameraUtils.getDisplayOrientation(mDisplayRotation, mCameraId);
mCameraDevice.setDisplayOrientation(mDisplayOrientation);

相片方向的设定

由于得到的相片和我们用户使用手机的方向有关,例如用户竖着拍照,那么得到的应该也是竖着的图片,所以我们监听手机方向的变化。如下

private MyOrientationEventListener mOrientationListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        mOrientationListener = new MyOrientationEventListener(this);

    }

    @Override
    public void onPause() {
        mOrientationListener.disable();
        super.onPause();
    }


    @Override
    public void onResume() {
        mOrientationListener.enable();
        super.onResume();
    }

    private class MyOrientationEventListener
            extends OrientationEventListener {
        public MyOrientationEventListener(Context context) {
            super(context);
        }

        @Override
        public void onOrientationChanged(int orientation) {
            // We keep the last known orientation. So if the user first orient
            // the camera then point the camera to floor or sky, we still have
            // the correct orientation.
            if (orientation == ORIENTATION_UNKNOWN) return;
            KSLog2.KSLog().d("onOrientationChanged = " + orientation);

        }
    }

通过上面的方法我们就可以监听手机的方向,然后我们通过公式来计算在当前手机的方向下应该设定手机真正的方向(0,90,180,270)这几种方向的一种,如下所示:

    // Orientation hysteresis amount used in rounding, in degrees
    public static final int ORIENTATION_HYSTERESIS = 5;
    public static int roundOrientation(int orientation, int orientationHistory) {
        boolean changeOrientation = false;
        if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
            changeOrientation = true;
        } else {
            int dist = Math.abs(orientation - orientationHistory);
            dist = Math.min( dist, 360 - dist );
            changeOrientation = ( dist >= 45 + ORIENTATION_HYSTERESIS );
        }
        if (changeOrientation) {
            return ((orientation + 45) / 90 * 90) % 360;
        }
        return orientationHistory;
    }

得到手机真正的方向后,我们就可以计算图片的方向了。如下所以

    /**
     *  获取照片的方向
     * @param cameraId 摄像头ID
     * @param orientation 手机方向
     * @return
     */
    public static int getJpegRotation(int cameraId, int orientation) {
        // See android.hardware.Camera.Parameters.setRotation for
        // documentation.
        int rotation = 0;
        if (orientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
            Camera.CameraInfo info = CameraHolder.instance().getCameraInfo()[cameraId];
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                rotation = (info.orientation - orientation + 360) % 360;
            } else {  // back-facing camera
                rotation = (info.orientation + orientation) % 360;
            }
        }
        return rotation;
    }

最后设定图片的方向

// Set rotation and gps data.
            mJpegRotation = CameraUtils.getJpegRotation(mCameraId, mOrientation);
            mParameters.setRotation(mJpegRotation);
            mParameters.set("rotation", mJpegRotation);
            mCameraDevice.setParameters(mParameters);

预览界面的大小设定

在设定预览界面的时候我们不能任意设定预览界面的大小(会出现异常同时也有可能出现在其他手机不兼容的情况),所以我们应该先查询系统支持的大小,然后通过计算得到最适合的预览界面。如下所示:

    public static Camera.Size getOptimalPreviewSize(Activity activity, List.Size> sizes) {
        if (sizes == null) return null;
        DeviceInfoUtils.ScreenInfo screenInfo = DeviceInfoUtils.getScreenInfo(activity);
        //这里得到的是surfaceView的长宽比,你们可以根据自己需要计算自己相机surfaceView的长宽比
        final double targetRatio = (screenInfo.width * 1.0f) / (screenInfo.height - activity.getResources().getDimensionPixelOffset(R.dimen.doc_scan_camera_bottom_bar_height));
        Camera.Size optimalSize = null;
        double minRatioDiff = Double.MAX_VALUE;
        double ratio = 0;
        for (Camera.Size size : sizes) {
            if (size.height > size.width) {
                ratio = ((double) (size.width)) / ((double) size.height);
            } else {
                ratio = ((double) (size.height)) / ((double) size.width);
            }
            double temp = Math.abs(targetRatio - ratio);
            if (temp < minRatioDiff && Math.min(size.height, size.width) >= screenInfo.width) {
                optimalSize = size;
                minRatioDiff = temp;
            }
        }
        KSLog2.KSLog().d("preview size width = " + optimalSize.width + " height = " + optimalSize.height + " minRatioDiff= " + minRatioDiff);
        return optimalSize;
    }

设定预览界面的大小

    // Set a preview size that is closest to the viewfinder height and has
        // the right aspect ratio.
        List.Size> sizes = mParameters.getSupportedPreviewSizes();
        Camera.Size optimalSize = CameraUtils.getOptimalPreviewSize(mActivity, sizes);
        Camera.Size original = mParameters.getPreviewSize();
        if (!original.equals(optimalSize)) {
            mParameters.setPreviewSize(optimalSize.width, optimalSize.height);
        }

总结

在开发相机中需要设定很多参数,其中很多参数都需要查询系统是否支持,然后再去设定系统支持设定中的某一种,例如:图片输出的大小、对焦方式、曝光模式等等,不然容易出现崩溃或者兼容性问题。

你可能感兴趣的:(Android)