想要改变ImageView中图片的参数,我们需要先了解ColorMatrix类:
ColorMatrix 是 Android 中的一个类,它属于 android.graphics 包。它用于对图像进行颜色变换,包括但不限于亮度、对比度、饱和度、色调和色相的调整。ColorMatrix 通过一个 4x5 的矩阵来定义线性变换,这个矩阵可以对图像的 RGB 颜色空间进行操作。他有以下几种常用操作:
- 颜色变换: ColorMatrix 可以对图像的每个像素的颜色值进行变换,实现各种视觉效果。
- 矩阵操作: 通过设置矩阵中的值,可以进行颜色缩放、旋转、倾斜等操作。
- 链式调用: ColorMatrix 支持链式调用,可以连续应用多个变换。
先编辑好对应的布局文件,布局中包含控件有:
- 自定义View——MatrixImageView,继承自ImageView,所以实现效果和ImageView是一样的
- 三条seekBar——实现分别控制ImageView的亮度、对比度、饱和度
- 两个Button按钮——是分别实现从相册加载图片到ImageView,然后再从ImageView保存图片到相册
对第三条感兴趣可以看 打开相册选择图片与保存图片到相册 这篇
创建AjustMethod文件来编辑对应的三种调节方法
通过adjustContrast方法调整对比度
// adjustContrast 函数用于调整图片的对比度
internal fun adjustContrast(contrastValue: Int): ColorMatrix {
// 计算对比度值,将对比度滑块的值(0-100)转换为对比度系数
val contrast = (1.0 + (contrastValue - 50) / 100.0).toFloat()
// 创建一个新的 ColorMatrix 对象
val colorMatrix = ColorMatrix()
// 设置 ColorMatrix 的值,应用对比度调整
// 对比度调整矩阵的对角线上的值表示每个颜色通道的缩放系数
colorMatrix.set(floatArrayOf(
contrast, 0f, 0f, 0f, 0f, // 红色通道
0f, contrast, 0f, 0f, 0f, // 绿色通道
0f, 0f, contrast, 0f, 0f, // 蓝色通道
0f, 0f, 0f, 1f, 0f // Alpha 通道,保持不变
))
// 返回调整后的 ColorMatrix
return colorMatrix
}
通过adjustBrightness方法调整亮度
// adjustBrightness 函数用于调整图片的亮度
internal fun adjustBrightness(brightnessValue: Int): ColorMatrix {
// 计算亮度值,将亮度滑块的值(0-100)转换为-50到50的范围
val brightness = brightnessValue - 50f
// 创建一个新的 ColorMatrix 对象
val colorMatrix = ColorMatrix()
// 设置 ColorMatrix 的值,应用亮度调整
// 亮度调整在矩阵的右侧列中添加一个常数,表示每个颜色通道的偏移量
colorMatrix.set(floatArrayOf(
1f, 0f, 0f, 0f, brightness, // 红色通道
0f, 1f, 0f, 0f, brightness, // 绿色通道
0f, 0f, 1f, 0f, brightness, // 蓝色通道
0f, 0f, 0f, 1f, 0f // Alpha 通道,保持不变
))
// 返回调整后的 ColorMatrix
return colorMatrix
}
通过adjustSaturability方法调整饱和度
// adjustSaturability 函数用于调整图片的饱和度
internal fun adjustSaturability(saturabilityValue: Int): ColorMatrix {
// 计算饱和度因子,将饱和度滑块的值(0-100)转换为 -1 到 1的范围
val saturationFactor = (saturabilityValue - 50).toFloat() / 50f
// 创建一个新的 ColorMatrix 对象
val colorMatrix = ColorMatrix()
// 使用 ColorMatrix 的 setSaturation 方法应用饱和度调整
// 饱和度因子1表示原始图像,小于1表示降低饱和度,大于1表示增加饱和度
colorMatrix.setSaturation(1f + saturationFactor)
// 返回调整后的 ColorMatrix
return colorMatrix
}
三种方法写完之后如果直接使用到seekBar上会出现爆闪的情况,什么是爆闪呢?
就是当你调节了其中一个参数,比如是亮度或者是对比度,然后再去调节另外一个参数就会出现图片过亮或者过暗的这种情况。
这是因为在我们调节完第一个参数,再去调整第二个参数时没有将第一条修改后的参数进行同步更新,所以出现画面一闪一闪的情况,所以我们在调用三个方法时还得需要注意调用方式而且还得增加一个applyAdjustments函数用来一直同步三种调节后的参数实时同步渲染到ImageView上
private fun applyAdjustments(contrastValue: Int, brightnessValue: Int, saturabilityValue: Int) {
// 根据对比度SeekBar的进度值调整对比度,生成对应的ColorMatrix
val contrastMatrix = adjustContrast(contrastValue)
// 根据亮度SeekBar的进度值调整亮度,生成对应的ColorMatrix
val brightnessMatrix = adjustBrightness(brightnessValue)
// 根据饱和度SeekBar的进度值调整饱和度,生成对应的ColorMatrix
val saturationMatrix = adjustSaturability(saturabilityValue)
// 创建一个新的ColorMatrix对象,用于存储最终的颜色变换矩阵
val combinedMatrix = ColorMatrix()
// 将对比度矩阵应用到combinedMatrix上
combinedMatrix.postConcat(contrastMatrix)
// 将亮度矩阵应用到combinedMatrix上,注意这里是顺序执行,对比度先于亮度
combinedMatrix.postConcat(brightnessMatrix)
// 将饱和度矩阵应用到combinedMatrix上,顺序在对比度和亮度之后
combinedMatrix.postConcat(saturationMatrix)
// 将最终的颜色变换矩阵设置为ImageView的颜色过滤器
// ColorMatrixColorFilter是Android中用于应用颜色变换矩阵的类
imageView.colorFilter = ColorMatrixColorFilter(combinedMatrix)
}
contrastSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
//当SeekBar的进度发生变化时调用
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
//根据当前进度和其他SeekBar的进度调用applyAdjustments函数来应用颜色调整
applyAdjustments(progress, brightnessSeekBar.progress, saturabilitySeekBar.progress)
}
// 当开始SeekBar的触摸事件时调用
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
// 当停止SeekBar的触摸事件时调用
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
brightnessSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
applyAdjustments(contrastSeekBar.progress, progress, saturabilitySeekBar.progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
saturabilitySeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
applyAdjustments(contrastSeekBar.progress, brightnessSeekBar.progress, progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})