我们公司的相机是自定义的相机。在一些全面屏上有一些显示拉伸的问题。出现问题的手机有三星s8,华为mate10,并且系统是8.0的。我手机是s8,在升级8.0前确认是没有问题的,升级了8.0后拍照和扫描二维码出现了显示的图像变扁的问题。当时还以为是系统的bug。一看果然,刚升级8.0没几天,三星就由发布了一个8.0的补丁,里面的内容有修复相机bug的字样。当时还是比较开心的,以为跟新完就没事了,结果更新完后,没卵用。。。。。在打开微信的相机和扫一扫发现他们的没问题。就觉得他们应该处理过这个问题。
解决这个问题要先明白几个地方:
1. Camera.Params 的setPreviewSize方法和 setPictureSize方法
这俩个方法参数都是Size,并且这俩个size最好一致,不然就会有图像拉伸的问题。而这个size也不能自己想一个数来设置,必须获取系统支持的并且合适的值。查看系统支持的size的方法是:
Params.getSupportedPictureSizes()
Params.getSupportedPreviewSizes()
我的手机是s8他支持的对应的size如下:
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: =============================================================================
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width4032 height:3024
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width4032 height:2268
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width3984 height:2988
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width3264 height:2448
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width3264 height:1836
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width3024 height:3024
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2976 height:2976
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2880 height:2160
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2560 height:1920
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2560 height:1440
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2160 height:2160
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width2048 height:1152
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width1920 height:1080
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width1440 height:1080
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width1280 height:960
05-08 15:00:18.836 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width1280 height:720
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PictureSizes: width640 height:480
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: =============================================================================
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:1920 height:1080
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:1440 height:1080
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:1088 height:1088
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:1280 height:720
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:960 height:720
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:720 height:720
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:720 height:480
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:640 height:480
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:352 height:288
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:320 height:240
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: PreviewSizes: width:176 height:144
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: =============================================================================
既然不能瞎写,哪我们怎么去找一个合适的size呢?这还要个问题要注意,返回的数据有可能是正序的也有可能是倒序的。为了方便处理我们要先对其进行排序。并且,因为默认摄像头方向是水平的,我们在使用的时候要旋转90度,所以这里的width实际上是高度,heigth实际上是宽度,下面给出选择方法:
/**
* 获取pictureSize的合适值
* @param list size集合
* @param th 设置的最小宽度
* @param rate 传入的宽高比
* @return
*/
public Camera.Size getPictureSize(List<Camera.Size> list, int th, float rate) {
Collections.sort(list, sizeComparator); //统一以升序的方式排列
int i = 0;
for (Camera.Size s : list) {
if ((s.width > th) && equalRate(s, rate)) { //合适参数的判断条件, 大于我们传入的最小高度且宽高比的差值不能超过0.2
Log.i(TAG, "MakeSure Picture :w = " + s.width + " h = " + s.height);
break;
}
i++; //拿到最合适的参数
}
if (i == list.size()) { //如果到最后也没有找到合适的,哪么就放宽条件去找
return getBestSize(list, rate);
} else {
return list.get(i); //返回找到的合适size
}
}
/**
* 遍历所有的size,找到和传入的宽高比的差值最小的一个
* @param list
* @param rate
* @return
*/
private Camera.Size getBestSize(List<Camera.Size> list, float rate) {
float previewDisparity = 100;
int index = 0;
for (int i = 0; i < list.size(); i++) {
Camera.Size cur = list.get(i);
float prop = (float) cur.width / (float) cur.height;
if (Math.abs(rate - prop) < previewDisparity) {
previewDisparity = Math.abs(rate - prop);
index = i;
}
}
return list.get(index);
}
private boolean equalRate(Camera.Size s, float rate) {
float r = (float) (s.width) / (float) (s.height);
return Math.abs(r - rate) <= 0.2; //传入的宽高比和size的宽高比的差不能大于0.2,要尽量的和传入的宽高比相同
}
private class CameraSizeComparator implements Comparator<Camera.Size> {
public int compare(Camera.Size lhs, Camera.Size rhs) {
if (lhs.width == rhs.width) {
return 0;
} else if (lhs.width > rhs.width) {
return 1;
} else {
return -1;
}
}
}
获取previewSize的方法一样。
2.那么在显示的时候要保证pictureSize和previewSize尽量保证一样,然后相机的预览界面也要保证尽量和这俩个size一样。我获取的合适的pictureSize和previewSize如下:
05-08 15:00:18.837 8451-8574/com.example.wangxu.testcream I/CameraInterface: suitable:picture_width:1280 picture_height:720 preview_width:1280 preview_height:720
可以发现显示是一样的,那么我设置的预览界面有多大了?
05-08 15:49:23.349 28180-28180/com.example.wangxu.testcream I/JCameraView: screenSize: width:1665.0 height:2960.0
那么他们的比值了?
1280/720 = 1.7777
2960/1665 = 2.0
这。。。将宽高比1.7的的图片显示在宽高比2.0的布局里面,所以被拉伸了。所以我们要做的就是缩放布局,让他的宽高比也到1.7就好。这里就是缩放预览控件的方法:
private void setSuitableParams() {
if (screenProp > 1.8) { //屏幕的宽高比大于1.8的时候处理
float previewProp = CameraInterface.getInstance().getPreviewProp();
if (previewProp == 0 || mVideoView == null) { //获取的size宽高比
return;
}
int measuredHeight = mVideoView.getMeasuredHeight();
int measuredWidth = mVideoView.getMeasuredWidth();
float clacWidth = measuredHeight / previewProp; //计算出要显示的预览界面的宽度。
ViewGroup.LayoutParams layoutParams = mVideoView.getLayoutParams();
if (layoutParams == null) {
layoutParams = new ViewGroup.LayoutParams((int) clacWidth, measuredHeight);
}
if (clacWidth > 800 && Math.abs(clacWidth - measuredWidth) > clacWidth * 0.1F) { //计算的宽度大于 800 并且和显示正常的布局的误差超过10%
layoutParams.width = (int) clacWidth;
}
final ViewGroup.LayoutParams finalLayoutParams = layoutParams;
mVideoView.post(new Runnable() {
@Override
public void run() {
if (mVideoView != null && finalLayoutParams != null) {
mVideoView.setLayoutParams(finalLayoutParams);
}
}
});
}
}
需要注意的是,因为我们将预览的布局进行了宽度的方大(全面屏是高度相对于宽度变大了),所以有部分宽度是在屏幕外面了,我们实际拍摄的图片的宽度大于预览界面上图片的宽度。
最后,为啥在8.0以下全面屏没事了。到底8.0对于相机做了啥,还不知道,如果有知道的小伙伴希望告知下。