一、前言

Android自定义相机开发中,常常会有通过手势放大或缩小相机预览画面的需求,即数码变焦DigitalZoom。

二、接口说明

1. 获取最大的放大倍数

float maxZoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);

怎么理解这个值呢?

假设正常预览画面(即没有缩放)矩形为 activity_rect,放大后的预览画面矩形为 crop_rect,那么它们宽高的比值最大就只能为 maxZoom,例如我测试中获取的该值为 10.0。(PS:activity_rect的宽高为分子,crop_rect的宽高是分母)

2. 获取未缩放的正常预览画面大小

Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

这个大小要用来计算我们最终放大后显示的画面大小。

3. 相机预览请求构造者设置显示的画面区域

mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);

计算得到的 zoomRect,通过上述接口设置给预览。

关于 SCALER_CROP_REGION ,详情可以参考:https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#SCALER_CROP_REGION

三、代码实现

1. 相机View处理触碰事件

private float mOldDistance;@Override
public boolean onTouchEvent(MotionEvent event) {if (event.getPointerCount() == 2) { // 当触碰点有2个时,才去放大缩小switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_POINTER_DOWN:// 点下时,得到两个点间的距离为mOldDistancemOldDistance = getFingerSpacing(event);break;case MotionEvent.ACTION_MOVE:// 移动时,根据距离是变大还是变小,去放大还是缩小预览画面float newDistance = getFingerSpacing(event);if (newDistance > mOldDistance) {mCameraProxy.handleZoom(true);} else if (newDistance < mOldDistance) {mCameraProxy.handleZoom(false);}// 更新mOldDistancemOldDistance = newDistance;break;default:break;}}return super.onTouchEvent(event);
}private static float getFingerSpacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return (float) Math.sqrt(x * x + y * y);
}

上面我们只处理了触碰事件,预览放大或缩小的逻辑由 mCameraProxy 的 handleZoom(boolean isZoomIn) 实现。

2. handleZoom() 实现

private final int MAX_ZOOM = 100; // 放大的最大值,用于计算每次放大/缩小操作改变的大小
private int mZoom = 0; // 缩放
private float mStepWidth; // 每次改变的宽度大小
private float mStepHeight; // 每次改变的高度大小// 每次切换摄像头计算一次就行,结果缓存到成员变量中
private void initZoomParameter() {Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);Log.d(TAG, "sensor_info_active_array_size: " + rect);// max_digital_zoom 表示 active_rect 除以 crop_rect 的最大值float max_digital_zoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);Log.d(TAG, "max_digital_zoom: " + max_digital_zoom);// crop_rect的最小宽高float minWidth = rect.width() / max_digital_zoom;float minHeight = rect.height() / max_digital_zoom;// 因为缩放时两边都要变化,所以要除以2mStepWidth = (rect.width() - minWidth) / MAX_ZOOM / 2;mStepHeight = (rect.height() - minHeight) / MAX_ZOOM / 2;
}public void handleZoom(boolean isZoomIn) {if (mCameraDevice == null || mCameraCharacteristics == null || mPreviewRequestBuilder == null) {return;}if (isZoomIn && mZoom < MAX_ZOOM) { // 放大mZoom++;} else if (mZoom > 0) { // 缩小mZoom--;}Log.v(TAG, "handleZoom: mZoom: " + mZoom);Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);int cropW = (int) (mStepWidth * mZoom);int cropH = (int) (mStepHeight * mZoom);Rect zoomRect = new Rect(rect.left + cropW, rect.top + cropH, rect.right - cropW, rect.bottom - cropH);Log.d(TAG, "zoomRect: " + zoomRect);mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);startPreview(); // 需要重新 start preview 才能生效
}

再简单说明一下上面的代码,因为本身maxZoom的值并不会很大,如果直接使用 1~maxZoom 的 int 值去放大缩小,画面变化就很剧烈,所以设置了一个 MAX_ZOOM = 100 去把这个过程划分成了100份,这个值可以自己设定。所以 mZoom 的判定范围也就变成了 0~MAX_ZOOM 。

再说计算 mStepWidth 和 mStepHeight 的代码。原Rect的宽是 rect.width(),放大到最大时 zoomRect 的宽是 rect.width() / maxZoom,因为有左右两边,所以它们的差值需要除以2,然后划分成 MAX_ZOOM 份,需要再除以 MAX_ZOOM 。

最后,放大时我们让 mZoom 自增1,缩小时让 mZoom 自减1,根据 mZoom 就可以得到剪裁的宽高大大小了。

四、工程地址

完整的代码可见:
https://github.com/afei-cn/CameraDemo/blob/master/app/src/main/java/com/afei/camerademo/camera/Camera2Proxy.java

相关使用实例可见:

自定义Camera系列之:SurfaceView + Camera2

自定义Camera系列之:TextureView + Camera2

自定义Camera系列之:GLSurfaceView + Camera2

Android Camera2相机预览画面放大缩小(数码变焦DigitalZoom)功能实现相关推荐

  1. Android Camera2 相机预览、获取数据

    Camera2简要说明 在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2),大幅提高了A ...

  2. v-viewer预览图的使用(图片预览旋转/放大缩小/上下切换等)

    前言: 之前项目需求,需要找一个预览图的组件,最开始,找了vue-preview组件.因为vue-preview是直接引入 < vue-preview>这个标签,无法看到对组件里面的图片i ...

  3. android+相机画面旋转,Android:相机预览的屏幕方向/旋转

    我已经创建了一个相机应用程序,我想让我的应用程序在所有4个可能的方向转换,并相应地更新相机预览.因为我已经使用我从以下复制的以下方法: Android – Camera preview is side ...

  4. android 圆形相机预览拍照_Android多种方式实现相机圆形预览

    最终效果图如下: 一.为预览控件设置圆角 public RoundTextureView(Context context, AttributeSet attrs) { super(context, a ...

  5. android 圆形相机预览拍照_Android多种方式实现相机圆形预览的示例代码

    效果图如下: 一.为预览控件设置圆角 public RoundTextureView(Context context, AttributeSet attrs) { super(context, att ...

  6. android自定义相机预览尺寸,相机在Android中,如何获得最佳尺寸,预览尺寸,图片尺寸,视图尺寸,图像扭曲...

    混合来自OpenGL和 Android相机的视图时图像失真,以便在使用takepicture方法时获取两者的图像.我查了一下,发现相机图片设置为640X480,openGL视图和相机预览都设置为128 ...

  7. 移动端查看预览图片放大缩小

    方法一 之前介绍过一款 移动端vue适用的插件大全 https://blog.csdn.net/MtangEr/article/details/85339092 里边有一篇是查看图片放大缩小的 htt ...

  8. Android Camera相机预览,拍照 ,横屏竖屏的处理

    功能分别是: 1.竖屏的前置,后置显示 加 拍照 2.横屏的前置,后置显示 加 拍照 整个项目的代码贴出来了,里面加了有备注,不理解的也可以去参考官网点击跳转到官网 首先选择前置后置布局效果如下 布局 ...

  9. Vue实现图片预览(放大缩小拖拽)纯手写

    这张图是显示的图片放大的一个预览情况,这里是参考预览操作实现的一个背景为黑色的部分,上层的图片可实现滚轮放大或者点击上部的放大镜图标进行放大,代码是基于Ant Design Vue框架的基础上 这里先 ...

最新文章

  1. 老信贷总结:贷款催收技巧和注意事项
  2. 最渣的 Spring Boot 文章
  3. Linux安装部署FTP服务器
  4. 胡斌、张礼礤会摧毁我们的信任
  5. Andriod Studio两种签名机制V1和V2的区别
  6. win98万能显卡驱动_win98/98系统 u盘万能驱动
  7. 青岛自然人税收管理系统服务器地址,青岛市自然人税收管理系统扣缴客户端
  8. 终于填了一个大坑:Python中如何处理《牛津高阶英汉词典》编码通不过问题(解决“UnicodeEncodeError”错误)
  9. 牛客编程语言练习赛第三场(C++)
  10. 第七周 位运算、布隆过滤、LUR和排序
  11. java安卓自动关机_android自动关机代码
  12. 当老板让我从 Java8 升到 Java11
  13. 做好个人时间管理的10个关键
  14. IOS游戏看广告后物理静音不能控制App声音
  15. C/C++语言的服务器LS调研 (Language Server 实现代码索引 跳转定义 智能提示等功能)
  16. Python学习记录 字典元素的访问
  17. openharmony中控屏开发:2.目标与价值
  18. Unity-PlayMaker开发学习笔记——简单的第三/第一人称控制器
  19. 查看linux下的字体
  20. Autosar Davinci Configurator新建工程以及导入DBC和CDD

热门文章

  1. word文档显示文件已损坏打不开怎么办呢?
  2. 如何能将mysql卸载干净
  3. 泰然金融总裁吴素春:网贷行业的价值不应该被全盘否定
  4. html修改时间触发onchange,js 触发select onchange事件代码
  5. 合理使用AutoRunner的回放设置
  6. MSM8909读PMIC芯片寄存器
  7. 简单讲解memmove函数
  8. Kali换源及更新教程
  9. rc4算法安全漏洞_RC4攻击:RC4加密算法能否保护SSL/TLS?
  10. 《数据结构》—— 哈夫曼树