如何获得像Instagram一样的1:1比例的Android Camera2?

我的问题很简单:

如何以1:1的比例获得Android android.hardware.Camera2并且不像Instagram一样变形?

我测试了GoogeSamples项目android-Camera2Basic 。 但是当我以1:1的比例更改预览时,图像会变形。 有没有人对此有所了解?

在此处输入图像描述

谢谢@CommonsWare。

我使用负边距(顶部和底部)跟随你的建议,它的工作原理。

要做到这一点,我只需更新AutoFitTextureView GoogeSamples项目android-Camera2Basic :

 public class AutoFitTextureView extends TextureView { //... private boolean mWithMargin = false; //... @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int margin = (height - width) / 2; if(!mWithMargin) { mWithMargin = true; ViewGroup.MarginLayoutParams margins = ViewGroup.MarginLayoutParams.class.cast(getLayoutParams()); margins.topMargin = -margin; margins.bottomMargin = -margin; margins.leftMargin = 0; margins.rightMargin = 0; setLayoutParams(margins); } if (0 == mRatioWidth || 0 == mRatioHeight) { setMeasuredDimension(width, height); } else { if (width < height) { setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); } else { setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); } } } } 

在此处输入图像描述

像这样创建自定义纹理视图:

 public class AutoFitTextureView extends TextureView { private int mCameraWidth = 0; private int mCameraHeight = 0; private boolean mSquarePreview = false; public AutoFitTextureView(Context context) { this(context, null); } public AutoFitTextureView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setAspectRatio(int width, int height, boolean squarePreview) { if (width < 0 || height < 0) { throw new IllegalArgumentException("Size cannot be negative."); } mCameraWidth = width; mCameraHeight = height; mSquarePreview = squarePreview; requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (0 == mCameraWidth || 0 == mCameraHeight) { setMeasuredDimension(width, height); } else { /** * Vertical orientation */ if (width < height) { if (mSquarePreview) { setTransform(squareTransform(width, height)); setMeasuredDimension(width, width); } else { setMeasuredDimension(width, width * mCameraHeight / mCameraWidth); } } /** * Horizontal orientation */ else { if (mSquarePreview) { setTransform(squareTransform(width, height)); setMeasuredDimension(height, height); } else { setMeasuredDimension(height * mCameraWidth / mCameraHeight, height); } } } } private Matrix setupTransform(int sw, int sh, int dw, int dh) { Matrix matrix = new Matrix(); RectF src = new RectF(0, 0, sw, sh); RectF dst = new RectF(0, 0, dw, dh); RectF screen = new RectF(0, 0, dw, dh); matrix.postRotate(-90, screen.centerX(), screen.centerY()); matrix.mapRect(dst); matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER); matrix.mapRect(src); matrix.setRectToRect(screen, src, Matrix.ScaleToFit.FILL); matrix.postRotate(-90, screen.centerX(), screen.centerY()); return matrix; } private Matrix squareTransform(int viewWidth, int viewHeight) { Matrix matrix = new Matrix(); if (viewWidth < viewHeight) { MyLogger.log(AutoFitTextureView.class, "Horizontal"); matrix.setScale(1, (float) mCameraHeight / (float) mCameraWidth, viewWidth / 2, viewHeight / 2); } else { MyLogger.log(AutoFitTextureView.class, "Vertical"); matrix.setScale((float) mCameraHeight / (float) mCameraWidth, 1, viewWidth / 2, viewHeight / 2); } return matrix; } } 

并在activity / fragment中为您的纹理视图调用setAspectRatio。

 if (mVideoSize.width > mVideoSize.height) { mTextureView.setAspectRatio(mVideoSize.height, mVideoSize.width, true); } else { mTextureView.setAspectRatio(mVideoSize.width, mVideoSize.height, true); } mCamera.setPreviewTexture(mTextureView.getSurfaceTexture()); mCamera.startPreview(); 

我用布局做到了这一点,谷歌代码可以保持原样,并根据用户界面自动设置1:1预览。

     

只需将AutoFitTextureView放在ConstraintLayout中即可

previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, videoSize); 做所有的魔力