Correct aspect ratio in Android

I am developing an application that draws a camera on SurfaceView

. I first found problems with these views. They were shown incorrectly. So I used the following method to fix the aspect ratio problem:

NOTE. This method can be found in several places to adjust the aspect ratio for Android camera.

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;
}

      

It worked great and my camera was shown correctly. But I found problems in newer devices like LG G3. He had a resolution that considered this method the most suitable, but he showed the image with the poles in portrait mode, as shown below:

enter image description here

Why is this happening? How can I solve this column in portrait mode?

+3


source to share


2 answers


If there is a bug in this code, you get a better result.

The aspect ratio of the phone camera will not match the aspect ratio of the phone screen.

It is only a question of which criteria are suitable for the best result. This code is Google's suggestion for determining the best camera resolution to display on a phone screen.



You may not agree with Google. In this case, you will need to write your own algorithm to determine the best camera resolution. You can optimize aspect ratio or resolution for width or height. You can try to fit the screen, or you can copy portions of the image to fill the entire screen. It depends on you.

Note. The code you posted tries to find a camera resolution that is 10% of the screen format and has a height that matches the closest screen. If the camera resolution does not exceed 10% of the screen aspect ratio, then the camera resolution is selected, the height of which corresponds to the nearest screen. In this case, you will have large black stripes around the rack.

+3


source


In my case, I had different views in the same activity, so I wanted to fix the dimensions of the camera preview layout first. In the layout, you need to specify the maximum dimensions (weights).

I created another method that determines the optimal preview size for any camera given the current width and height of the current view, as well as the orientation of the activity:

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;
}

      

In this case, a custom size object is used because after API 21 Size is available .



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;
    }

}

      

You can determine the width and height of the view by listening to its global layout changes, and then you can set new dimensions. It also shows how to programmatically determine the orientation of an activity:

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);
                }
            }
        });

      

You also need to rotate the orientation of the camera, which is another problem.

+1


source







All Articles