How to adjust Hue Saturation and Brightness of an image or widget in Flutter?
Solution 1
I've added BananaNeil's answer into the Themed package.
Use the provided ChangeColors
widget to change the brightness, saturation and hue of any widget, including images, like this:
ChangeColors(
hue: 0.55,
brightness: 0.2,
saturation: 0.1,
child: Image.asset('myImage.png'),
);
Parameters are:
brightness
- Negative value will make it darker (
-1
is darkest). - Positive value will make it lighter (
1
is the maximum, but you can go above it). -
0.0
is unchanged.
saturation
- Negative value will make it less saturated (
-1
is greyscale). - Positive value will make it more saturated (
1
is the maximum, but you can go above it). -
0.0
is unchanged.
hue
- From
-1.0
to1.0
(Note:1.0
wraps into-1.0
, such as1.2
is the same as-0.8
). -
0.0
is unchanged. Adding or subtracting multiples of2.0
also keeps it unchanged.
Please note: The difference from the ChangeColors
widget to BananaNeil's answer is that the widget is a proper StatelessWidget
, code is null-safe, it fixes the limits of saturation so that you don't get weird effects, and the documentation was added explaining the parameters. If you don't want to add a package, just copy the code from GitHub.
Solution 2
To solve this issue, I built an ImageFilter
widget, which can be used like this:
ImageFilter(
hue: 0.1,
brightness: -0.6,
saturation: 0.8,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
)
)
)
It takes percentage inputs in decimal form between -1 and 1.
Which uses 3 layers of the ColorFiltered widget:
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,
)
)
);
}
To generate the filter matrix, I used help from this answer to a similar question for android: https://stackoverflow.com/a/7917978/937841 and created a ColorFilterGenerator
that works in flutter:
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();
}
}
I would bet that there is a way to concatenate the hue/saturation/brightness matrices (like was done in the android question I mentioned above), and only use 1 color filtered matrix (which would likely be more efficient), but this worked for my case.
Comments
-
BananaNeil over 1 year
In my Flutter app, I have an image and three sliders, one for Hue, one for Saturation, and one for Brightness, and I'm trying to figure out how to use the
ColorFiltered
widget to make these adjustments, but I can't figure out what to put in for theColorFilter.matrix
.My code looks something like this:
ColorFiltered( colorFilter: ColorFilter.matrix( // What goes here? ), child: Container( decoration: BoxDecoration( image: DecorationImage( fit: BoxFit.cover, image: NetworkImage(myImageUrl), ) ) ) )
Does anyone know how to generate a color filter matrix based on HSV values?