Android 如何在平方 SurfaceView(如 Instagram)中将相机预览大小设置为平方纵横比
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11121963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I set camera preview size to squared aspect ratio in a squared SurfaceView (like Instagram)
提问by cesards
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 相框非常相似的东西,这就是我得到的:
When I should get something like this:
当我应该得到这样的东西时:
and...
和...
when I should get something like:
当我应该得到类似的东西时:
I think I'm maanaging the SurfaceView and Camera preview well, only using
我想我很好地管理 SurfaceView 和相机预览,只使用
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?? :-(
我做错了什么??:-(
采纳答案by xramos
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 用于 SurfacePreview。似乎您有纵横比问题,也许您有正确的预览尺寸,但您将其放置在不正确的布局中。
Another solution might be (just like Instagram does) to make your camera at full size and then hide some areas of the layout 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
希望这对你有帮助
回答by Ycastan
The solution that works for me is the 2nd Answer, but because we need to rotate the camera 90o is necessary to switch the WIDTH with the HEIGTH, something like this...
对我有用的解决方案是第二个答案,但是因为我们需要将相机旋转 90o 才能将宽度与高度切换,就像这样......
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
回答by YadirHB
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 版本,您可能需要添加另一个构造函数重载。对于 Kitkat 来说,这很好。
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”是用来渲染预览的,它居中并且有一个包含平方组件的LinearLayout。这实际上是“面具”,它涵盖了相机预览。还要注意,除了 SquaredFrame 是透明的,其他两个都是黑色的背景色。
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
现在一切都必须绑定在活动类中
@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. :-)
有点长,但我希望它对不止一个人有帮助。:-)
回答by Martin ?uráb
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://stackoverflow.com/a/39430615/5181489
我在方形视图中遇到了同样的问题 - 只需将 SurfaceView 的相机大小设置为我想要绘制它的视图的大小即可解决它。没有复杂的计算,它对我有用。整个方法见我的回复:https: //stackoverflow.com/a/39430615/5181489
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
...
params.setPreviewSize(viewParams.height, viewParams.width);
camera.setParameters(params);
回答by Huy Tower
It's so hard. Not easily.
它是如此艰苦。不容易。
First thing : You define 2 black Linear Layout
to get the UI as you posted.
第一件事:您定义 2 blackLinear Layout
以在您发布时获取 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
或者你想要真正的定制相机?可以在这里办理入住
回答by shailesh
You can use this to get 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");
}
}