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

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

1.     Surfaceview的大小android

2.     Camera中的Preview的大小ide

以下图:

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

 

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

若是surfaceview尺寸比例跟预览尺寸比例相同,那便不会产生变形,以下图:this

 

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

上面只是针对一种屏幕进行设置,并且每台手机所支持的预览尺寸是不同的,因此这样子固定死的话极可能会产生程序崩溃,而崩溃的缘由是由于该手机不支持你所支持的尺寸。.net

 

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

思路以下:code

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

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

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;
    }
}

 

 

 
相关文章
相关标签/搜索