在Android中更正宽高比

时间:2014-11-21 08:54:51

标签: android android-camera aspect-ratio

我正在开发一个在SurfaceView上绘制相机的应用程序。一开始我发现了观点的麻烦。他们没有正确显示。所以我使用以下方法来纠正宽高比问题:

注意:此方法可在多个位置找到,以便更正Android相机的宽高比。

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

    // Check wheter is portrait or landscape
    if (orientation == 1)
        targetRatio = (double) h / w;
    else
        targetRatio = (double) w / h;

    if (sizes == null)
        return null;

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

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (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);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

这很完美,我的相机显示正确。但我发现新设备存在问题,例如LG G3。它有一个分辨率,这个方法认为是最合适的,但它在肖像模式下显示带有支柱框的图像,如下图所示:

enter image description here

为什么会这样?如何在纵向模式下解决此支柱盒?

2 个答案:

答案 0 :(得分:3)

除非该代码中存在错误,否则您将获得“最佳”结果。

手机相机的宽高比无法保证与手机屏幕的宽高比相匹配。

只需确定最佳结果的标准是什么。该代码是谷歌建议决定在手机屏幕上显示的最佳相机分辨率。

您可能不同意Google。在这种情况下,您需要编写自己的算法来决定什么是最佳的相机分辨率。您可以针对宽高比或宽度或高度的分辨率进行优化。您可以尝试适合屏幕,或者您可以剪切图像的位以填充整个屏幕。这取决于你。

注意:您发布的代码会尝试查找在屏幕宽高比的10%范围内的相机分辨率,而的高度与屏幕最接近的高度相匹配。 如果相机分辨率在距离屏幕宽高比不超过10%的范围内,则会选择高度与屏幕最接近的相机分辨率。在这种情况下,你会在支柱盒周围留下明显的黑条。

答案 1 :(得分:1)

在我的情况下,我在同一个活动中有其他视图,所以我想在第一个位置修复相机预览布局的尺寸。在布局中,您需要提供所需的最大尺寸(重量)。

我创建了另一种方法,在给定目标视图当前宽度和高度以及活动方向的情况下,确定任何相机的最佳预览大小:

public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) {
    if (CommonUtils.isEmpty(cameraPreviewSizes)) {
        return null;
    }

    int optimalHeight = Integer.MIN_VALUE;
    int optimalWidth = Integer.MIN_VALUE;

    for (Camera.Size cameraPreviewSize : cameraPreviewSizes) {
        boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width;
        int actualCameraWidth = cameraPreviewSize.width;
        int actualCameraHeight = cameraPreviewSize.height;

        if (isActivityPortrait) {
            if (!isCameraPreviewHeightBigger) {
                int temp = cameraPreviewSize.width;
                actualCameraWidth = cameraPreviewSize.height;
                actualCameraHeight = temp;
            }
        } else {
            if (isCameraPreviewHeightBigger) {
                int temp = cameraPreviewSize.width;
                actualCameraWidth = cameraPreviewSize.height;
                actualCameraHeight = temp;
            }
        }

        if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) {
            // finds only smaller preview sizes than target size
            continue;
        }

        if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) {
            // finds only better sizes
            optimalWidth = actualCameraWidth;
            optimalHeight = actualCameraHeight;
        }
    }

    Size optimalSize = null;

    if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) {
        optimalSize = new Size(optimalWidth, optimalHeight);
    }

    return optimalSize;
}

这使用自定义尺寸对象,因为Android&#39; s Size在API 21之后可用。

public class Size {

    private int width;
    private int height;

    public Size(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

}

您可以通过聆听视图的全局布局更改来确定视图的宽度和高度,然后可以设置新的尺寸。这还显示了如何以编程方式确定活动的方向:

cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // gets called after layout has been done but before display.
                cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);

                boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
                Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait);
                if (optimalCameraPreviewSize != null) {
                    LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight());
                    cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams);
                }
            }
        });

您还需要旋转相机方向,这是另一个问题。