【问题标题】:How to fit camera preview and Surface View while saving the image without stretching in android studio如何在保存图像而不在android studio中拉伸的同时适应相机预览和Surface View
【发布时间】:2016-03-16 09:19:40
【问题描述】:

我已经搜索了有关拟合相机预览和表面视图的信息,但我找不到关于在 android studio 中保存图像时不拉伸图像的信息。

相机可以很好地显示在设备的表面视图上。支持的屏幕尺寸和表面视图的比例还可以。

问题在于,在捕获图像后,它需要从屏幕表面视图的各个方面获取更多信息。它只是不采用表面视图上显示的视图,而是在保存图像时更多地显示在设备的所有侧面。

只有在表面视图的高度和支持的屏幕尺寸相等时才能解决此问题。如: 支持的尺寸是: 1280/720 表面视图是: 405/720 但这会导致限制表面视图的高度和宽度的问题。我希望表面视图的高度更长,宽度与父级匹配。

因此,如果高度不相等,问题就无法解决。我希望表面视图的高度更长,宽度与父视图匹配。

谁能帮我解决这个问题, 谢谢大家,

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private static final String TAG = "CameraPreview";

private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;

public int measurewidth, measureheigh;


public CameraPreview(Context context, Camera camera) {
    super(context);
    mContext = context;
    mCamera = camera;

    // supported preview sizes
    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    for(Camera.Size str: mSupportedPreviewSizes)
        Log.e(TAG, str.width + "/" + str.height);

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    // empty. surfaceChanged will take care of stuff
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.

}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.
    if (mHolder.getSurface() == null){
        // preview surface does not exist
        return;
    }

    // stop preview before making changes
    try {
        mCamera.stopPreview();
    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
    }

    // set preview size and make any resize, rotate or reformatting changes here
    // start preview with new settings
    try {
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width  ,mPreviewSize.height); //B
        // parameters.setPreviewSize(1280,720 );
        mCamera.setParameters(parameters);
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();


    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

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

    Log.e(TAG, "REAL SCREEN SIZE  => w=" + width + ", h=" + height);


    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }
    Log.e(TAG, "MPREVIEW SIZE OPTIMAL  => w=" + mPreviewSize.width + ", h=" + mPreviewSize.height);

    float ratio;
    if(mPreviewSize.height >= mPreviewSize.width)
        ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
    else
        ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

    Log.e(TAG, "Ration  => R=" + ratio);

    // One of these methods should be used, second method squishes preview slightly
    //setMeasuredDimension(1080, 1200);
    //setMeasuredDimension(mPreviewSize.height, mPreviewSize.width); //B

     setMeasuredDimension(width, (int)(width*ratio)); //B


    // setMeasuredDimension(720, 1280);


    // setMeasuredDimension((int) (width ), height);

    measurewidth = width ; // this is for bitmap width   
    measureheigh = (int)(width*ratio); // this is for bitmap height


}

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { // long screen
    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.width - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.width - targetHeight);
        }
    }

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

}

【问题讨论】:

  • 首先说明您正在使用的相机API并显示一些代码。
  • API 是 12 @haike00
  • 我说的是相机 API(1 或 2),而不是 SDK 版本。

标签: android android-layout android-camera


【解决方案1】:

在检查了您的代码(以及您面临的问题)之后,我决定不专注于编码部分。相反,我将概述预览和快照(拍照)之间发生的情况。

概述

在旧版相机 API 中,您需要注意两个非常重要的 Camera.Size - 预览大小和图片大小。

Camera.Parameters API,您可以通过调用Parameters.getSupportedPreviewSizes()Parameters.getSupportedPicturSizes() 获得2 个单独的支持尺寸列表。

顾名思义,每个尺寸列表都专用于不同的用途 - 预览和拍照。

示例案例

想象一下你有这样的列表:

  • 预览尺寸:1920x1080 (16:9)、1280x960 (4:3)
  • 图片尺寸:3840x2160 (16:9)、1920x1440 (4:3)

比如说,你想以 3840x2160 (16:9) 拍照,你打电话给Parameters.setPictureSize(3840, 2160) 告诉相机你想在你打电话给takePicture(...) 时以这个分辨率拍照。

解方程

现在,您将如何在屏幕(或取景器)上显示具有相同分辨率的预览?

是的,你猜对了 - 具有相同纵横比 (AR) 的预览尺寸。

我们需要找出(目标)图片尺寸的AR,找到与AR相同的预览尺寸,准备好后调用Parameters.setPreviewSize(width, height)

在我们的例子中,我们将选择 1920x1080 的预览尺寸,因为它与图片尺寸具有相同的 AR (16:9)。

不同的 AR?

如果您想拍摄 16:9 的照片,但将预览尺寸设置为 4:3,会发生什么情况?

答案很明显,用户将无法以所见即所得的方式拍照。

注意事项

选择图片尺寸并确定预览尺寸并不难。不过,要正确使用相机,您还需要注意更多事项。

  • 与设备自然方向相反的相机方向 (CameraInfo.orientation)。记得在必要时调用 `Parameters.setRotation(rotation)。
  • 如果相机支持不同方向的相同分辨率(例如 1920x1080 和 1080x1920),请使用您希望拍摄照片的方向调用 `Parameters.setPreviewSize(width, height)。

希望这会有所帮助。

【讨论】:

  • 感谢它确实有效的答案。当我输入图片尺寸时,它确实有效。这就是问题所在。 @haike
  • @AndroidApp 很高兴它有帮助。 =)
猜你喜欢
  • 1970-01-01
  • 2016-02-20
  • 1970-01-01
  • 2019-03-02
  • 2012-07-04
  • 1970-01-01
  • 2021-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多