如何在 Flutter 中调整图像的色相饱和度和亮度?

Ban*_*eil 2 image-processing colormatrix dart flutter

在我的 Flutter 应用程序中,我有一个图像和三个滑块,一个用于Hue,一个用于Saturation,一个用于Brightness,我试图弄清楚如何使用ColorFiltered小部件进行这些调整,但我想不通为ColorFilter.matrix.

我的代码看起来像这样:

ColorFiltered(
  colorFilter: ColorFilter.matrix(
    // What goes here?
  ),
  child: Container(
    decoration: BoxDecoration(
      image: DecorationImage(
        fit: BoxFit.cover,
        image: NetworkImage(myImageUrl),
      )
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

有谁知道如何根据 HSV 值生成滤色器矩阵?

Ban*_*eil 8

为了解决这个问题,我构建了一个ImageFilter小部件,可以这样使用:

ImageFilter(
  hue: 0.1,
  brightness: -0.6,
  saturation: 0.8,
  child: Container(
    decoration: BoxDecoration(
      image: DecorationImage(
        fit: BoxFit.cover,
        image: NetworkImage(imageUrl),
      ),
    )
  )
)

Run Code Online (Sandbox Code Playgroud)

它采用介于 -1 和 1 之间的十进制形式的百分比输入。

它使用 3 层 ColorFiltered 小部件:

Widget ImageFilter({brightness, saturation, hue, child}) {
  return ColorFiltered(
    colorFilter: ColorFilter.matrix(
      ColorFilterGenerator.brightnessAdjustMatrix(
        value: brightness,
      )
    ),
    child: ColorFiltered(
      colorFilter: ColorFilter.matrix(
        ColorFilterGenerator.saturationAdjustMatrix(
          value: saturation,
        )
      ),
      child: ColorFiltered(
        colorFilter: ColorFilter.matrix(
          ColorFilterGenerator.hueAdjustMatrix(
            value: hue,
          )
        ),
        child: child,
      )
    )
  );
}
Run Code Online (Sandbox Code Playgroud)

为了生成过滤器矩阵,我使用了这个答案的帮助来解决一个类似的 android 问题:https : //stackoverflow.com/a/7917978/937841并创建了一个ColorFilterGenerator适用于颤振的:

import 'dart:math';

class ColorFilterGenerator {
    static List<double> hueAdjustMatrix({double value}) {
      value = value * pi;

      if (value == 0)
        return [
          1,0,0,0,0,
          0,1,0,0,0,
          0,0,1,0,0,
          0,0,0,1,0,
        ];

      double cosVal = cos(value);
      double sinVal = sin(value);
      double lumR = 0.213;
      double lumG = 0.715;
      double lumB = 0.072;

      return List<double>.from(<double>[
        (lumR + (cosVal * (1 - lumR))) + (sinVal * (-lumR)), (lumG + (cosVal * (-lumG))) + (sinVal * (-lumG)), (lumB + (cosVal * (-lumB))) + (sinVal * (1 - lumB)), 0, 0, (lumR + (cosVal * (-lumR))) + (sinVal * 0.143), (lumG + (cosVal * (1 - lumG))) + (sinVal * 0.14), (lumB + (cosVal * (-lumB))) + (sinVal * (-0.283)), 0, 0, (lumR + (cosVal * (-lumR))) + (sinVal * (-(1 - lumR))), (lumG + (cosVal * (-lumG))) + (sinVal * lumG), (lumB + (cosVal * (1 - lumB))) + (sinVal * lumB), 0, 0, 0, 0, 0, 1, 0,
      ]).map((i) => i.toDouble()).toList();
    }

    static List<double> brightnessAdjustMatrix({double value}}) {
      if (value <= 0)
        value = value * 255;
      else value = value * 100

      if (value == 0)
        return [
          1,0,0,0,0,
          0,1,0,0,0,
          0,0,1,0,0,
          0,0,0,1,0,
        ];

      return List<double>.from(<double>[
        1, 0, 0, 0, value, 0, 1, 0, 0, value, 0, 0, 1, 0, value, 0, 0, 0, 1, 0
      ]).map((i) => i.toDouble()).toList();
    }

    static List<double> saturationAdjustMatrix({double value}) {
      value = value * 100;

      if (value == 0)
        return [
          1,0,0,0,0,
          0,1,0,0,0,
          0,0,1,0,0,
          0,0,0,1,0,
        ];

      double x = ((1 + ((value > 0) ? ((3 * value) / 100) : (value / 100)))).toDouble();
      double lumR = 0.3086;
      double lumG = 0.6094;
      double lumB = 0.082;

      return List<double>.from(<double>[
        (lumR * (1 - x)) + x, lumG * (1 - x), lumB * (1 - x),
        0, 0,
        lumR * (1 - x),
        (lumG * (1 - x)) + x,
        lumB * (1 - x),
        0, 0,
        lumR * (1 - x),
        lumG * (1 - x),
        (lumB * (1 - x)) + x,
        0, 0, 0, 0, 0, 1, 0,
      ]).map((i) => i.toDouble()).toList();
    }
}
Run Code Online (Sandbox Code Playgroud)

我敢打赌,有一种方法可以连接色调/饱和度/亮度矩阵(就像我在上面提到的 android 问题中所做的那样),并且只使用 1 个颜色过滤矩阵(这可能会更有效),但这适用于我的情况。


Mar*_*rcG 1

我已将BananaNeil 的答案添加到Themed package中。

使用提供的ChangeColors小部件更改任何小部件(包括图像)的亮度、饱和度和色调,如下所示:

ChangeColors(
   hue: 0.55,
   brightness: 0.2,
   saturation: 0.1,
   child: Image.asset('myImage.png'),
);
Run Code Online (Sandbox Code Playgroud)

参数为:

亮度

  • 负值会使它更暗(-1最暗)。
  • 正值会使其更轻(1是最大值,但您可以超过它)。
  • 0.0是不变的。

饱和

  • 负值将使其饱和度降低(-1为灰度)。
  • 正值将使其更加饱和(1是最大值,但您可以超过它)。
  • 0.0是不变的。

色调

  • From -1.0to 1.0(注:1.0换行成-1.0,如 与1.2相同-0.8)。
  • 0.0是不变的。添加或减去 的倍数2.0也使其保持不变。

请注意:小部件与 BananaNeil 的答案的区别在于ChangeColors,小部件是正确的StatelessWidget,代码是空安全的,它修复了饱和度的限制,这样您就不会得到奇怪的效果,并且添加了解释参数的文档。如果您不想添加包,只需从GitHub复制代码即可。