简体   繁体   English

Android - 如何使用相机getSupportedPreviewSizes()进行纵向方向

[英]Android - How to use camera getSupportedPreviewSizes() for portrait orientation

I'm trying to embed a camera preview in an activity. 我正在尝试在活动中嵌入相机预览。 And it's only in portrait orientation. 它只是在纵向方向。 The problem is the preview gets stretched. 问题是预览被拉长了。

I've tried to pick the optimal size. 我试图选择最佳尺寸。 But the problem is all supported preview sizes from getSupportedPreviewSizes() returns sizes in landscape orientation. 但问题是getSupportedPreviewSizes()支持的所有预览大小都以横向方式返回大小。 So picking the right size according to my code won't work I guess. 因此,根据我的代码选择正确的大小我认为不行。

My layout XML: 我的布局XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_take_attendance"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:orientation="vertical"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.lab.rafael.smartattendance.TakeAttendanceActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/take_attendance_label"
        android:id="@+id/take_attendance_label"
        android:layout_marginBottom="@dimen/activity_vertical_margin"/>

    <!-- camera preview container -->
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/red"
        android:id="@+id/take_attendance_scan_qr_frame"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="@string/take_attendance_manual_text"
            />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/take_attendance_manual_button"
            android:id="@+id/take_attendance_manual_button"/>
    </LinearLayout>
</LinearLayout>

Here's my CameraPreview class: 这是我的CameraPreview类:

package com.lab.rafael.smartattendance.camera;

import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.util.List;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private Camera mCamera = null;
    private SurfaceHolder mHolder = null;
    private Camera.Size optimalSize = null;

    public CameraPreview(Context context, Camera camera)
    {
        super(context);
        mCamera = camera;
        mHolder = getHolder();
        mHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            Camera.Parameters params = mCamera.getParameters();
            List<String> focusModes = params.getSupportedFocusModes();
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(holder);

            if(focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }

            if(optimalSize != null) {
                params.setPreviewSize(optimalSize.width, optimalSize.height);
            }

            mCamera.setParameters(params);

            mCamera.startPreview();
        } catch (IOException e)
        {
            Log.e("created_error", 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.e("changed_error", e.getMessage());
        }

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e){
            Log.e("error", e.getMessage());
        }
    }

    @Override
    public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
        optimalSize = getOptimalSize(MeasureSpec.getSize(measureWidthSpec), MeasureSpec.getSize(measureHeightSpec));
        setMeasuredDimension(optimalSize.width, optimalSize.height);
    }

    protected Camera.Size getOptimalSize(int width, int height) {
        List<Camera.Size> supportedSizes = mCamera.getParameters().getSupportedPreviewSizes();
        double targetRatio = (double) width / height,
                optimalRatio = 0.0,
                acceptableRatioMargin = 0.1,
                minDiff = Double.MAX_VALUE;


        for(Camera.Size size : supportedSizes) {
            optimalRatio = (double) size.width / size.height;
            if(Math.abs(optimalRatio - targetRatio) < acceptableRatioMargin) {
                if(Math.abs(height - size.height) < minDiff) {
                    minDiff = Math.abs(height - size.height);
                    optimalSize = size;
                }
            }
        }

        if(optimalSize == null) {
            for(Camera.Size size : supportedSizes) {
                if(Math.abs(height - size.height) <= minDiff) {
                    minDiff = Math.abs(height - size.height);
                    optimalSize = size;
                }
            }
        }

        return optimalSize;
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
    }
}

The below images is resulting from the values: 以下图像来自以下值:

Specified resolution from measureSpecWidth/Height = `984x1335`

Returned from getOptimalSize() = `1600x1200`.

Because provided supportedPreviewSizes are for landscape not portrait. 因为提供的supportedPreviewSizes适用于横向而非纵向。

Here's the result: 这是结果:

在此输入图像描述

I had same problem like 1 year ago. 我和1年前一样有同样的问题。 Plus I had to deal with frontal and back camera. 另外,我不得不处理正面和背面相机。 I don't remember much about the code but I tried it before posting this answer an it's still working like a charm. 我不太记得代码,但我在发布这个答案之前尝试过它仍然像魅力一样工作。
Hope you can dig and compare with your code. 希望您能挖掘并与您的代码进行比较。 I can share more code if you just something working ;) 如果你只是工作,我可以分享更多的代码;)

/**
 * A simple wrapper around a Camera and a SurfaceView that renders a centered preview of the Camera
 * to the surface. We need to center the SurfaceView because not all devices have cameras that
 * support preview sizes at the same aspect ratio as the device's display.
 */
public class Preview extends ViewGroup implements SurfaceHolder.Callback {

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Camera.Size mPreviewSize;
    List<Camera.Size> mSupportedPreviewSizes;
    Camera mCamera;
    private Context context;
    private int mCameraId;
    public boolean use_front_camera;

    public Preview(Context context, int cameraId) {
        super(context);

        this.context = context;
        mCameraId = cameraId;
        use_front_camera = true;

        mSurfaceView = new SurfaceView(context);
        addView(mSurfaceView);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();
        }
    }

    public void switchCamera(Camera camera) {
        setCamera(camera);
        try {
            camera.setPreviewDisplay(mHolder);
        } catch (IOException exception) {
            android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
        }
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        requestLayout();

        camera.setParameters(parameters);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        //MUST CALL THIS
        setMeasuredDimension(width, height);

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

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                /**
                 * Como el calculo se hace con la cámara en modo landscape y luego toca
                 * girar la cámara para que se vea bien, se pasan los valores cambiados.
                 */
                previewWidth = mPreviewSize.height;
                previewHeight = mPreviewSize.width;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight < height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
    //        if (mCamera != null) {
    //            mCamera.stopPreview();
    //        }
    }


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

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

        int targetHeight = h;

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

        // Cannot find the one match the aspect ratio, ignore the requirement
        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;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin    
        // the preview.

        if (mCamera == null)
            return;

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        parameters.setJpegQuality(100);
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);


        List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
        Camera.Size size = sizes.get(0);
        for(int i=0;i<sizes.size();i++)
        {
            if(sizes.get(i).width > size.width)
                size = sizes.get(i);
        }
        parameters.setPictureSize(size.width, size.height);


        requestLayout();


        mCamera.setParameters(parameters);
            mCamera.setDisplayOrientation(getCameraDisplayOrientation((FragmentActivity)context, mCameraId));
        mCamera.startPreview();
    }


    public static int getCameraDisplayOrientation(FragmentActivity activity, int cameraId) {
        Camera.CameraInfo info = new Camera.CameraInfo();

        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }


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


    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(int cameraIndex){
        Camera c = null;
        try {
            c = Camera.open(cameraIndex); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
            android.util.Log.e(IdelityConstants.ERROR_IDELITY_KEY_LOG, "Camera is not available: " + e.getMessage());
        }
        return c; // returns null if camera is unavailable
    }
}



here is the XML, its simple (you will see in the screenshot). 这是XML,它很简单(你会在截图中看到)。 The only important thing is the FrameLayout with id: capture_evidence_camera_preview 唯一重要的是带有id:capture_evidence_camera_preview的FrameLayout

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:id="@+id/capture_evidence_linearLayout_camera"
    android:layout_weight="3"
    android:layout_gravity="center_horizontal">


    <FrameLayout
        android:id="@+id/capture_evidence_camera_preview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/capture_evidence_default_text_number_evidence"
        android:id="@+id/capture_evidence_textView_value_typed"
        android:textSize="50sp"
        android:textColor="@color/idelity_blanco"
        android:gravity="center_horizontal"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:background="#d2000000"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:paddingTop="8dp"
        android:paddingBottom="8dp" />
</RelativeLayout>


<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1">

    <net.idelity.idelitymobile.ui.helpers.IdelityButton
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:text="@string/button_back"
        android:id="@+id/capture_evidence_button_cancel"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:background="@drawable/button_gray"
        android:textColor="@color/idelity_blanco"
        android:textSize="20sp"
        android:paddingLeft="40dp"
        android:paddingRight="40dp"
        android:textStyle="bold" />

    <net.idelity.idelitymobile.ui.helpers.IdelityButton
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/capture_evidence_button_capture_evidence"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@+id/capture_evidence_button_cancel"
        android:layout_toEndOf="@+id/capture_evidence_button_cancel"
        android:background="@drawable/take_photo_button_camera"
        android:textSize="25sp"
        android:textColor="@color/idelity_blanco"
        android:textStyle="bold"
        android:text="@string/capture_evidence_button_capture_evidence"
        android:paddingBottom="10dp" />
</RelativeLayout>

XML预览

Its used under an FragmentActivity (I can share it if you need it too) 它在FragmentActivity下使用(如果你需要它我可以分享它)

tl;dr the sizes used both in getSupportedPreviewSizes() and in setPreviewSize(int width, int height) are in the original camera orientation, which might (and usually is) different to the natural phone's orientation and the current display orientation. tl; drgetSupportedPreviewSizes()setPreviewSize(int width, int height)中使用的大小都是原始相机方向,这可能(通常是)与自然手机的方向和当前显示方向不同。

Because of this the getOptimalSize(int, int) method looped through the sizes when they are on their side (and using 1/ratio of them because of that), not picking any of them and choosing a wrong ratio at the end, based on the height according to the second loop in the method, resulting in a squashed image. 因此,当getOptimalSize(int, int)方法在它们一边时(并且因此使用1/ratio它们的1/ratio getOptimalSize(int, int)循环时getOptimalSize(int, int)方法循环,​​不选择任何一个并在最后选择错误的比率,基于根据该方法中的第二循环的高度,导致压扁的图像。


Apparently, the supported sizes are always referring to the camera in its natural angle (although the documentation does not tell us that). 显然,支持的尺寸总是指相机的自然角度(虽然文档没有告诉我们)。 The camera's natural angle is normally not the same as the natural angle of the phone. 相机的自然角度通常与手机的自然角度不同。 You can check the difference between them using the CameraInfo.orientation field. 您可以使用CameraInfo.orientation字段检查它们之间的差异。

The documentation that does hint that this is true (besides trying it out) is the same documentation that solves your mystery as well: Camera.Parameters.setPreviewSize(int width, int height) : 提示这是真的文档(除了尝试之外)也是解决你的谜团的相同文档: Camera.Parameters.setPreviewSize(int width, int height)

The sides of width and height are based on camera orientation. 宽度和高度的边是基于相机方向。 That is, the preview size is the size before it is rotated by display orientation. 也就是说,预览大小是按显示方向旋转之前的大小。 So applications need to consider the display orientation while setting preview size. 因此,应用程序需要在设置预览大小时考虑显示方向。 For example, suppose the camera supports both 480x320 and 320x480 preview sizes. 例如,假设相机支持480x320和320x480预览尺寸。 The application wants a 3:2 preview ratio. 该应用程序需要3:2的预览比率。 If the display orientation is set to 0 or 180, preview size should be set to 480x320. 如果显示方向设置为0或180,则预览大小应设置为480x320。 If the display orientation is set to 90 or 270, preview size should be set to 320x480. 如果显示方向设置为90或270,则预览大小应设置为320x480。 The display orientation should also be considered while setting picture size and thumbnail size. 设置图片大小和缩略图大小时,还应考虑显示方向。

( Documentation here ) 这里的文件

We can learn a couple of things from that: 我们可以从中学到一些东西:

  1. The sizes you get are supposed to be the same no matter what the display/phone orientation is, so there is nothing wrong with the values you see there. 无论显示器/电话方向如何,您获得的尺寸都应该是相同的,因此您在那里看到的值没有任何问题。 You should turn them on their side in order to pick the best one for the onMeasure() method to measure the view in a portrait orientation (based on the screen and space you want the preview to occupy). 您应该将它们放在一边,以便为onMeasure()方法选择最佳的一个,以纵向方式测量视图(基于您希望预览占据的屏幕和空间)。

    Ideally - turn them after you confirmed the camera's mounting angle and the current phone's angle are not compatible (one landscape and one portrait). 理想情况下 - 在确认相机的安装角度并且当前手机的角度不兼容(一个风景和一个人像)后转动它们。

     //in getOptimalSize(int width, int height) //isCameraOnSide() is a new method you should implement //return true iff the camera is mounted on the side compared to //the phone's natural orientation. double targetRatio = (isCameraOnSide()) ? (double) height / width : (double) width / height, optimalRatio = 0.0, acceptableRatioMargin = 0.1, minDiff = Double.MAX_VALUE; for(Camera.Size size : supportedSizes) { optimalRatio = (double) size.width / size.height; if(Math.abs(optimalRatio - targetRatio) < acceptableRatioMargin) { if(Math.abs(height - size.height) < minDiff) { minDiff = Math.abs(height - size.height); optimalSize = size; } } } 

    In your and my cases isCameraOnSide() returns true - as we can see from your line of setPreviewOrientation(90) . 在你和我的情况下, isCameraOnSide()返回true - 正如我们从你的setPreviewOrientation(90)行看到的setPreviewOrientation(90) For a more general implementation, here's one based google's Camera2Basic sample: 对于更一般的实现,这里有一个基于谷歌的Camera2Basic示例:

     private boolean isCameraOnSide(){ int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); //Inquire the sensor's orientation relative to the natural phone's orientation android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(0, info); //Back-facing camera int sensorOrientation = info.orientation; boolean swappedDimensions = false; switch (displayRotation) { case Surface.ROTATION_0: case Surface.ROTATION_180: if (sensorOrientation == 90 || sensorOrientation == 270) { swappedDimensions = true; } break; case Surface.ROTATION_90: case Surface.ROTATION_270: if (sensorOrientation == 0 || sensorOrientation == 180) { swappedDimensions = true; } break; default: Log.e(TAG, "Display rotation is invalid: " + displayRotation); } return swappedDimensions; } 
  2. And more importantly: If you use the Camera.Parameters.getPreviewSize() method as a watch or in a Log I think you will see that it is set to a different ratio than the one of the size picked by the setMearuseDimension(int, int) method. 更重要的是:如果你使用Camera.Parameters.getPreviewSize()方法作为手表或在日志中我认为你会看到它被设置为与setMearuseDimension(int, int)选择的大小不同的比率setMearuseDimension(int, int)方法。 This difference in ratios is the origin of the stretch/squash (it looks squashed vertically in your picture. That can also be a hint that the distortion is not from a landscape/portrait confusion, as a landscape picture in portrait view would be stretched vertically rather than squashed). 这种比例的差异是拉伸/壁球的起源(它看起来在你的图片中垂直压扁。 也可以暗示失真不是来自景观/肖像混乱,因为纵向视图中的风景图片将垂直拉伸而不是压扁)。 After choosing the right size for the view (in this case SurfaceView), you should call Camera.Parameters.setPreviewSize(int width, int height) with a supported preview size that has the same ratio as the size you used for the view (again, width according to the camera, not the current phone/display orientation. That means it might go into the height parameter). 在为视图选择正确的大小(在本例中为SurfaceView)之后,您应该使用支持的预览大小调用Camera.Parameters.setPreviewSize(int width, int height) ,该大小与您用于视图的大小具有相同的比例(再次,根据相机的宽度,而不是当前的手机/显示方向。这意味着它可能会进入height参数)。

    For example, you could do that in surfaceCreated and surfaceChanged methods (worked for me). 例如,您可以在surfaceCreatedsurfaceChanged方法中执行此操作(适用于我)。 Make sure the preview is not on when you set the camera's preview size and start it (or re-start it) after you do: 在执行以下操作后,确保在设置相机的预览尺寸并启动(或重新启动)时未启用预览:

      //inside surfaceCreated(SurfaceHolder holder) Camera.Parameters params = mCamera.getParameters(); Camera.Size prevSize = getOptimalSize(getWidth(), getHeight()); //prevSize should be still in the camera's orientation. In your and my cases - landscape params.setPreviewSize(prevSize.width, prevSize.height); mCamera.setParameters(params); mCamera.setPreviewDisplay(holder); mCamera.startPreview(); 

I've worked on developing camera applications for a while and there is a lot of things to take into consideration but let's keep it simple 我已经开发了一段时间开发相机应用程序,有很多事情需要考虑,但让我们保持简单

  1. Try to make the target view size as the same aspect ratio as one of the popular supported preview sizes (3:2, 16:9 ,4:3). 尝试将目标视图大小设置为与常用的支持预览大小(3:2,16:9,4:3)相同的宽高比。 If you can't try to choose one preview size that has the smallest difference in aspect ratio 如果您无法尝试选择宽高比差异最小的一个预览尺寸
  2. After choosing a proper view size you can center it inside your activity by overriding onLayout() on your CameraPreview 选择合适的视图大小后,您可以通过覆盖onLayout()上的CameraPreview onLayout()将其置于活动中心
public static Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    return determineBestSize(sizes);
}

public static Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
    return determineBestSize(sizes);
}

protected static Camera.Size determineBestSize(List<Camera.Size> sizes) {
    Camera.Size bestSize = null;
    long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    long availableMemory = Runtime.getRuntime().maxMemory() - used;
    for (Camera.Size currentSize : sizes) {
        int newArea = currentSize.width * currentSize.height;
        long neededMemory = newArea * 4 * 4; // newArea * 4 Bytes/pixel * 4 needed copies of the bitmap (for safety :) )
        boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
        boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
        boolean isSafe = neededMemory < availableMemory;
        if (isDesiredRatio && isBetterSize && isSafe) {
            bestSize = currentSize;
        }
    }
    if (bestSize == null) {
        return sizes.get(0);
    }
    return

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM