栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android Camera 预览拉伸问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android Camera 预览拉伸问题

预览会出现拉伸的问题代码:
预览拉伸Demo


预览画面拉伸问题改正的 gitee 代码在文章最后给出
预览拉伸的原因:
每颗Camera都支持一些分辨率,Camera的这些图像如果和预览画面的宽高比例不一致就会发生预览图像拉伸。注意这里是宽高比,只要宽高比一致,即使宽高的大小不一样也不会拉伸。
另外:旋转手机时 Camera 也会旋转,但是预览画面不会旋转,这会导致 Camera 图像原来的宽映射到预览画面的高, Camera 图像原来的高映射到预览画面的宽。由于手机画面的尺寸一般都不是 1 :1 的,所以当手机旋转时,预览画面一定会产生拉伸的效果。

预览拉伸的解决办法:
将预览画面的宽高比设置为和 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 sizeList = new ArrayList(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);
    }

    
    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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/691359.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号