如何在一个平方的界面视图中设置相机预览尺寸和平方的纵横比(比如Instagram)

时间:2022-08-27 10:50:54

I'm trying to develop my own camera activity, but I have a problem that I'm not unable to solve...

我正在开发我自己的相机活动,但是我有一个问题我无法解决……

What I want, is something very similiar to instagram photo frame, and this is what I get:

我想要的是与instagram相框非常相似的东西,这就是我得到的:

如何在一个平方的界面视图中设置相机预览尺寸和平方的纵横比(比如Instagram)

When I should get something like this:

当我得到这样的东西:

如何在一个平方的界面视图中设置相机预览尺寸和平方的纵横比(比如Instagram)

and...

和…

如何在一个平方的界面视图中设置相机预览尺寸和平方的纵横比(比如Instagram)

when I should get something like:

当我得到这样的东西:

如何在一个平方的界面视图中设置相机预览尺寸和平方的纵横比(比如Instagram)

I think I'm maanaging the SurfaceView and Camera preview well, only using

我想我只是在使用SurfaceView和Camera preview

Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(90);

and Custom SurfaceView:

和自定义SurfaceView:

public class SquaredSurfaceView extends SurfaceView {

private int width;
private int height;

public SquaredSurfaceView(Context context) {
    super(context);
}

public SquaredSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public SquaredSurfaceView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = MeasureSpec.getSize(widthMeasureSpec);
    height = width;
    setMeasuredDimension(width, width);
}

public int getViewWidth() {
    return width;
}

public int getViewHeight() {
    return height;
}

}

}

What I'm doing wrong?? :-(

我做错了什么吗? ?:-(

6 个解决方案

#1


17  

As said before you need to find the correct preview size (the one with aspect ratio 1:1) and probably you have to use FrameLayout for the SurfacePreview. It seems that you have and aspect ratio problem maybe you have the right preview size but you are placing it in an incorrect layout.

如前所述,您需要找到正确的预览大小(长宽比为1:1),并且可能需要使用FrameLayout进行表面预览。看起来你有和长宽比问题也许你有正确的预览尺寸但是你把它放在了不正确的布局中。

Another solution might be (just like Instagram does) to make your camera at full size and then hide some areas of the layour just to make it look like a square. Then by software you would have to cut the image to make it a real square.

另一种解决方案可能是(就像Instagram那样)把你的相机放大,然后隐藏一些区域,让它看起来像个正方形。然后通过软件,你必须把图像切割成一个真正的正方形。

Hope this helps you

希望这能帮助你

#2


5  

The solution that works for me is the 2nd Answer, but because we need to rotate the camera 90º is necessary to switch the WIDTH with the HEIGTH, something like this...

我的解决方案是第二个答案,而是因为我们需要旋转相机90º是必要的切换与HEIGTH宽度,这样……

   camera.setDisplayOrientation(90);
   Camera.Parameters params= camera.getParameters();
   surfaceView.getLayoutParams().width=params.getPreviewSize().height;
   surfaceView.getLayoutParams().height=params.getPreviewSize().width;

Hope this solution helps!! :D

希望这个解决方案帮助! !:D

#3


2  

my solution is more like building a square mask and then to place it over the preview surface.

我的解决方案更像是构建一个正方形的蒙版,然后将它放在预览界面上。

You will need 3 things mainly, first a square frame component. I've made a custom component:

你主要需要3件东西,首先是一个方形框架组件。我做了一个自定义组件:

package com.example.squaredviewer;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Display;
import android.view.WindowManager;
import android.widget.RelativeLayout;

/**
* Created by yadirhb on 14-08-2015.
*/
public class SquaredFrame extends RelativeLayout{
    public SquaredFrame(Context context, AttributeSet attrs) {
         super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        setMeasuredDimension(size, size);
    }
}

Depending of the Android API version for the which you're developing, you will maybe need to add another constructor overload. For Kitkat this is just fine.

根据您正在开发的Android API版本的不同,您可能需要添加另一个构造函数重载。对奇巧来说,这没什么。

The second step is to build the layout:

第二步是建立布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="visible">

<RelativeLayout
    android:id="@+id/camera_preview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="false"
    android:layout_alignParentTop="false"
    android:layout_centerInParent="true"
    android:background="#ffffff">

</RelativeLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008">

    </LinearLayout>

    <com.example.squaredviewer.SquaredFrame
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"></com.example.squaredviewer.SquaredFrame>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008" />
</LinearLayout>
</RelativeLayout>

Notice that the RelativeLayout "camera_preview" is the one used to render the preview, it is centered and has a LinearLayout which contains the squared component. This is actually the "mask" and it covers the camera preview. Notice also that except the SquaredFrame, which is transparent, the others two are background coloured with black.

请注意,RelativeLayout“camera_preview”是用于呈现预览的,它是居中的,并且具有包含平方组件的线性布局。这实际上是“蒙版”,它覆盖了摄像头预览。还要注意的是,除了透明的方形框架外,其他两个框架都是黑色的背景色。

Now the surface view, for the camera preview in which the surface is sized acording the aspect ratio.

现在是曲面视图,用于摄像机的预览,在这个视图中,曲面根据纵横比进行调整。

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private final String TAG = "PIC-FRAME";

    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Display display;

    public CameraPreview(Activity context, Camera camera) {
        super(context);
        mCamera = camera;
        display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

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

        setKeepScreenOn(true);
    }

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

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int 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;
        }

        try {
            // stop preview before making changes
            mCamera.stopPreview();
            // set preview size and make any resize, rotate or
            // reformatting changes here
            // Now that the size is known, set up the camera parameters and begin
            // the preview.
            Camera.Parameters parameters = mCamera.getParameters();
            // You need to choose the most appropriate previewSize for your app
            Camera.Size previewSize = parametes.getSupportedPreviewSizes().get(0);
            parameters.setPreviewSize(previewSize.width, previewSize.height);


             // start preview with new settings
             mCamera.setParameters(parameters);

             // Set the holder size based on the aspect ratio
             int size = Math.min(display.getWidth(), display.getHeight());
             double ratio = (double) previewSize.width / previewSize.height;

             mHolder.setFixedSize((int)(size * ratio), size);
             mCamera.setPreviewDisplay(mHolder);
             mCamera.startPreview();

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

Now everything must be tied in the activity class

现在所有东西都必须绑定到activity类中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_picture_taker);

    mDecorView = getWindow().getDecorView();

    //mCamera = a camera instance;

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);

    //Layout where camera preview is shown.
    RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
    //FrameLayout stack controllers inside and superpose them.
    preview.addView(mPreview, 0);

    // TODO
}

A little long, but I hope it be helpful for more than one. :-)

有点长,但我希望它对不止一个人有帮助。:-)

#4


2  

I had the same problem with a square view - resolved it simply by setting the SurfaceView's camera size to the size of the view where I wanted to draw it. No complicated calculations and it works for me. See my response here for the whole method: https://*.com/a/39430615/5181489

我有一个同样的问题,一个正方形的视图-解决它仅仅是通过将SurfaceView的相机大小设置成我想要画它的视图的大小。没有复杂的计算,对我来说是可行的。整个方法的响应如下:https://*.com/a/39430615/5181489

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        ...
        params.setPreviewSize(viewParams.height, viewParams.width);
        camera.setParameters(params);

#5


-1  

You can use this to get pictureSize:

你可以用这个来设置pictureSize:

public static void initialCameraPictureSize(Context context, android.hardware.Camera.Parameters parameters) {

    List list = parameters.getSupportedPictureSizes();
    if(list != null) {
        android.hardware.Camera.Size size = null;
        Iterator iterator = list.iterator();
        do {
            if(!iterator.hasNext())
                break;
            android.hardware.Camera.Size size1 = (android.hardware.Camera.Size)iterator.next();
            if(Math.abs(3F * ((float)size1.width / 4F) - (float)size1.height) < 0.1F * (float)size1.width && (size == null || size1.height > size.height && size1.width < 3000))
                size = size1;
        } while(true);
        if(size != null)
            parameters.setPictureSize(size.width, size.height);
        else
            Log.e("CameraSettings", "No supported picture size found");
    }
}

#6


-1  

It's so hard. Not easily.

它是如此困难。不容易。

First thing : You define 2 black Linear Layout to get the UI as you posted.

第一件事:你定义了两个黑色线性布局来获得你发布的UI。

Second thing : you need cut the picture from full picture to square picture.

第二件事:你需要把整幅画剪成正方形。

How to cut, you need use scaleBitmap method.

如何切割,需要使用scaleBitmap方法。

Or you want real Custom Camera? Can check in here

或者你想要真正的定制相机?可以检查在这里

#1


17  

As said before you need to find the correct preview size (the one with aspect ratio 1:1) and probably you have to use FrameLayout for the SurfacePreview. It seems that you have and aspect ratio problem maybe you have the right preview size but you are placing it in an incorrect layout.

如前所述,您需要找到正确的预览大小(长宽比为1:1),并且可能需要使用FrameLayout进行表面预览。看起来你有和长宽比问题也许你有正确的预览尺寸但是你把它放在了不正确的布局中。

Another solution might be (just like Instagram does) to make your camera at full size and then hide some areas of the layour just to make it look like a square. Then by software you would have to cut the image to make it a real square.

另一种解决方案可能是(就像Instagram那样)把你的相机放大,然后隐藏一些区域,让它看起来像个正方形。然后通过软件,你必须把图像切割成一个真正的正方形。

Hope this helps you

希望这能帮助你

#2


5  

The solution that works for me is the 2nd Answer, but because we need to rotate the camera 90º is necessary to switch the WIDTH with the HEIGTH, something like this...

我的解决方案是第二个答案,而是因为我们需要旋转相机90º是必要的切换与HEIGTH宽度,这样……

   camera.setDisplayOrientation(90);
   Camera.Parameters params= camera.getParameters();
   surfaceView.getLayoutParams().width=params.getPreviewSize().height;
   surfaceView.getLayoutParams().height=params.getPreviewSize().width;

Hope this solution helps!! :D

希望这个解决方案帮助! !:D

#3


2  

my solution is more like building a square mask and then to place it over the preview surface.

我的解决方案更像是构建一个正方形的蒙版,然后将它放在预览界面上。

You will need 3 things mainly, first a square frame component. I've made a custom component:

你主要需要3件东西,首先是一个方形框架组件。我做了一个自定义组件:

package com.example.squaredviewer;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Display;
import android.view.WindowManager;
import android.widget.RelativeLayout;

/**
* Created by yadirhb on 14-08-2015.
*/
public class SquaredFrame extends RelativeLayout{
    public SquaredFrame(Context context, AttributeSet attrs) {
         super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        setMeasuredDimension(size, size);
    }
}

Depending of the Android API version for the which you're developing, you will maybe need to add another constructor overload. For Kitkat this is just fine.

根据您正在开发的Android API版本的不同,您可能需要添加另一个构造函数重载。对奇巧来说,这没什么。

The second step is to build the layout:

第二步是建立布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="visible">

<RelativeLayout
    android:id="@+id/camera_preview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="false"
    android:layout_alignParentTop="false"
    android:layout_centerInParent="true"
    android:background="#ffffff">

</RelativeLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008">

    </LinearLayout>

    <com.example.squaredviewer.SquaredFrame
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"></com.example.squaredviewer.SquaredFrame>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008" />
</LinearLayout>
</RelativeLayout>

Notice that the RelativeLayout "camera_preview" is the one used to render the preview, it is centered and has a LinearLayout which contains the squared component. This is actually the "mask" and it covers the camera preview. Notice also that except the SquaredFrame, which is transparent, the others two are background coloured with black.

请注意,RelativeLayout“camera_preview”是用于呈现预览的,它是居中的,并且具有包含平方组件的线性布局。这实际上是“蒙版”,它覆盖了摄像头预览。还要注意的是,除了透明的方形框架外,其他两个框架都是黑色的背景色。

Now the surface view, for the camera preview in which the surface is sized acording the aspect ratio.

现在是曲面视图,用于摄像机的预览,在这个视图中,曲面根据纵横比进行调整。

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private final String TAG = "PIC-FRAME";

    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Display display;

    public CameraPreview(Activity context, Camera camera) {
        super(context);
        mCamera = camera;
        display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

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

        setKeepScreenOn(true);
    }

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

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int 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;
        }

        try {
            // stop preview before making changes
            mCamera.stopPreview();
            // set preview size and make any resize, rotate or
            // reformatting changes here
            // Now that the size is known, set up the camera parameters and begin
            // the preview.
            Camera.Parameters parameters = mCamera.getParameters();
            // You need to choose the most appropriate previewSize for your app
            Camera.Size previewSize = parametes.getSupportedPreviewSizes().get(0);
            parameters.setPreviewSize(previewSize.width, previewSize.height);


             // start preview with new settings
             mCamera.setParameters(parameters);

             // Set the holder size based on the aspect ratio
             int size = Math.min(display.getWidth(), display.getHeight());
             double ratio = (double) previewSize.width / previewSize.height;

             mHolder.setFixedSize((int)(size * ratio), size);
             mCamera.setPreviewDisplay(mHolder);
             mCamera.startPreview();

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

Now everything must be tied in the activity class

现在所有东西都必须绑定到activity类中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_picture_taker);

    mDecorView = getWindow().getDecorView();

    //mCamera = a camera instance;

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);

    //Layout where camera preview is shown.
    RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
    //FrameLayout stack controllers inside and superpose them.
    preview.addView(mPreview, 0);

    // TODO
}

A little long, but I hope it be helpful for more than one. :-)

有点长,但我希望它对不止一个人有帮助。:-)

#4


2  

I had the same problem with a square view - resolved it simply by setting the SurfaceView's camera size to the size of the view where I wanted to draw it. No complicated calculations and it works for me. See my response here for the whole method: https://*.com/a/39430615/5181489

我有一个同样的问题,一个正方形的视图-解决它仅仅是通过将SurfaceView的相机大小设置成我想要画它的视图的大小。没有复杂的计算,对我来说是可行的。整个方法的响应如下:https://*.com/a/39430615/5181489

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        ...
        params.setPreviewSize(viewParams.height, viewParams.width);
        camera.setParameters(params);

#5


-1  

You can use this to get pictureSize:

你可以用这个来设置pictureSize:

public static void initialCameraPictureSize(Context context, android.hardware.Camera.Parameters parameters) {

    List list = parameters.getSupportedPictureSizes();
    if(list != null) {
        android.hardware.Camera.Size size = null;
        Iterator iterator = list.iterator();
        do {
            if(!iterator.hasNext())
                break;
            android.hardware.Camera.Size size1 = (android.hardware.Camera.Size)iterator.next();
            if(Math.abs(3F * ((float)size1.width / 4F) - (float)size1.height) < 0.1F * (float)size1.width && (size == null || size1.height > size.height && size1.width < 3000))
                size = size1;
        } while(true);
        if(size != null)
            parameters.setPictureSize(size.width, size.height);
        else
            Log.e("CameraSettings", "No supported picture size found");
    }
}

#6


-1  

It's so hard. Not easily.

它是如此困难。不容易。

First thing : You define 2 black Linear Layout to get the UI as you posted.

第一件事:你定义了两个黑色线性布局来获得你发布的UI。

Second thing : you need cut the picture from full picture to square picture.

第二件事:你需要把整幅画剪成正方形。

How to cut, you need use scaleBitmap method.

如何切割,需要使用scaleBitmap方法。

Or you want real Custom Camera? Can check in here

或者你想要真正的定制相机?可以检查在这里