如何在 Flutter 中调整图像或小部件的色调饱和度和亮度?
How to adjust Hue Saturation and Brightness of an image or widget in Flutter?
在我的 Flutter 应用中,我有一张图片和三个滑块,一个用于 Hue,一个用于 Saturation,一个用于 亮度,我想知道如何使用 ColorFiltered
小部件进行这些调整,但我不知道要为 [=12 添加什么=].
我的代码看起来像这样:
ColorFiltered(
colorFilter: ColorFilter.matrix(
// What goes here?
),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(myImageUrl),
)
)
)
)
有谁知道如何根据HSV值生成滤色矩阵?
为了解决这个问题,我构建了一个 ImageFilter
小部件,可以这样使用:
ImageFilter(
hue: 0.1,
brightness: -0.6,
saturation: 0.8,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
)
)
)
它采用介于 -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,
)
)
);
}
为了生成过滤器矩阵,我使用了此答案对 android 的类似问题的帮助: 并创建了一个在 flutter 中工作的 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();
}
}
我敢打赌,有一种方法可以连接 hue/saturation/brightness 矩阵(就像我在上面提到的 android 问题中所做的那样),并且只使用 1 个颜色过滤矩阵(这很可能更有效率),但这适用于我的情况。
我们必须在其中包含一个颜色矩阵。
一些例子是:
static const ColorFilter sepia = ColorFilter.matrix(<double>[
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0]);
static const ColorFilter greyscale = ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0, 0, 0, 1, 0]);
只需复制上面的矩阵即可获得棕褐色或灰度滤镜。
我已将 BananaNeil 的回答 添加到 Themed package。
使用提供的 ChangeColors
小部件更改任何小部件(包括图像)的亮度、饱和度和色调,如下所示:
ChangeColors(
hue: 0.55,
brightness: 0.2,
saturation: 0.1,
child: Image.asset('myImage.png'),
);
参数为:
亮度
- 负值会使颜色变暗(
-1
最暗)。
- 正值会使它变轻(
1
是最大值,但您可以超过它)。
0.0
不变。
饱和度
- 负值会降低饱和度(
-1
是灰度)。
- 正值会使它更饱和(
1
是最大值,但您可以超过它)。
0.0
不变。
色调
- 从
-1.0
到1.0
(注:1.0
换成-1.0
,如1.2
等同于-0.8
) .
0.0
不变。添加或减去 2.0
的倍数也保持不变。
请注意:从 ChangeColors
小部件到 BananaNeil 的答案的区别在于小部件是一个适当的 StatelessWidget
,代码是空安全的,它修复了饱和度的限制,这样您就不会得到奇怪的效果,并且添加了解释参数的文档。如果您不想添加包,只需复制 GitHub.
中的代码即可
在我的 Flutter 应用中,我有一张图片和三个滑块,一个用于 Hue,一个用于 Saturation,一个用于 亮度,我想知道如何使用 ColorFiltered
小部件进行这些调整,但我不知道要为 [=12 添加什么=].
我的代码看起来像这样:
ColorFiltered(
colorFilter: ColorFilter.matrix(
// What goes here?
),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(myImageUrl),
)
)
)
)
有谁知道如何根据HSV值生成滤色矩阵?
为了解决这个问题,我构建了一个 ImageFilter
小部件,可以这样使用:
ImageFilter(
hue: 0.1,
brightness: -0.6,
saturation: 0.8,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
)
)
)
它采用介于 -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,
)
)
);
}
为了生成过滤器矩阵,我使用了此答案对 android 的类似问题的帮助: 并创建了一个在 flutter 中工作的 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();
}
}
我敢打赌,有一种方法可以连接 hue/saturation/brightness 矩阵(就像我在上面提到的 android 问题中所做的那样),并且只使用 1 个颜色过滤矩阵(这很可能更有效率),但这适用于我的情况。
我们必须在其中包含一个颜色矩阵。 一些例子是:
static const ColorFilter sepia = ColorFilter.matrix(<double>[
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0]);
static const ColorFilter greyscale = ColorFilter.matrix(<double>[
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0, 0, 0, 1, 0]);
只需复制上面的矩阵即可获得棕褐色或灰度滤镜。
我已将 BananaNeil 的回答 添加到 Themed package。
使用提供的 ChangeColors
小部件更改任何小部件(包括图像)的亮度、饱和度和色调,如下所示:
ChangeColors(
hue: 0.55,
brightness: 0.2,
saturation: 0.1,
child: Image.asset('myImage.png'),
);
参数为:
亮度
- 负值会使颜色变暗(
-1
最暗)。 - 正值会使它变轻(
1
是最大值,但您可以超过它)。 0.0
不变。
饱和度
- 负值会降低饱和度(
-1
是灰度)。 - 正值会使它更饱和(
1
是最大值,但您可以超过它)。 0.0
不变。
色调
- 从
-1.0
到1.0
(注:1.0
换成-1.0
,如1.2
等同于-0.8
) . 0.0
不变。添加或减去2.0
的倍数也保持不变。
请注意:从 ChangeColors
小部件到 BananaNeil 的答案的区别在于小部件是一个适当的 StatelessWidget
,代码是空安全的,它修复了饱和度的限制,这样您就不会得到奇怪的效果,并且添加了解释参数的文档。如果您不想添加包,只需复制 GitHub.