android camera中的预览图片变形的解决办法

泡在网上的日子 / 文 发表于2013-07-22 21:08 次阅读 Camera,android

之前处理相机模块的时候,遇到了一个问题,就是调用系统的camera的时候在拍照预览界面的时候看到的照片是变形的。不晓得大家有没有和我遇到一样的问题,后来发现是我的布局界面没有按对应的比例进行缩放导致的。后来参考了系统camera中的代码解决了这个问题,特此记录下来。每部手机中设置了好几组预览图片的尺寸、以及实际图片的尺寸。只有当预览图的尺寸比例和实际图片的比例相同的时候就不会出现变形的情况。下面一组数据是我测试中记录的一组数据:

02-09 19:00:40.831: D/tag(27507): pictureSizeValueString : 1280x960,1600x1200,2048x1536,2592x1456,2592x1936
02-09 19:00:40.831: D/tag(27507): previewSizeValueString : 176x144,320x240,352x288,640x480,720x480,720x576,848x480,1280x720

上面红色部分标记的都是具有相同比例的尺寸,都为4:3,而其他比例却不尽相同。故我们只要在初始化camera的时候给其设置好相同比例的预览图尺寸和实际图的尺寸,并且设置你的SurfaceView或者VideoView的尺寸比例相同就行了。但是要注意的是:魅族手机貌似取不到这些值。

@Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            //设置参数
            mCamera = Camera.open();
            //摄像头画面显示在Surface上
            mCamera.setPreviewDisplay(surfaceHolder);
                      
            Parameters parameters = mCamera.getParameters();
        } catch (IOException e) {
            if (mCamera != null) mCamera.release();
            mCamera = null;
        }
                  
        if (mCamera == null) {
            finish();
            return ;
        }
        updateCameraParameters();
        mCamera.startPreview();   
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        try {
            //摄像头画面显示在Surface上
            mCamera.setPreviewDisplay(surfaceHolder);
            updateCameraParameters();
            mCamera.startPreview();   
        } catch (IOException e) {
            if (mCamera != null) mCamera.release();
            mCamera = null;
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();
        //关闭预览
        mCamera.release();
        //释放资源
    }



private void updateCameraParameters() {
        if (mCamera != null) {
            Camera.Parameters p = mCamera.getParameters();
               
            long time = new Date().getTime();
            p.setGpsTimestamp(time);
               
            Size pictureSize = findBestPictureSize(p);
            p.setPictureSize(pictureSize.width, pictureSize.height);
               
            // Set the preview frame aspect ratio according to the picture size.
            Size size = p.getPictureSize();
            PreviewFrameLayout frameLayout = (PreviewFrameLayout) findViewById(R.id.frame_layout);
            frameLayout.setAspectRatio((double) size.width / size.height);
               
            Size previewSize = findBestPreviewSize(p);
            p.setPreviewSize(previewSize.width,previewSize.height);
               
            mCamera.setParameters(p);
               
            int supportPreviewWidth = previewSize.width;
            int supportPreviewHeight = previewSize.height;
               
            int srcWidth = getScreenWH().widthPixels;
            int srcHeight = getScreenWH().heightPixels;
               
            int width = Math.min(srcWidth, srcHeight);
            int height = width * supportPreviewWidth / supportPreviewHeight ;
              
            mSur.setLayoutParams(new FrameLayout.LayoutParams(height, width));//
        }
    }
       
    private Size findBestPictureSize(Camera.Parameters parameters) {
        int  diff = Integer.MIN_VALUE;
        String pictureSizeValueString = parameters.get("picture-size-values");
            
         // saw this on Xperia
         if (pictureSizeValueString == null) {
             pictureSizeValueString = parameters.get("picture-size-value");
         }
            
         if(pictureSizeValueString == null) {
             return  mCamera.new Size(getScreenWH().widthPixels,getScreenWH().heightPixels);
         }
            
         Log.d("tag", "pictureSizeValueString : " + pictureSizeValueString);
         int bestX = 0;
         int bestY = 0;
           
           
         for(String pictureSizeString : COMMA_PATTERN.split(pictureSizeValueString))
         {
             pictureSizeString = pictureSizeString.trim();
                
             int dimPosition = pictureSizeString.indexOf('x');
             if(dimPosition == -1){
                 Log.e(TAG, "Bad pictureSizeString:"+pictureSizeString);
                 continue;
             }
                
             int newX = 0;
             int newY = 0;
                
             try{
                 newX = Integer.parseInt(pictureSizeString.substring(0, dimPosition));
                 newY = Integer.parseInt(pictureSizeString.substring(dimPosition+1));
             }catch(NumberFormatException e){
                 Log.e(TAG, "Bad pictureSizeString:"+pictureSizeString);
                 continue;
             }
               
             Point screenResolution = new Point (getScreenWH().widthPixels,getScreenWH().heightPixels);
                
             int newDiff = Math.abs(newX - screenResolution.x)+Math.abs(newY- screenResolution.y);
                 if(newDiff == diff)
                 {
                     bestX = newX;
                     bestY = newY;
                     break;
                 } else if(newDiff > diff){
                     if((3 * newX) == (4 * newY)) {
                         bestX = newX;
                         bestY = newY;
                         diff = newDiff;
                     }
                 }
             }
                
         if (bestX > 0 && bestY > 0) {
            return mCamera.new Size(bestX, bestY);
         }
        return null;
    }
       
    private Size findBestPreviewSize(Camera.Parameters parameters) {
           
         String previewSizeValueString = null;
         int diff = Integer.MAX_VALUE;
         previewSizeValueString = parameters.get("preview-size-values");
            
         if (previewSizeValueString == null) {
             previewSizeValueString = parameters.get("preview-size-value");
         }
           
         if(previewSizeValueString == null) {  // 有些手机例如m9获取不到支持的预览大小   就直接返回屏幕大小
             return  mCamera.new Size(getScreenWH().widthPixels,getScreenWH().heightPixels);
         }
         Log.d("tag", "previewSizeValueString : " + previewSizeValueString);
         int bestX = 0;
         int bestY = 0;
           
         for(String prewsizeString : COMMA_PATTERN.split(previewSizeValueString))
         {
             prewsizeString = prewsizeString.trim();
                
             int dimPosition = prewsizeString.indexOf('x');
             if(dimPosition == -1){
                 Log.e(TAG, "Bad prewsizeString:"+prewsizeString);
                 continue;
             }
                
             int newX = 0;
             int newY = 0;
                
             try{
                 newX = Integer.parseInt(prewsizeString.substring(0, dimPosition));
                 newY = Integer.parseInt(prewsizeString.substring(dimPosition+1));
             }catch(NumberFormatException e){
                 Log.e(TAG, "Bad prewsizeString:"+prewsizeString);
                 continue;
             }
               
             Point screenResolution = new Point (getScreenWH().widthPixels,getScreenWH().heightPixels);
                
             int newDiff = Math.abs(newX - screenResolution.x)+Math.abs(newY- screenResolution.y);
                
             if(newDiff == diff)
             {
                 bestX = newX;
                 bestY = newY;
                 break;
             } else if(newDiff < diff){
                 if((3 * newX) == (4 * newY)) {
                     bestX = newX;
                     bestY = newY;
                     diff = newDiff;
                 }
             }
         }
         if (bestX > 0 && bestY > 0) {
            return mCamera.new Size(bestX, bestY);
         }
        return null;
    }
       
     protected DisplayMetrics getScreenWH() {
        DisplayMetrics dMetrics = new DisplayMetrics();
        dMetrics = this.getResources().getDisplayMetrics();
        return dMetrics;
     }


收藏 赞 (9) 踩 (14)
上一篇:Android Camera 使用详解
Android Camera 使用小结 Android手机关于Camera的使用,一是拍照,二是摄像,由于Android提供了强大的组件功能,为此对于在Android手机系统上进行Camera的开发,我们可以使用两类方法:一是借助Intent和MediaStroe调用系统Camera App程序来实现拍照和摄像功
下一篇:多个Activity之间共享数据的5种方式以及 Application Context
今天面试安卓开发岗位的时候,面试官问了我一个很简单的问题:个Activity之间如何共享数据 。一时只回答了intent和广播两种方式。回来一查,发现自己的回答很不靠谱。 其实有如下5种方式: 1.基于消息的通信机制 Intent ---boudle ,extra 数据类型有限,比如