Android Camera 预览拉伸问题

预览会出现拉伸的问题代码:
预览拉伸Demo
在这里插入图片描述

竖屏拉伸

横屏拉伸
预览画面拉伸问题改正的 gitee 代码在文章最后给出
预览拉伸的原因:
每颗Camera都支持一些分辨率,Camera的这些图像如果和预览画面的宽高比例不一致就会发生预览图像拉伸。注意这里是宽高比,只要宽高比一致,即使宽高的大小不一样也不会拉伸。
另外:旋转手机时预览画面拉伸非常严重。
预览拉伸的解决办法:
将预览画面的宽高比设置为和 Camera 输出画面的宽高比一致

步骤
1.列出这颗 Camera 支持的所有 Size,以及手机的 width 和 height
2.遍历选择一个 Size,算出这个 Size 的宽高比 ratio = size.height / size.width(因为Camera Size的宽高是相反的)
3.以手机的宽作为预览控件的宽,如果得出的 ratio 使得控件的 height 超过手机的 height ,那么 遍历下一个Size 重复步骤2,直到选出一个合适的 Size。如果所有的 Size 的高都比手机的高都大,那么就需要使用 Matrix 手动将 Camera 输出的画面缩放到一个合适的大小,最后这种情况先不实现。
两点注意:
1.Camera 支持的所有 Size ,它的 size.width 和 size.height 是反着的,我们要把 size.width 当成高 ,size.height 当成宽。
2.预览控件在设置宽高比的时候,要保证预览画面的宽和手机的宽是一样的,这样看起来才不别扭。

预览控件的宽应该设置为 match_parent,高应该设置为 wrap_content
假设要设置的宽高比 ratio = cameraWidth / cameraHeight,
预览控件在设置宽高比的时候只改变高度即可: height = width / ratio

也许你会发现,这里我们并没有针对横屏的预览显示做处理,实际测试中发现,我们设置完宽高比,在旋转到横屏的时候也不会发生预览拉伸。
竖屏
横屏
关键代码:

private Size getBestSize() {
	CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
	CameraCharacteristics characteristics = null;
	try {
	    characteristics = cameraManager.getCameraCharacteristics("0");
	} catch (CameraAccessException e) {
	    e.printStackTrace();
	}
	
	// 获得手机的宽高
	Point point = new Point();
	((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(point);
	int phone_width = point.x;
	int phone_height = point.y;
	Log.e(TAG, "phone_width = "+phone_width+", phone_height = "+phone_height );
	// 获取这颗Camera支持的Size
	StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
	ArrayList<Size> sizeList = new ArrayList<Size>(Arrays.asList(map.getOutputSizes(SurfaceTexture.class)));
	for (Size size : sizeList) {
	    Log.e(TAG, "width = "+size.getWidth() +", height = "+size.getHeight());
	    double ratio = (double) size.getHeight() / (double)size.getWidth();
	    // 以手机的宽作为控件的宽,计算出控件的高
	    int height = (int) (phone_width / ratio);
	    Log.e(TAG, "ratio = " + ratio + ", height = " + height);
	    // 如果计算出的控件的高超过手机的高,就遍历下一个
	    if (height > phone_height) {
	        continue;
	    }
	    else {
	        return size;
	    }
}
// 没有合适的宽高比
return null;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.TextureView;

public class AutoFitTextureView extends TextureView {
    private static final String TAG = "hugang";

    private int ratioW = 0;
    private int ratioH = 0;

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

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

    public AutoFitTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 设置宽高比
     * @param width
     * @param height
     */
    public void setAspectRation(int width, int height){
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("width or height can not be negative.");
        }
        ratioW = width;
        ratioH = height;
        Log.e(TAG, "setAspectRation: ratioW = "+ratioW+" ratioH = "+ratioH );
        //请求重新布局
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        Log.e(TAG, "onMeasure: width = "+width+" height = "+height );
        if (0 == ratioW || 0 == ratioH){
            //未设定宽高比,使用预览窗口默认宽高,当AutoFitTextureView初始化的时候会走一次这个逻辑
            setMeasuredDimension(width, height);
            Log.e(TAG, "onMeasure 000: width = "+width+" height = "+height );
        } else {
            //设定宽高比,调整预览窗口大小(调整后窗口大小不超过默认值)
            if (width < height * ratioW / ratioH) {
                Log.e(TAG, "onMeasure 111: width = "+width+" height = "+(width * ratioH / ratioW) );
                setMeasuredDimension(width, width * ratioH / ratioW);
            } else {
                Log.e(TAG, "onMeasure 222: width = "+(height * ratioW / ratioH)+" height = "+height );
                setMeasuredDimension(height * ratioW / ratioH, height);
            }
        }
    }
}

解决预览画面拉伸的Demo
预览画面拉伸问题改正Demo
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值