1. 前言
这段时间,在使用 natario1/CameraView 来实现带滤镜的预览
、拍照
、录像
功能。
由于CameraView
封装的比较到位,在项目前期,的确为我们节省了不少时间。
但随着项目持续深入,对于CameraView
的使用进入深水区,逐渐出现满足不了我们需求的情况。
Github
中的issues
中,有些BUG
作者一直没有修复。
那要怎么办呢 ? 项目迫切地需要实现相关功能,只能自己硬着头皮去看它的源码,去解决这些问题。
而这篇文章是其中关于CameraView
在使用多滤镜MultiFilter
的时候哦度会遇到拍照错乱的BUG
。
以下源码解析基于CameraView 2.7.2
implementation("com.otaliastudios:cameraview:2.7.2")
为了在博客上更好的展示,本文贴出的代码进行了部分精简
2. 复现BUG
2.1 添加权限
在AndroidManifest.xml
中添加权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
别忘了申请权限
ActivityCompat.requestPermissions(
this,
arrayOf(
android.Manifest.permission.CAMERA,
android.Manifest.permission.RECORD_AUDIO,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
),
1
)
2.2 在XML中添加布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MyMainActivity">
<com.otaliastudios.cameraview.CameraView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cameraFacing="back"
app:cameraEngine="camera2"
app:cameraExperimental="true"
app:cameraMode="picture" />
<Button
android:id="@+id/btn_take_picture"
android:layout_gravity="right|bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="拍照" />
</FrameLayout>
2.3 实现Activity
在Activity
中添加如下代码
class CameraActivity : AppCompatActivity() {
private lateinit var binding: ActivityTest2Binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTest2Binding.inflate(layoutInflater)
setContentView(binding.root)
//TODO 申请权限,这里略过,详见上文
binding.btnTakePicture.setOnClickListener {
//调用带滤镜拍照
binding.cameraView.takePictureSnapshot()
}
binding.cameraView.addCameraListener(object : CameraListener() {
override fun onPictureTaken(result: PictureResult) {
super.onPictureTaken(result)
//拍照回调
val res = BitmapFactory.decodeByteArray(result.data, 0, result.data.size)
res?.also {
val file = getNewImageFile()
ImageUtils.save(it, file, Bitmap.CompressFormat.JPEG)
}
}
})
//初始化CameraView
binding.cameraView.setLifecycleOwner(this)
val multiFilter = MultiFilter()
val crossProcess = Filters.CROSS_PROCESS.newInstance()
multiFilter.addFilter(crossProcess)
//设置滤镜
binding.cameraView.filter = multiFilter
}
}
2.4 运行项目
接着运行项目,预览时正常的,点击拍照,可以发现,带滤镜拍出来的图片是正常的。
2.5 使用两个滤镜
然后我们改成使用两个滤镜
//初始化CameraView
binding.cameraView.setLifecycleOwner(this)
val multiFilter = MultiFilter()
val crossProcess = Filters.CROSS_PROCESS.newInstance()
multiFilter.addFilter(crossProcess)
val vignette = Filters.VIGNETTE.newInstance()
multiFilter.addFilter(vignette)
//设置滤镜
binding.cameraView.filter = multiFilter
默认情况下,CameraView
会使用摄像头支持的最大像素进行拍照,我这个手机CameraView
最终选用的摄像头分辨率是3072x4096
,而我的手机屏幕分辨率是1080*2412
(也就是CameraView
的分辨率),预览时候是正常的,拍出来的照片居然放大了 ?
2.6 使用1080P
我们再将CameraView
拍照的分辨率强制指定为1920*1080
,而我的手机屏幕分辨率是1080*2412
,预览也是正常的,这个时候拍出来的照片却是比实际尺寸缩小的。
3. BUG小结
至此,我们可以总结这个BUG
,是跟CameraView
的尺寸和摄像头选取的分辨率匹配有关。
- 使用单个滤镜
- 一切正常
- 使用多个滤镜,预览正常,但是
- 手机选用的摄像头分辨率比
CameraView
分辨率高 : 照片得到的画面会放大 - 手机选用的摄像头分辨率比
CameraView
分辨率低 : 拍照得到的画面会缩小,会有黑边
- 手机选用的摄像头分辨率比
那这到底是为什么呢 ? 又该怎么解决呢 ?
我们在下一篇文章中做详细分析 : 解决相机库CameraView多滤镜拍照错乱的BUG (二) : 解决BUG
4. 其他
4.1 CameraView源码解析系列
Android 相机库CameraView源码解析 (一) : 预览-CSDN博客
Android 相机库CameraView源码解析 (二) : 拍照-CSDN博客
Android 相机库CameraView源码解析 (三) : 滤镜相关类说明-CSDN博客
Android 相机库CameraView源码解析 (四) : 带滤镜预览-CSDN博客
Android 相机库CameraView源码解析 (五) : 带滤镜拍照-CSDN博客
Android 相机库CameraView源码解析 (六) : 保存滤镜效果-CSDN博客