返回

高级 UI 之 Paint(滤镜、颜色通道、矩阵运算)

Android

前言

在 Android 开发中,Canvas 和 Paint 是至关重要的图形组件。Canvas 作为画布,而 Paint 作为画笔,赋予图形色彩和样式。在上一篇文章中,我们深入探讨了 Canvas 的基本操作。本文将重点关注 Paint 的高级特性,包括滤镜、颜色通道和矩阵运算,从而帮助 Android 开发人员创建更复杂、更令人印象深刻的 UI 效果。

一、滤镜

滤镜是一种图像处理技术,可以增强、调整或转换图像的外观。Paint 提供了一系列预定义的滤镜,如:

  • ColorMatrixColorFilter: 允许对颜色通道进行线性操作。
  • LightingColorFilter: 应用光源,创建阴影和高光效果。
  • PorterDuffColorFilter: 结合两种图像,根据指定的模式进行混合。

这些滤镜可以通过 ColorFilter 接口应用于 Paint 对象。例如,要应用色相旋转滤镜,可以按如下方式进行:

Paint paint = new Paint();
paint.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0xFF0000));

二、颜色通道

颜色通道是图像中颜色的基本组件。Paint 提供了方法来操作这些通道:

  • Color.alpha(): 获取或设置颜色的透明度。
  • Color.red()、Color.green()、Color.blue(): 获取或设置颜色的 RGB 值。

通过调整颜色通道,我们可以创建颜色混合、饱和度调整和反色效果。例如,要将颜色转换为其反色,可以按如下方式进行:

int color = Color.parseColor("#FF0000");
int invertedColor = 0xFFFFFFFF - color;

三、矩阵运算

矩阵运算是一种强大的数学工具,可用于变换图像。Paint 支持通过 ColorMatrix 类进行矩阵运算。ColorMatrix 可以定义为一个 4x5 的矩阵,用于对颜色通道进行线性变换。

例如,要创建亮度调整矩阵,可以按如下方式进行:

float[] matrix = {
    1, 0, 0, 0, 100,
    0, 1, 0, 0, 100,
    0, 0, 1, 0, 100,
    0, 0, 0, 1, 0
};
paint.setColorFilter(new ColorMatrixColorFilter(matrix));

示例

为了展示高级 Paint 特性的实际应用,让我们创建一个小程序,其中用户可以实时调整图像滤镜、颜色通道和矩阵运算。

代码:

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.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.SeekBar;

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private SeekBar seekBarHue, seekBarSaturation, seekBarBrightness, seekBarContrast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);
        seekBarHue = findViewById(R.id.seekBarHue);
        seekBarSaturation = findViewById(R.id.seekBarSaturation);
        seekBarBrightness = findViewById(R.id.seekBarBrightness);
        seekBarContrast = findViewById(R.id.seekBarContrast);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);

        // 创建一个 Paint 对象
        Paint paint = new Paint();

        // 设置监听器以响应 SeekBar 更改
        seekBarHue.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float hue = progress / 360f;
                paint.setColorFilter(new LightingColorFilter(0xFFFFFFFF, hue));
                updateImage(bitmap, paint);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

        seekBarSaturation.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float saturation = progress / 100f;
                float[] matrix = {
                        1, 0, 0, 0, saturation,
                        0, 1, 0, 0, saturation,
                        0, 0, 1, 0, saturation,
                        0, 0, 0, 1, 0
                };
                paint.setColorFilter(new ColorMatrixColorFilter(matrix));
                updateImage(bitmap, paint);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

        seekBarBrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float brightness = progress / 100f;
                int invertedColor = 0xFFFFFFFF - Color.parseColor("#FF0000");
                paint.setColorFilter(new PorterDuffColorFilter(invertedColor, PorterDuff.Mode.ADD));
                updateImage(bitmap, paint);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

        seekBarContrast.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float contrast = progress / 100f;
                float[] matrix = {
                        contrast, 0, 0, 0, 0,
                        0, contrast, 0, 0, 0,
                        0, 0, contrast, 0, 0,
                        0, 0, 0, 1, 0
                };
                paint.setColorFilter(new ColorMatrixColorFilter(matrix));
                updateImage(bitmap, paint);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

        updateImage(bitmap, paint);
    }

    private void updateImage(Bitmap bitmap, Paint paint) {
        // 创建一个新的 Bitmap 以应用效果
        Bitmap updatedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

        // 创建一个 Canvas 并绘制图像
        Canvas canvas = new Canvas(updatedBitmap);
        canvas.drawBitmap(bitmap, 0, 0, paint);

        // 设置图像视图的图像
        imageView.setImageBitmap(updatedBitmap);
    }
}

结论

通过掌握 Paint 的高级特性,包括滤镜、颜色通道和矩阵运算,Android 开发人员可以创建更加复杂、更具互动性的 UI 效果。本文提供了一个实用的示例,展示了如何实时调整这些特性,从而提供引人入胜的用户体验。