• Android Camera多屏幕适配解决预览照片拉伸


    通常,拍照预览页面的照片拉伸主要与下面两个因素有关:

    1.     Surfaceview的大小

    2.     Camera中的Preview的大小

    如下图:

        图中preview显示的是手机支持的预览尺寸,picture显示的是手机支持设置图片尺寸,screen显示的是屏幕尺寸,surface显示的是surfaceview尺寸,default pre:手机缺省情况下的预览尺寸,default pic:手机缺省请款下的图片尺寸。reqPreview:手机设置的预览尺寸,reqPicSize:手机设置的图片尺寸。
     

     

    如图,该手机surfaceview大小为1280*720(横屏,比例为:16:9)预览尺寸大小为960*720(横屏,比例为4:3)。从上面的二维码可以看到产生了明显的拉伸。正因为surfaceview的宽高比例跟camera preview的宽高比例不一样才会产生这样的效果。

    如果surfaceview尺寸比例跟预览尺寸比例相同,那便不会产生变形,如下图:

    设置surfaceview大小为 1280*720(横屏,比例为:4:3)预览尺寸大小为2048*1152(横屏,比例为4:3)便不会拉伸变形。

    上面只是针对一种屏幕进行设置,而且每台手机所支持的预览尺寸是不一样的,所以这样子固定死的话很可能会产生程序崩溃,而崩溃的原因是因为该手机不支持你所支持的尺寸。

    那么问题就来了,怎么样才能够达到适配多台手机,界面不产生拉伸变形,而且程序又不崩溃?

    思路如下:

    1.     先将获取手机支持预览的尺寸列表通过方法parmeters.getSupportedPreviewSizes()来得到返回类型为List<Size>的值,

    2.     先进行屏幕方向的一个判断,因为预览列表里面的尺寸都是w>h(即横屏),如果屏幕是竖屏则需要先将宽高进行调换,这样方便接下来的比较。

    3.     先用for循环将预览尺寸列表每个元素宽高与surfaceview的宽高进行比较,如果存在宽高尺寸都与surfaceview宽高尺寸相同的size则将该宽高设置为预览尺寸。

    4.     如果步骤2找不到相同尺寸就得进行该步骤,将尺寸列表的宽高比例和surfaceview的比例作比较,找到一个相同或相近的。(一般来说,只要surfaceview的尺寸和屏幕尺寸相同,就可以找到相同的比例)然后将该尺寸的size设置为预览尺寸。

    接下来是上代码

      

    /**
         * 通过对比得到与宽高比最接近的尺寸(如果有相同尺寸,优先选择)
         * 
         * @param surfaceWidth
         *            需要被进行对比的原宽
         * @param surfaceHeight
         *            需要被进行对比的原高
         * @param preSizeList
         *            需要对比的预览尺寸列表
         * @return 得到与原宽高比例最接近的尺寸
         */
        protected Camera.Size getCloselyPreSize(int surfaceWidth, int surfaceHeight,
                List<Size> preSizeList) {
            
            int ReqTmpWidth;
            int ReqTmpHeight;
            // 当屏幕为垂直的时候需要把宽高值进行调换,保证宽大于高
            if (mIsPortrait) {
                ReqTmpWidth = surfaceHeight;
                ReqTmpHeight = surfaceWidth;
            } else {
                ReqTmpWidth = surfaceWidth;
                ReqTmpHeight = surfaceHeight;
            }
            //先查找preview中是否存在与surfaceview相同宽高的尺寸
            for(Camera.Size size : preSizeList){
                if((size.width == ReqTmpWidth) && (size.height == ReqTmpHeight)){
                    return size;
                }
            }
            
            // 得到与传入的宽高比最接近的size
            float reqRatio = ((float) ReqTmpWidth) / ReqTmpHeight;
            float curRatio, deltaRatio;
            float deltaRatioMin = Float.MAX_VALUE;
            Camera.Size retSize = null;
            for (Camera.Size size : preSizeList) {
                curRatio = ((float) size.width) / size.height;
                deltaRatio = Math.abs(reqRatio - curRatio);
                if (deltaRatio < deltaRatioMin) {
                    deltaRatioMin = deltaRatio;
                    retSize = size;
                }
            }
    
            return retSize;
        }

    其中 参数 width 和height 是 SurfaceView 的宽和高,可以在surfaceChanged方法中找到:

    package com.yfqsdie.tower.preview;
    
    import com.yfqsdie.tower.util.CameraUtil;
    
    import android.content.Context;
    import android.graphics.PixelFormat;
    import android.hardware.Camera;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    /**
     * Created by renlei
     * DATE: 15-11-5
     * Time: 下午4:52
     */
    public class MySurfacePreview extends SurfaceView implements SurfaceHolder.Callback {
        private SurfaceHolder surfaceHolder;
        private Handler mHandler;
    
        public MySurfacePreview(Context context, AttributeSet attrs) {
            super(context, attrs);
            surfaceHolder = getHolder();
            surfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半�?�明 transparent透明
            surfaceHolder.addCallback(this);
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            CameraUtil.getInstance().doOpenCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            System.out.print("width="+width+" height="+height+" format="+format);
    //        CameraUtil.getInstance().doStartPreview(surfaceHolder);
            CameraUtil.getInstance().doStartPreview(surfaceHolder,width,height);  //spire modify 2017-09-27 解决变形问题
            if (mHandler != null) {
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mHandler.sendEmptyMessage(CameraUtil.PREVIEW_HAS_STARTED);
                    }
                }, 1000);
            }
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            CameraUtil.getInstance().doStopPreview();
        }
    
        public void setmHandler(Handler handler) {
            this.mHandler = handler;
        }
    }
     
  • 相关阅读:
    【C语言】学习笔记8——结构struct(1)
    【算法导论】最大子数组——暴力求解
    【算法导论】最大子数组——递归
    【算法导论】二分查找
    【Linux】Linux服务器(centos7)环境搭建java/python3/nginx
    【算法导论】归并排序
    【C语言】第一个C语言小程序 —— 日期算法和万年历2
    【C语言】第一个C语言小程序 —— 日期算法和万年历
    【python】面向对象
    【java】对jdbc操作结果简单的映射封装
  • 原文地址:https://www.cnblogs.com/aspirant/p/7602151.html
Copyright © 2020-2023  润新知