Commit 92e40b5c authored by Hans Muller's avatar Hans Muller Committed by GitHub

Image color blend mode (#9486)

parent da7867be
...@@ -33,12 +33,11 @@ class SectionCard extends StatelessWidget { ...@@ -33,12 +33,11 @@ class SectionCard extends StatelessWidget {
], ],
), ),
), ),
child: new Opacity( child: new Image.asset(
opacity: 0.075, section.backgroundAsset,
child: new Image.asset( color: const Color.fromRGBO(255, 255, 255, 0.075),
section.backgroundAsset, colorBlendMode: BlendMode.modulate,
fit: BoxFit.cover, fit: BoxFit.cover,
),
), ),
), ),
); );
......
...@@ -26,6 +26,7 @@ class RenderImage extends RenderBox { ...@@ -26,6 +26,7 @@ class RenderImage extends RenderBox {
double height, double height,
double scale: 1.0, double scale: 1.0,
Color color, Color color,
BlendMode colorBlendMode,
BoxFit fit, BoxFit fit,
FractionalOffset alignment, FractionalOffset alignment,
ImageRepeat repeat: ImageRepeat.noRepeat, ImageRepeat repeat: ImageRepeat.noRepeat,
...@@ -35,6 +36,7 @@ class RenderImage extends RenderBox { ...@@ -35,6 +36,7 @@ class RenderImage extends RenderBox {
_height = height, _height = height,
_scale = scale, _scale = scale,
_color = color, _color = color,
_colorBlendMode = colorBlendMode,
_fit = fit, _fit = fit,
_alignment = alignment, _alignment = alignment,
_repeat = repeat, _repeat = repeat,
...@@ -95,15 +97,14 @@ class RenderImage extends RenderBox { ...@@ -95,15 +97,14 @@ class RenderImage extends RenderBox {
ColorFilter _colorFilter; ColorFilter _colorFilter;
// Should we make the blend mode configurable?
void _updateColorFilter() { void _updateColorFilter() {
if (_color == null) if (_color == null)
_colorFilter = null; _colorFilter = null;
else else
_colorFilter = new ColorFilter.mode(_color, BlendMode.srcIn); _colorFilter = new ColorFilter.mode(_color, _colorBlendMode ?? BlendMode.srcIn);
} }
/// If non-null, apply this color filter to the image before painting. /// If non-null, this color is blended with each image pixel using [colorBlendMode].
Color get color => _color; Color get color => _color;
Color _color; Color _color;
set color(Color value) { set color(Color value) {
...@@ -114,6 +115,24 @@ class RenderImage extends RenderBox { ...@@ -114,6 +115,24 @@ class RenderImage extends RenderBox {
markNeedsPaint(); markNeedsPaint();
} }
/// Used to combine [color] with this image.
///
/// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
/// the source and this image is the destination.
///
/// See also:
///
/// * [BlendMode], which includes an illustration of the effect of each blend mode.
BlendMode get colorBlendMode => _colorBlendMode;
BlendMode _colorBlendMode;
set colorBlendMode(BlendMode value) {
if (value == _colorBlendMode)
return;
_colorBlendMode;
_updateColorFilter();
markNeedsPaint();
}
/// How to inscribe the image into the space allocated during layout. /// How to inscribe the image into the space allocated during layout.
/// ///
/// The default varies based on the other fields. See the discussion at /// The default varies based on the other fields. See the discussion at
...@@ -251,6 +270,8 @@ class RenderImage extends RenderBox { ...@@ -251,6 +270,8 @@ class RenderImage extends RenderBox {
description.add('scale: $scale'); description.add('scale: $scale');
if (color != null) if (color != null)
description.add('color: $color'); description.add('color: $color');
if (colorBlendMode != null)
description.add('colorBlendMode: $colorBlendMode');
if (fit != null) if (fit != null)
description.add('fit: $fit'); description.add('fit: $fit');
if (alignment != null) if (alignment != null)
......
...@@ -2558,6 +2558,7 @@ class RawImage extends LeafRenderObjectWidget { ...@@ -2558,6 +2558,7 @@ class RawImage extends LeafRenderObjectWidget {
this.height, this.height,
this.scale: 1.0, this.scale: 1.0,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -2586,9 +2587,19 @@ class RawImage extends LeafRenderObjectWidget { ...@@ -2586,9 +2587,19 @@ class RawImage extends LeafRenderObjectWidget {
/// Used when determining the best display size for the image. /// Used when determining the best display size for the image.
final double scale; final double scale;
/// If non-null, apply this color filter to the image before painting. /// If non-null, this color is blended with each image pixel using [colorBlendMode].
final Color color; final Color color;
/// Used to combine [color] with this image.
///
/// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
/// the source and this image is the destination.
///
/// See also:
///
/// * [BlendMode], which includes an illustration of the effect of each blend mode.
final BlendMode colorBlendMode;
/// How to inscribe the image into the space allocated during layout. /// How to inscribe the image into the space allocated during layout.
/// ///
/// The default varies based on the other fields. See the discussion at /// The default varies based on the other fields. See the discussion at
...@@ -2621,6 +2632,7 @@ class RawImage extends LeafRenderObjectWidget { ...@@ -2621,6 +2632,7 @@ class RawImage extends LeafRenderObjectWidget {
height: height, height: height,
scale: scale, scale: scale,
color: color, color: color,
colorBlendMode: colorBlendMode,
fit: fit, fit: fit,
alignment: alignment, alignment: alignment,
repeat: repeat, repeat: repeat,
...@@ -2635,6 +2647,7 @@ class RawImage extends LeafRenderObjectWidget { ...@@ -2635,6 +2647,7 @@ class RawImage extends LeafRenderObjectWidget {
..height = height ..height = height
..scale = scale ..scale = scale
..color = color ..color = color
..colorBlendMode = colorBlendMode
..alignment = alignment ..alignment = alignment
..fit = fit ..fit = fit
..repeat = repeat ..repeat = repeat
...@@ -2653,6 +2666,8 @@ class RawImage extends LeafRenderObjectWidget { ...@@ -2653,6 +2666,8 @@ class RawImage extends LeafRenderObjectWidget {
description.add('scale: $scale'); description.add('scale: $scale');
if (color != null) if (color != null)
description.add('color: $color'); description.add('color: $color');
if (colorBlendMode != null)
description.add('colorBlendMode: $colorBlendMode');
if (fit != null) if (fit != null)
description.add('fit: $fit'); description.add('fit: $fit');
if (alignment != null) if (alignment != null)
......
...@@ -69,6 +69,7 @@ class Image extends StatefulWidget { ...@@ -69,6 +69,7 @@ class Image extends StatefulWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -87,6 +88,7 @@ class Image extends StatefulWidget { ...@@ -87,6 +88,7 @@ class Image extends StatefulWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -107,6 +109,7 @@ class Image extends StatefulWidget { ...@@ -107,6 +109,7 @@ class Image extends StatefulWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -135,6 +138,7 @@ class Image extends StatefulWidget { ...@@ -135,6 +138,7 @@ class Image extends StatefulWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -153,6 +157,7 @@ class Image extends StatefulWidget { ...@@ -153,6 +157,7 @@ class Image extends StatefulWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.colorBlendMode,
this.fit, this.fit,
this.alignment, this.alignment,
this.repeat: ImageRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
...@@ -176,9 +181,19 @@ class Image extends StatefulWidget { ...@@ -176,9 +181,19 @@ class Image extends StatefulWidget {
/// aspect ratio. /// aspect ratio.
final double height; final double height;
/// If non-null, apply this color filter to the image before painting. /// If non-null, this color is blended with each image pixel using [colorBlendMode].
final Color color; final Color color;
/// Used to combine [color] with this image.
///
/// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
/// the source and this image is the destination.
///
/// See also:
///
/// * [BlendMode], which includes an illustration of the effect of each blend mode.
final BlendMode colorBlendMode;
/// How to inscribe the image into the space allocated during layout. /// How to inscribe the image into the space allocated during layout.
/// ///
/// The default varies based on the other fields. See the discussion at /// The default varies based on the other fields. See the discussion at
...@@ -221,6 +236,8 @@ class Image extends StatefulWidget { ...@@ -221,6 +236,8 @@ class Image extends StatefulWidget {
description.add('height: $height'); description.add('height: $height');
if (color != null) if (color != null)
description.add('color: $color'); description.add('color: $color');
if (colorBlendMode != null)
description.add('colorBlendMode: $colorBlendMode');
if (fit != null) if (fit != null)
description.add('fit: $fit'); description.add('fit: $fit');
if (alignment != null) if (alignment != null)
...@@ -291,6 +308,7 @@ class _ImageState extends State<Image> { ...@@ -291,6 +308,7 @@ class _ImageState extends State<Image> {
height: widget.height, height: widget.height,
scale: _imageInfo?.scale ?? 1.0, scale: _imageInfo?.scale ?? 1.0,
color: widget.color, color: widget.color,
colorBlendMode: widget.colorBlendMode,
fit: widget.fit, fit: widget.fit,
alignment: widget.alignment, alignment: widget.alignment,
repeat: widget.repeat, repeat: widget.repeat,
......
...@@ -26,7 +26,7 @@ void main() { ...@@ -26,7 +26,7 @@ void main() {
) )
), ),
null, null,
EnginePhase.layout EnginePhase.layout,
); );
RenderImage renderImage = key.currentContext.findRenderObject(); RenderImage renderImage = key.currentContext.findRenderObject();
expect(renderImage.image, isNull); expect(renderImage.image, isNull);
...@@ -305,6 +305,19 @@ void main() { ...@@ -305,6 +305,19 @@ void main() {
testWidgets('Image.memory control test', (WidgetTester tester) async { testWidgets('Image.memory control test', (WidgetTester tester) async {
await tester.pumpWidget(new Image.memory(new Uint8List.fromList(kTransparentImage))); await tester.pumpWidget(new Image.memory(new Uint8List.fromList(kTransparentImage)));
}); });
testWidgets('Image color and colorBlend parameters', (WidgetTester tester) async {
await tester.pumpWidget(
new Image(
image: new TestImageProvider(),
color: const Color(0xFF00FF00),
colorBlendMode: BlendMode.clear
)
);
final RenderImage renderer = tester.renderObject<RenderImage>(find.byType(Image));
expect(renderer.color, const Color(0xFF00FF00));
expect(renderer.colorBlendMode, BlendMode.clear);
});
} }
class TestImageProvider extends ImageProvider<TestImageProvider> { class TestImageProvider extends ImageProvider<TestImageProvider> {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment