我的问题很简单:
如何以1:1的比例获得Android
android.hardware.Camera2
并且不像Instagram那样变形?
我使用GoogeSamples项目android-Camera2Basic进行了测试。但是当我以1:1的比例更改预览时,图像会变形。有没有人对此有所了解?
答案 0 :(得分:4)
感谢@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);
}
}
}
}
答案 1 :(得分:1)
像这样创建自定义纹理视图:
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();
答案 2 :(得分:1)
我用布局做到了这一点,谷歌代码可以保持原样,并根据用户界面自动设置1:1预览。
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/footer"
android:layout_below="@id/header">
<com.example.android.camera2video.AutoFitTextureView
android:id="@+id/texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintDimensionRatio="w,1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
将AutoFitTextureView放入ConstraintLayout然后
previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
width, height, videoSize);
做所有的魔法
答案 3 :(得分:1)
对于寻找此内容的任何人,我都尝试过above answer。添加边距以隐藏Textureview的一部分以使其看起来像正方形,在预览中看起来不错。但是在保存图像时,还应该从输出图像中删除隐藏区域。
一种更简单的解决方案是显示完整的textureview并在其上叠加其他布局以使其看起来像正方形。您可以轻松地从输出中裁剪图像。
您可以找到示例代码here