无论在Camera1或者Camera2在适配不一样手机/不一样使用场景的状况下都须要计算摄像头里提供的分辨率列表中最合适的那一个分辨率.因此在须要大量机型适配的app,是不建议不通过计算直接自定义分辨率设置到预览或者拍照照片中,有几率会由于摄像头不支持你输入的自定义分辨率致使报错或者打不开摄像头.算法
若是你的确有需求要自定义分辨率,那么使用场景只有一个那就是你是在开发Android设备,而且你输入的自定义分辨率肯定在这个设备上不会报错.数组
目前本人总结的2个分辨率计算方法有2个:app
下面我就来解释这个2个计算方法.spa
较为歪门邪道的方法,核心就是TextureView的宽高比与摄像头的高宽比作差值比较,注意这里一个是宽高一个是高宽,求出来的结果就是在指定指定比例最接近正方形的分辨率code
优势:由于是正方形的分辨率,因此在预览的时候无论是什么尺寸的TextureView的都能显示的不会变形.因此比较适合在小尺寸TextureView上orm
缺点:在预览的时候其实没法彻底显示完整(正方形无论怎么样都有可能上下或者左右超出View的大小),因此TextureView会自动忽略四周部分,只显示最中间的部分.这样拍照的时候就会发现预览与实际照片显示范围不一致.blog
/** * 获取匹配的大小 这里是Camera2获取分辨率数组的方式,Camera1获取不一样,计算同样 * @return */ private Size getMatchingSize(){ Size selectSize = null; float selectProportion = 0; try { float viewProportion = (float)mTextureView.getWidth() / (float)mTextureView.getHeight();//计算View的宽高比 CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentCameraId); StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG); for (int i = 0; i < sizes.length; i++){ Size itemSize = sizes[i]; float itemSizeProportion = (float)itemSize.getHeight() / (float)itemSize.getWidth();//计算当前分辨率的高宽比 float differenceProportion = Math.abs(viewProportion - itemSizeProportion);//求绝对值 Log.e(TAG, "相减差值比例="+differenceProportion ); if (i == 0){ selectSize = itemSize; selectProportion = differenceProportion; continue; } if (differenceProportion <= selectProportion){ //判断差值是否是比以前的选择的差值更小 if (differenceProportion == selectProportion){ //若是差值与以前选择的差值同样 if (selectSize.getWidth() + selectSize.getHeight() < itemSize.getWidth() + itemSize.getHeight()){//选择分辨率更大的Size selectSize = itemSize; selectProportion = differenceProportion; } }else { selectSize = itemSize; selectProportion = differenceProportion; } } } } catch (CameraAccessException e) { e.printStackTrace(); } Log.e(TAG, "getMatchingSize: 选择的比例是="+selectProportion); Log.e(TAG, "getMatchingSize: 选择的尺寸是 宽度="+selectSize.getWidth()+"高度="+selectSize.getHeight()); return selectSize; }
这个是最正常的算法了,核心就是找到与屏幕宽度最接近的分辨率,而后在找最接近屏幕高度的分辨率.这里是屏幕宽度是最高优先级的,其次在知足高度.开发
优势:预览图像与拍照照片的效果彻底一致.get
缺点:it
在看代码前这里说明一个重要知识!摄像头分辨率的宽度和高度与屏幕分辨率的宽度和高度的对应
1.摄像头分辨率的宽度和高度实际上是手机横屏下的才是正确方向.以下图所示
2.屏幕的分辨率的宽度和高度依然是手机竖屏下的高度和宽度.
代码部分
private Size getMatchingSize2(){ Size selectSize = null; try { CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentCameraId); StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); //由于我这里是将预览铺满屏幕,因此直接获取屏幕分辨率 int deviceWidth = displayMetrics.widthPixels; //屏幕分辨率宽 int deviceHeigh = displayMetrics.heightPixels; //屏幕分辨率高 Log.e(TAG, "getMatchingSize2: 屏幕密度宽度="+deviceWidth); Log.e(TAG, "getMatchingSize2: 屏幕密度高度="+deviceHeigh ); /** * 循环40次,让宽度范围从最小逐步增长,找到最符合屏幕宽度的分辨率, * 你要是不放心那就增长循环,确定会找到一个分辨率,不会出现此方法返回一个null的Size的状况 * ,可是循环越大后获取的分辨率就越不匹配 */ for (int j = 1; j < 41; j++) { for (int i = 0; i < sizes.length; i++) { //遍历全部Size Size itemSize = sizes[i]; Log.e(TAG,"当前itemSize 宽="+itemSize.getWidth()+"高="+itemSize.getHeight()); //判断当前Size高度小于屏幕宽度+j*5 && 判断当前Size高度大于屏幕宽度-j*5 && 判断当前Size宽度小于当前屏幕高度 if (itemSize.getHeight() < (deviceWidth + j*5) && itemSize.getHeight() > (deviceWidth - j*5)) { if (selectSize != null){ //若是以前已经找到一个匹配的宽度 if (Math.abs(deviceHeigh-itemSize.getWidth()) < Math.abs(deviceHeigh - selectSize.getWidth())){ //求绝对值算出最接近设备高度的尺寸 selectSize = itemSize; continue; } }else { selectSize = itemSize; } } } if (selectSize != null){ //若是不等于null 说明已经找到了 跳出循环 break; } } } catch (CameraAccessException e) { e.printStackTrace(); } Log.e(TAG, "getMatchingSize2: 选择的分辨率宽度="+selectSize.getWidth()); Log.e(TAG, "getMatchingSize2: 选择的分辨率高度="+selectSize.getHeight()); return selectSize; }