Android 相机预览已拉伸(stretch)

标签 android android-camera surfaceview preview aspect-ratio

我一直致力于在 Android 上制作我的自定义相机 Activity ,但是当旋转相机时,表面 View 的纵横比会变得困惑。

在我的 oncreate Activity 中,我设置了 framelayout,它包含显示相机参数的表面 View 。

//FrameLayout that will hold the camera preview
        FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);

        //Setting camera's preview size to the best preview size
        Size optimalSize = null;
        camera = getCameraInstance();
        double aspectRatio = 0;
        if(camera != null){
            //Setting the camera's aspect ratio
            Camera.Parameters parameters = camera.getParameters();
            List<Size> sizes = parameters.getSupportedPreviewSizes();
            optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
            aspectRatio = (float)optimalSize.width/optimalSize.height;
        }

        if(optimalSize!= null){
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            previewHolder.setLayoutParams(params);
            LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            cameraPreview.setLayoutParams(surfaceParams);

        }

        cameraPreview.setCamera(camera);

        //Adding the preview to the holder
        previewHolder.addView(cameraPreview);

然后,在 Surface View 中,我设置要显示的相机参数

public void setCamera(Camera camera) {
        if (mCamera == camera) { return; }

        mCamera = camera;

        if (mCamera != null) {
            requestLayout();

            try {
                mCamera.setPreviewDisplay(mHolder);
            } catch (IOException e) {
                e.printStackTrace();
            }


            if(mCamera != null){
                //Setting the camera's aspect ratio
                Camera.Parameters parameters = mCamera.getParameters();
                List<Size> sizes = parameters.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);

                parameters.setPreviewSize(optimalSize.width, optimalSize.height);
                mCamera.setParameters(parameters);
            }

            /*
              Important: Call startPreview() to start updating the preview surface. Preview must 
              be started before you can take a picture.
              */
            mCamera.startPreview();
        }

    }

enter image description here

你可以看到,当手机旋转时,乐高人变得又高又瘦:

如何确保相机 View 的纵横比正确?

最佳答案

我正在使用这种方法 -> 基于 API Demos 来获取我的预览大小:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio=(double)h / w;

        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

如您所见,您必须输入屏幕的宽度和高度。此方法将根据这些值计算屏幕比例,然后从supportedPreviewSizes 列表中选择最适合您的可用值。使用

将您的 supportedPreviewSize 列表放在 Camera 对象不为空的位置
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

然后在 onMeasure 中,您可以像这样获得最佳 previewSize:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
           mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

然后(在我的surfaceChanged方法的代码中,就像我说的我使用CameraActivity代码的API Demos结构,你可以在Eclipse中生成它):

Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();

给你一个提示,因为我做了几乎和你一样的应用程序。 Camera Activity 的良好做法是隐藏 StatusBar。 Instagram 等应用程序正在这样做。它会降低您的屏幕高度值并更改您的比率值。在某些设备上可能会出现奇怪的预览尺寸(你的 SurfaceView 会被剪掉一点)


为了回答您的问题,如何检查您的预览比例是否正确?然后获取您设置的参数的高度和宽度:

mCamera.setParameters(parameters);

您的设定比例等于高度/宽度。如果您希望相机在屏幕上看起来不错,那么您为相机设置的参数的高宽比必须与屏幕的高(减去状态栏)/宽比相同。

关于Android 相机预览已拉伸(stretch),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19577299/

相关文章:

android - 为什么移动设备上的屏幕绘图被认为是 "expensive"?

java - 保存 HashMap 共享首选项

android - Delight-im 高级 webview 在每个 GET 和 POST 请求中发送自定义 header

android - 如何在底部的图像位图上放置文本?

Android Camera.Parameters setPictureSize 不起作用

Android Camera takePicture函数不调用Callback函数

android - 设置 Android 照片 EXIF 方向

java - 如何在 surfaceview 中将 Android 相机更改为纵向?

android - 以编程方式截取屏幕截图不会捕获 surfaceVIew 的内容

android - 将 surfaceView(带相机预览)移动到屏幕左侧