在上一篇 Android | ColorMatrix 全面解析:原理、方法 中,介绍了ColorMatrix的常见方法,本文在其基础上,利用 ColorMatrix
动态调整图像亮度和饱和度,并实现滑动实时预览效果的示例。
效果演示
左图是原图,右图是可以实时调节亮度或饱和度的处理图。拖动下方 SeekBar,即可看到变化效果。
上述效果是同时调整了亮度和饱和度,还可以分别单个设置以及设置其他属性等,可以自行尝试,后面会给出完整代码示例。
实现思路
- 使用
ColorMatrixImageView
自定义 View 扩展AppCompatImageView
- 利用
ColorMatrix.setSaturation()
设置饱和度 - 利用
ColorMatrix.setScale()
或构造矩阵设置亮度 - 使用
ColorMatrix.postConcat()
合并多个色彩矩阵,配合ColorMatrixColorFilter
实时更新图片色彩 - 使用协程进行防抖处理,避免滑动频繁更新造成卡顿
ColorMatrixImageView 实现代码
class ColorMatrixImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
private var brightness = 1.0f // 默认亮度
private var saturation = 1.0f // 默认饱和度
// 防抖处理
private var mJob: Job? = null
private val mScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
init {
scaleType = ScaleType.CENTER_CROP
}
fun setBrightness(brightness: Float) {
this.brightness = brightness
scheduleUpdate()
}
fun setSaturation(value: Float) {
this.saturation = value
scheduleUpdate()
}
fun setAdjustments(brightness: Float, saturation: Float) {
this.saturation = saturation
this.brightness = brightness
scheduleUpdate()
}
private fun scheduleUpdate(delayMs: Long = 16L) {
mJob?.cancel()
mJob = mScope.launch {
delay(delayMs)
applyAdjustments()
}
}
private fun applyAdjustments() {
val combineMatrix = ColorMatrix()
val saturationMatrix = ColorMatrix()
saturationMatrix.setSaturation(saturation)
val brightnessMatrix = ColorMatrix(
floatArrayOf(
brightness, 0f, 0f, 0f, 0f,
0f, brightness, 0f, 0f, 0f,
0f, 0f, brightness, 0f, 0f,
0f, 0f, 0f, 1f, 0f
)
)
combineMatrix.postConcat(saturationMatrix)
combineMatrix.postConcat(brightnessMatrix)
colorFilter = ColorMatrixColorFilter(combineMatrix)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mScope.cancel()
}
}
XML 布局文件(部分)
<org.ninetripods.mq.study.widget.matrix.ColorMatrixImageView
android:id="@+id/iv_color_matrix_xml_view"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginStart="30dp"
android:background="@color/black"
android:scaleType="centerCrop"
android:src="@drawable/icon_cat_h"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_origin"
app:layout_constraintTop_toTopOf="parent" />
SeekBar 调节 UI 控制代码
mSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
val barValue = progress / 20f // 0.0f ~ 5.0f
// 只调亮度
mIvColorMatrix.setBrightness(barValue)
mTvProcess.text = String.format("亮度 = %.2f", barValue)
// 只调饱和度
// mIvColorMatrix.setSaturation(barValue)
// mTvProcess.text = String.format("饱和度 = %.2f", barValue)
// 同时调亮度 + 饱和度
// mIvColorMatrix.setAdjustments(barValue, barValue)
// mTvProcess.text = String.format("亮度 & 饱和度 = %.2f", barValue)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
1. 亮度(Brightness)
亮度是通过将 RGB 三通道统一放大或缩小来实现的。例如:
ColorMatrix(floatArrayOf(
brightness, 0f, 0f, 0f, 0f,
0f, brightness, 0f, 0f, 0f,
0f, 0f, brightness, 0f, 0f,
0f, 0f, 0f, 1f, 0f
))
2. 饱和度(Saturation)
饱和度的变化是通过 ColorMatrix.setSaturation(saturation)
方法内部完成的,值域通常为 0f ~ 2f
,1f 表示不变。
总结
本文通过封装一个 ColorMatrixImageView
,结合协程防抖与 SeekBar 滑动控制,实现了 Android 图像的动态调色处理。完整代码参见:github.com/crazyqiang/…