Paint API之—— ColorFilter(颜色过滤器)(1/3)

Paint API 之—— ColorFilter 详解(一)

在 Android 绘图系统中,Paint 是定义绘制样式的核心类,而 ColorFilter 是 Paint 的一个高级属性,用于对绘制内容的颜色进行过滤和变换,广泛应用于图像处理、UI 效果和自定义绘图场景。本文作为 ColorFilter 详解系列的第一部分,将聚焦于 ColorFilter 的基础概念、子类(LightingColorFilter、PorterDuffColorFilter、ColorMatrixColorFilter)、工作原理和基本用法,提供代码示例和注意事项,结合 Canvas 和 Path 的简单应用。内容基于 Android 官方文档和开发实践,适合希望掌握颜色变换的开发者。

后续部分将深入探讨高级用法(如动态滤镜、动画效果)和与 WebView、Socket 的集成。


一、ColorFilter 基础

1. 定义
  • ColorFilter:Paint 的一个属性,用于修改绘制内容的颜色或 Alpha 通道,生成滤镜效果(如色调调整、亮度变化或颜色混合)。
  • 包路径android.graphics.ColorFilter
  • 作用
  • 改变绘制内容的颜色(如变红、变灰)。
  • 实现类似 Photoshop 的颜色调整(亮度、对比度、饱和度)。
  • 支持 PorterDuff 模式混合或矩阵变换。
  • 常见场景
  • 图片变灰(黑白效果)。
  • 图标颜色替换。
  • 动态滤镜(如夜间模式、色调调整)。
2. ColorFilter 子类

Android 提供三种主要 ColorFilter 子类:

  • LightingColorFilter:通过颜色乘法和加法调整颜色,适合简单颜色替换或亮度调整。
  • PorterDuffColorFilter:基于 PorterDuff 混合模式,结合 Alpha 通道进行颜色混合。
  • ColorMatrixColorFilter:使用 4×5 颜色矩阵进行复杂变换,如饱和度、色调调整。
  • 注意:ColorFilter 是抽象类,实际使用其子类。
3. 工作原理
  • ColorFilter 修改 Paint 的颜色输出,作用于每个像素的 RGBA 值。
  • 常与 Canvas 结合,影响 drawBitmap、drawRect、drawText 等绘制操作。
  • 仅对颜色和 Alpha 通道生效,不改变几何形状。
4. 设置 ColorFilter
  • 代码示例(Kotlin):
  import android.graphics.Color
  import android.graphics.LightingColorFilter
  import android.graphics.Paint

  val paint = Paint().apply {
      colorFilter = LightingColorFilter(Color.RED, 0) // 替换为红色
  }
  • 清除 ColorFilter
  paint.colorFilter = null

二、ColorFilter 子类详解

1. LightingColorFilter
  • 定义:通过颜色乘法和加法调整颜色,公式为:
    [
    C_{out} = C_{in} \times \text{mul} + \text{add}
    ]
    其中 (C_{in}) 为输入颜色,(\text{mul}) 为乘法因子,(\text{add}) 为加法因子。
  • 构造函数
  LightingColorFilter(int mul, int add)
  • mul:颜色乘法因子(RGB 值,0xFFFFFF 表示无变化)。
  • add:颜色加法因子(RGB 值,0x000000 表示无变化)。
  • 应用场景
  • 替换特定颜色(如将图标变红)。
  • 调整亮度(通过加法因子)。
  • 代码示例:将图片变红。
  paint.colorFilter = LightingColorFilter(0xFF0000, 0) // 保留红色通道
  canvas.drawBitmap(bitmap, 0f, 0f, paint)
2. PorterDuffColorFilter
  • 定义:基于 PorterDuff 混合模式,将指定颜色与绘制内容混合,适合实现叠加或遮罩效果。
  • 构造函数
  PorterDuffColorFilter(int color, PorterDuff.Mode mode)
  • color:混合颜色。
  • mode:PorterDuff 模式(如 SRC_IN、MULTIPLY)。
  • 应用场景:动态叠加颜色(如水印、滤镜)。
  • 代码示例:用绿色覆盖图片(SRC_IN)。
  import android.graphics.PorterDuff
  import android.graphics.PorterDuffColorFilter

  paint.colorFilter = PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_IN)
  canvas.drawBitmap(bitmap, 0f, 0f, paint)
3. ColorMatrixColorFilter
  • 定义:使用 4×5 颜色矩阵变换 RGBA 值,支持复杂效果如灰度、色调调整、反转等。
  • 构造函数
  ColorMatrixColorFilter(float[] matrix)
  ColorMatrixColorFilter(ColorMatrix matrix)
  • matrix:4×5 矩阵,格式为:
    [
    \begin{bmatrix}
    R_{scale} & R_{g} & R_{b} & R_{a} & R_{offset} \
    G_{r} & G_{scale} & G_{b} & G_{a} & G_{offset} \
    B_{r} & B_{g} & B_{scale} & B_{a} & B_{offset} \
    A_{r} & A_{g} & A_{b} & A_{scale} & A_{offset}
    \end{bmatrix}
    ]
    其中 (R_{out} = R_{in} \times R_{scale} + G_{in} \times R_{g} + B_{in} \times R_{b} + A_{in} \times R_{a} + R_{offset})。
  • 应用场景
  • 灰度效果(饱和度设为 0)。
  • 色调调整(修改 RGB 权重)。
  • 颜色反转。
  • 代码示例:灰度效果。
  import android.graphics.ColorMatrix
  import android.graphics.ColorMatrixColorFilter

  val matrix = ColorMatrix().apply {
      setSaturation(0f) // 饱和度为 0,生成灰度
  }
  paint.colorFilter = ColorMatrixColorFilter(matrix)
  canvas.drawBitmap(bitmap, 0f, 0f, paint)

三、实战示例:动态颜色滤镜切换

以下是一个完整的示例,展示如何使用三种 ColorFilter 实现图片滤镜效果(红色滤镜、绿色叠加、灰度效果),支持点击切换。

1. 自定义 View(ColorFilterView)

绘制图片并应用不同 ColorFilter。

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.LightingColorFilter
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.util.AttributeSet
import android.view.View

class ColorFilterView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
    private val paint = Paint().apply {
        isAntiAlias = true
    }
    private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.sample_image) // 替换为你的图片
    private val filters = listOf(
        LightingColorFilter(0xFF0000, 0), // 红色滤镜
        PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_IN), // 绿色叠加
        ColorMatrixColorFilter(ColorMatrix().apply { setSaturation(0f) }) // 灰度
    )
    private var currentFilterIndex = 0

    init {
        setOnClickListener {
            currentFilterIndex = (currentFilterIndex + 1) % filters.size
            paint.colorFilter = filters[currentFilterIndex]
            invalidate()
        }
        // 初始化默认滤镜
        paint.colorFilter = filters[currentFilterIndex]
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 绘制图片
        canvas.drawBitmap(bitmap, 0f, 0f, paint)

        // 显示当前滤镜名称
        paint.colorFilter = null
        paint.color = Color.BLACK
        paint.textSize = 40f
        val filterName = when (currentFilterIndex) {
            0 -> "Lighting (Red)"
            1 -> "PorterDuff (Green)"
            2 -> "ColorMatrix (Gray)"
            else -> "Unknown"
        }
        canvas.drawText(filterName, 20f, height - 40f, paint)
    }
}
  • 说明
  • LightingColorFilter:将图片变为红色(仅保留红色通道)。
  • PorterDuffColorFilter:用绿色覆盖(SRC_IN 模式)。
  • ColorMatrixColorFilter:将图片转为灰度。
  • 交互:点击切换滤镜,显示名称。
2. 布局文件(activity_main.xml)
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <com.example.ColorFilterView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
3. 主 Activity(MainActivity)
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
4. 运行效果
  • 初始显示红色滤镜图片。
  • 点击切换到绿色叠加、灰度效果,底部显示滤镜名称。
  • 效果:类似图片编辑器的滤镜切换。
5. 结合 Canvas 和 Path

使用 Path 绘制形状并应用 ColorFilter。

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    // 绘制三角形
    val path = Path().apply {
        moveTo(width / 2f, height / 4f)
        lineTo(width / 4f, height * 3 / 4f)
        lineTo(width * 3 / 4f, height * 3 / 4f)
        close()
    }
    paint.colorFilter = filters[currentFilterIndex]
    paint.color = Color.BLUE
    canvas.drawPath(path, paint)

    // 显示滤镜名称
    paint.colorFilter = null
    paint.color = Color.BLACK
    paint.textSize = 40f
    val filterName = when (currentFilterIndex) {
        0 -> "Lighting (Red)"
        1 -> "PorterDuff (Green)"
        2 -> "ColorMatrix (Gray)"
        else -> "Unknown"
    }
    canvas.drawText(filterName, 20f, height - 40f, paint)
}
  • 效果:绘制蓝色三角形,应用红色、绿色或灰度滤镜。

四、常见问题及注意事项

  1. 性能问题
  • 原因:ColorMatrixColorFilter 的矩阵计算可能影响大图像性能。
  • 解决
    • 使用小尺寸 Bitmap:
      kotlin val scaledBitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true)
    • 启用硬件加速:
      xml <application android:hardwareAccelerated="true">
    • 异步处理:
      kotlin GlobalScope.launch(Dispatchers.IO) { val filteredBitmap = applyFilter(bitmap) runOnUiThread { imageView.setImageBitmap(filteredBitmap) } }
  1. 兼容性
  • API 支持:ColorFilter 在 API 1+ 可用,效果一致。
  • WebView:渲染为 Bitmap 使用 ARGB_8888 格式。
  • 低版本:测试复杂矩阵变换效果。
  1. 内存管理
  • Bitmap 回收
    kotlin if (!bitmap.isRecycled) bitmap.recycle()
  • OOM 预防:采样图片:
    kotlin val options = BitmapFactory.Options().apply { inSampleSize = 2 }
  1. 错误处理
  • Socket 错误(后续集成):
    kotlin try { socket.connect() } catch (e: IOException) { Log.e("Socket", "连接失败: ${e.message}") }
  • 绘制异常:确保 Paint 初始化。
  1. 效果优化
  • 动态调整:使用 ValueAnimator 动画滤镜:
    kotlin ValueAnimator.ofFloat(0f, 1f).apply { addUpdateListener { val matrix = ColorMatrix().apply { setSaturation(it.animatedValue as Float) } paint.colorFilter = ColorMatrixColorFilter(matrix) invalidate() } start() }
  • 多滤镜叠加:顺序应用多个 ColorFilter(需多个 Paint)。

五、学习建议与实践

  1. 学习路径
  • 掌握 LightingColorFilter 的简单颜色替换。
  • 理解 PorterDuffColorFilter 的混合模式。
  • 学习 ColorMatrixColorFilter 的矩阵变换。
  • 实现动态滤镜切换。
  1. 实践项目
  • 简单项目:实现图片变红或灰度。
  • 进阶项目:动态切换滤镜,添加动画。
  • 高级项目:通过 Socket 传输滤镜参数。
  1. 调试工具
  • Layout Inspector:检查滤镜效果。
  • Profiler:监控性能。
  • Logcat:记录滤镜参数。
  1. 推荐资源
  • ColorFilter 文档:https://developer.android.com/reference/android/graphics/ColorFilter
  • ColorMatrix:https://developer.android.com/reference/android/graphics/ColorMatrix
  • 性能优化:https://developer.android.com/topic/performance/vitals/render

六、总结

  • ColorFilter:Paint 的颜色变换工具,支持 Lighting、PorterDuff 和 ColorMatrix 三种子类。
  • 子类详解
  • LightingColorFilter:颜色乘加,简单替换。
  • PorterDuffColorFilter:基于 PorterDuff 模式混合。
  • ColorMatrixColorFilter:矩阵变换,复杂效果。
  • 实战示例:动态切换滤镜(红色、绿色、灰度),结合 Canvas 和 Path。
  • 注意事项
  • 性能优化:小尺寸 Bitmap、硬件加速。
  • 内存管理:回收 Bitmap。
  • 错误处理:绘制和网络异常。

七、后续系列预告

本篇为 ColorFilter 系列(一),聚焦基础概念和基本用法。后续系列将深入:

  • 详解(二):ColorMatrixColorFilter 的高级矩阵变换(色调、对比度、反转)。
  • 详解(三):动态滤镜动画和 WebView、Socket 集成。

如果需要更详细的代码(如矩阵变换公式、动画示例)或特定场景讲解,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注