I have tried the blend mode that seems to be working for only color i.e colorblendmode. Is there any way to achieve the mix-blend-mode as of CSS?
Stack(
children: <Widget>[
Image.asset(
"asset/text.PNG",
height: double.maxFinite,
width: double.maxFinite,
fit: BoxFit.fitHeight,
color: Colors.red,
colorBlendMode: BlendMode.multiply,
),
Image.asset("asset/face.jpg",
width: double.maxFinite,
fit: BoxFit.fitHeight,
color: Colors.red,
colorBlendMode: BlendMode.multiply),
],
),
This results in something like: The output of code above
What i want to get Output from CSS
Using RenderProxyBox and some painting, I was able to recreate the exact sample on the CSS website without asynchronously loading the image in your Flutter code.
Image using CSS (left) vs image using Flutter(right).
Read the article I wrote about this here
To start, a BlendMask SingleChildRenderObject is created that creates a RenderProxyBox render object called RenderBlendMask is created. The child is painted with a BlendMode and an opacity.
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
// Applies a BlendMode to its child.
class BlendMask extends SingleChildRenderObjectWidget {
final BlendMode blendMode;
final double opacity;
const BlendMask({
required this.blendMode,
this.opacity = 1.0,
super.key,
super.child,
});
@override
RenderObject createRenderObject(context) {
return RenderBlendMask(blendMode, opacity);
}
@override
void updateRenderObject(BuildContext context, RenderBlendMask renderObject) {
renderObject.blendMode = blendMode;
renderObject.opacity = opacity;
}
}
class RenderBlendMask extends RenderProxyBox {
BlendMode blendMode;
double opacity;
RenderBlendMask(this.blendMode, this.opacity);
@override
void paint(context, offset) {
// Create a new layer and specify the blend mode and opacity to composite it with:
context.canvas.saveLayer(
offset & size,
Paint()
..blendMode = blendMode
..color = Color.fromARGB((opacity * 255).round(), 255, 255, 255),
);
super.paint(context, offset);
// Composite the layer back into the canvas using the blendmode:
context.canvas.restore();
}
}
Now to blend two widgets (Not restricted to images), just add the widget you want to blend above another using a stack, and wrap it in your BlendMode.
class ImageMixer extends StatelessWidget {
const ImageMixer({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Stack(
children: [
SizedBox.expand(
child: Image.asset(
'images/sky.jpg',
),
),
BlendMask(
opacity: 1.0,
blendMode: BlendMode.softLight,
child: SizedBox.expand(
child: Image.asset(
'images/monkey.jpg',
),
),
),
],
),
),
);
}
}
That produces the image above, and it works exactly like the CSS example.