diff --git a/src/Avalonia.Base/Media/Imaging/BitmapBlendingMode.cs b/src/Avalonia.Base/Media/Imaging/BitmapBlendingMode.cs
index 73a3f7b269..9eea86a443 100644
--- a/src/Avalonia.Base/Media/Imaging/BitmapBlendingMode.cs
+++ b/src/Avalonia.Base/Media/Imaging/BitmapBlendingMode.cs
@@ -1,5 +1,6 @@
namespace Avalonia.Media.Imaging
{
+ // TODO12 split the enum into two: composite mode and blend mode. (And rename Blending to Blend at the same time).
///
/// Controls the way the bitmaps are drawn together.
///
@@ -54,6 +55,66 @@ namespace Avalonia.Media.Imaging
///
/// Display the sum of the source image and destination image.
///
- Plus
+ Plus,
+ ///
+ /// Multiplies the complements of the backdrop and source color values, then complements the result.
+ ///
+ Screen,
+ ///
+ /// Multiplies or screens the colors, depending on the backdrop color value.
+ ///
+ Overlay,
+ ///
+ /// Selects the darker of the backdrop and source colors.
+ ///
+ Darken,
+ ///
+ /// Selects the lighter of the backdrop and source colors.
+ ///
+ Lighten,
+ ///
+ /// Darkens the backdrop color to reflect the source color.
+ ///
+ ColorDodge,
+ ///
+ /// Multiplies or screens the colors, depending on the source color value.
+ ///
+ ColorBurn,
+ ///
+ /// Darkens or lightens the colors, depending on the source color value.
+ ///
+ HardLight,
+ ///
+ /// Subtracts the darker of the two constituent colors from the lighter color.
+ ///
+ SoftLight,
+ ///
+ /// Produces an effect similar to that of the Difference mode but lower in contrast.
+ ///
+ Difference,
+ ///
+ /// The source color is multiplied by the destination color and replaces the destination
+ ///
+ Exclusion,
+ ///
+ /// Creates a color with the hue of the source color and the saturation and luminosity of the backdrop color.
+ ///
+ Multiply,
+ ///
+ /// Creates a color with the hue of the source color and the saturation and luminosity of the backdrop color.
+ ///
+ Hue,
+ ///
+ /// Creates a color with the saturation of the source color and the hue and luminosity of the backdrop color.
+ ///
+ Saturation,
+ ///
+ /// Creates a color with the hue and saturation of the source color and the luminosity of the backdrop color.
+ ///
+ Color,
+ ///
+ /// Creates a color with the luminosity of the source color and the hue and saturation of the backdrop color.
+ ///
+ Luminosity
}
}
diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs
index 1b5fe123da..5e8ee86c72 100644
--- a/src/Avalonia.Controls/Image.cs
+++ b/src/Avalonia.Controls/Image.cs
@@ -17,6 +17,12 @@ namespace Avalonia.Controls
///
public static readonly StyledProperty SourceProperty =
AvaloniaProperty.Register(nameof(Source));
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty BlendModeProperty =
+ AvaloniaProperty.Register(nameof(BlendMode));
///
/// Defines the property.
@@ -34,7 +40,7 @@ namespace Avalonia.Controls
static Image()
{
- AffectsRender(SourceProperty, StretchProperty, StretchDirectionProperty);
+ AffectsRender(SourceProperty, StretchProperty, StretchDirectionProperty, BlendModeProperty);
AffectsMeasure(SourceProperty, StretchProperty, StretchDirectionProperty);
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue(AutomationControlType.Image);
}
@@ -49,6 +55,15 @@ namespace Avalonia.Controls
set => SetValue(SourceProperty, value);
}
+ ///
+ /// Gets or sets the blend mode for the image.
+ ///
+ public BitmapBlendingMode BlendMode
+ {
+ get => GetValue(BlendModeProperty);
+ set => SetValue(BlendModeProperty, value);
+ }
+
///
/// Gets or sets a value controlling how the image will be stretched.
///
@@ -91,7 +106,10 @@ namespace Avalonia.Controls
Rect sourceRect = new Rect(sourceSize)
.CenterRect(new Rect(destRect.Size / scale));
- context.DrawImage(source, sourceRect, destRect);
+ using (context.PushRenderOptions(RenderOptions with { BitmapBlendingMode = BlendMode }))
+ {
+ context.DrawImage(source, sourceRect, destRect);
+ }
}
}
diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs
index ba7ab60fb0..add72caa30 100644
--- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs
+++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs
@@ -29,36 +29,38 @@ namespace Avalonia.Skia
public static SKBlendMode ToSKBlendMode(this BitmapBlendingMode blendingMode)
{
- switch (blendingMode)
+ return blendingMode switch
{
- case BitmapBlendingMode.Unspecified:
- case BitmapBlendingMode.SourceOver:
- return SKBlendMode.SrcOver;
- case BitmapBlendingMode.Source:
- return SKBlendMode.Src;
- case BitmapBlendingMode.SourceIn:
- return SKBlendMode.SrcIn;
- case BitmapBlendingMode.SourceOut:
- return SKBlendMode.SrcOut;
- case BitmapBlendingMode.SourceAtop:
- return SKBlendMode.SrcATop;
- case BitmapBlendingMode.Destination:
- return SKBlendMode.Dst;
- case BitmapBlendingMode.DestinationIn:
- return SKBlendMode.DstIn;
- case BitmapBlendingMode.DestinationOut:
- return SKBlendMode.DstOut;
- case BitmapBlendingMode.DestinationOver:
- return SKBlendMode.DstOver;
- case BitmapBlendingMode.DestinationAtop:
- return SKBlendMode.DstATop;
- case BitmapBlendingMode.Xor:
- return SKBlendMode.Xor;
- case BitmapBlendingMode.Plus:
- return SKBlendMode.Plus;
- default:
- throw new ArgumentOutOfRangeException(nameof(blendingMode), blendingMode, null);
- }
+ BitmapBlendingMode.Unspecified => SKBlendMode.SrcOver,
+ BitmapBlendingMode.SourceOver => SKBlendMode.SrcOver,
+ BitmapBlendingMode.Source => SKBlendMode.Src,
+ BitmapBlendingMode.SourceIn => SKBlendMode.SrcIn,
+ BitmapBlendingMode.SourceOut => SKBlendMode.SrcOut,
+ BitmapBlendingMode.SourceAtop => SKBlendMode.SrcATop,
+ BitmapBlendingMode.Destination => SKBlendMode.Dst,
+ BitmapBlendingMode.DestinationIn => SKBlendMode.DstIn,
+ BitmapBlendingMode.DestinationOut => SKBlendMode.DstOut,
+ BitmapBlendingMode.DestinationOver => SKBlendMode.DstOver,
+ BitmapBlendingMode.DestinationAtop => SKBlendMode.DstATop,
+ BitmapBlendingMode.Xor => SKBlendMode.Xor,
+ BitmapBlendingMode.Plus => SKBlendMode.Plus,
+ BitmapBlendingMode.Screen => SKBlendMode.Screen,
+ BitmapBlendingMode.Overlay => SKBlendMode.Overlay,
+ BitmapBlendingMode.Darken => SKBlendMode.Darken,
+ BitmapBlendingMode.Lighten => SKBlendMode.Lighten,
+ BitmapBlendingMode.ColorDodge => SKBlendMode.ColorDodge,
+ BitmapBlendingMode.ColorBurn => SKBlendMode.ColorBurn,
+ BitmapBlendingMode.HardLight => SKBlendMode.HardLight,
+ BitmapBlendingMode.SoftLight => SKBlendMode.SoftLight,
+ BitmapBlendingMode.Difference => SKBlendMode.Difference,
+ BitmapBlendingMode.Exclusion => SKBlendMode.Exclusion,
+ BitmapBlendingMode.Multiply => SKBlendMode.Multiply,
+ BitmapBlendingMode.Hue => SKBlendMode.Hue,
+ BitmapBlendingMode.Saturation => SKBlendMode.Saturation,
+ BitmapBlendingMode.Color => SKBlendMode.Color,
+ BitmapBlendingMode.Luminosity => SKBlendMode.Luminosity,
+ _ => throw new ArgumentOutOfRangeException(nameof(blendingMode), blendingMode, null)
+ };
}
public static SKPoint ToSKPoint(this Point p)
diff --git a/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs b/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs
new file mode 100644
index 0000000000..1f8f5d2241
--- /dev/null
+++ b/tests/Avalonia.RenderTests/Controls/ImageBlendTests.cs
@@ -0,0 +1,83 @@
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Xunit;
+
+#if AVALONIA_SKIA
+namespace Avalonia.Skia.RenderTests
+#else
+namespace Avalonia.Direct2D1.RenderTests.Controls
+#endif
+{
+ public class ImageBlendTests : TestBase
+ {
+ private readonly Bitmap _bitmapBase;
+ private readonly Bitmap _bitmapOver;
+
+ public ImageBlendTests()
+ : base(@"Controls\Image\blend")
+ {
+ _bitmapBase = new Bitmap(Path.Combine(OutputPath, "Cat.jpg"));
+ _bitmapOver = new Bitmap(Path.Combine(OutputPath, "ColourShading - by Stib.png"));
+ }
+
+ [Fact]
+ public async Task Image_Blend_Nothing() => await TestBlendMode(BitmapBlendingMode.Unspecified);
+ [Fact]
+ public async Task Image_Blend_Plus() => await TestBlendMode(BitmapBlendingMode.Plus);
+ [Fact]
+ public async Task Image_Blend_Screen() => await TestBlendMode(BitmapBlendingMode.Screen);
+ [Fact]
+ public async Task Image_Blend_Overlay() => await TestBlendMode(BitmapBlendingMode.Overlay);
+ [Fact]
+ public async Task Image_Blend_Darken() => await TestBlendMode(BitmapBlendingMode.Darken);
+ [Fact]
+ public async Task Image_Blend_Lighten() => await TestBlendMode(BitmapBlendingMode.Lighten);
+ [Fact]
+ public async Task Image_Blend_ColorDodge() => await TestBlendMode(BitmapBlendingMode.ColorDodge);
+ [Fact]
+ public async Task Image_Blend_ColorBurn() => await TestBlendMode(BitmapBlendingMode.ColorBurn);
+ [Fact]
+ public async Task Image_Blend_HardLight() => await TestBlendMode(BitmapBlendingMode.HardLight);
+ [Fact]
+ public async Task Image_Blend_SoftLight() => await TestBlendMode(BitmapBlendingMode.SoftLight);
+ [Fact]
+ public async Task Image_Blend_Difference() => await TestBlendMode(BitmapBlendingMode.Difference);
+ [Fact]
+ public async Task Image_Blend_Exclusion() => await TestBlendMode(BitmapBlendingMode.Exclusion);
+ [Fact]
+ public async Task Image_Blend_Multiply() => await TestBlendMode(BitmapBlendingMode.Multiply);
+ [Fact]
+ public async Task Image_Blend_Hue() => await TestBlendMode(BitmapBlendingMode.Hue);
+ [Fact]
+ public async Task Image_Blend_Saturation() => await TestBlendMode(BitmapBlendingMode.Saturation);
+ [Fact]
+ public async Task Image_Blend_Color() => await TestBlendMode(BitmapBlendingMode.Color);
+ [Fact]
+ public async Task Image_Blend_Luminosity() => await TestBlendMode(BitmapBlendingMode.Luminosity);
+
+ private async Task TestBlendMode(BitmapBlendingMode blendMode, [CallerMemberName] string testName = "")
+ {
+ var panel = new Panel();
+ panel.Children.Add(new Image() { Source = _bitmapBase });
+ panel.Children.Add(new Image() { Source = _bitmapOver, BlendMode = blendMode });
+
+ var target = new Decorator
+ {
+ Width = 512,
+ Height = 512,
+ Child = new Border
+ {
+ Background = Brushes.Red,
+ Child = panel
+ }
+ };
+
+ await RenderToFile(target,testName);
+ CompareImages(testName);
+ }
+ }
+}
diff --git a/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs b/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs
new file mode 100644
index 0000000000..8236468aeb
--- /dev/null
+++ b/tests/Avalonia.RenderTests/Controls/ImageCompositionTests.cs
@@ -0,0 +1,70 @@
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Xunit;
+
+#if AVALONIA_SKIA
+namespace Avalonia.Skia.RenderTests
+#else
+namespace Avalonia.Direct2D1.RenderTests.Controls
+#endif
+{
+ public class ImageCompositionTests : TestBase
+ {
+ private readonly Bitmap _bitmapA;
+ private readonly Bitmap _bitmapB;
+
+ public ImageCompositionTests()
+ : base(@"Controls\Image\composition")
+ {
+ _bitmapA = new Bitmap(Path.Combine(OutputPath, "A.png"));
+ _bitmapB = new Bitmap(Path.Combine(OutputPath, "B.png"));
+ }
+ [Fact]
+ public async Task Image_Blend_SourceOver() => await TestCompositeMode(BitmapBlendingMode.SourceOver);
+ [Fact]
+ public async Task Image_Blend_Source() => await TestCompositeMode(BitmapBlendingMode.Source);
+ [Fact]
+ public async Task Image_Blend_SourceIn() => await TestCompositeMode(BitmapBlendingMode.SourceIn);
+ [Fact]
+ public async Task Image_Blend_SourceOut() => await TestCompositeMode(BitmapBlendingMode.SourceOut);
+ [Fact]
+ public async Task Image_Blend_SourceAtop() => await TestCompositeMode(BitmapBlendingMode.SourceAtop);
+ [Fact]
+ public async Task Image_Blend_Destination() => await TestCompositeMode(BitmapBlendingMode.Destination);
+ [Fact]
+ public async Task Image_Blend_DestinationIn() => await TestCompositeMode(BitmapBlendingMode.DestinationIn);
+ [Fact]
+ public async Task Image_Blend_DestinationOut() => await TestCompositeMode(BitmapBlendingMode.DestinationOut);
+ [Fact]
+ public async Task Image_Blend_DestinationOver() => await TestCompositeMode(BitmapBlendingMode.DestinationOver);
+ [Fact]
+ public async Task Image_Blend_DestinationAtop() => await TestCompositeMode(BitmapBlendingMode.DestinationAtop);
+ [Fact]
+ public async Task Image_Blend_Xor() => await TestCompositeMode(BitmapBlendingMode.Xor);
+
+ private async Task TestCompositeMode(BitmapBlendingMode blendMode, [CallerMemberName] string testName = "")
+ {
+ var panel = new Panel();
+ panel.Children.Add(new Image() { Source = _bitmapA });
+ panel.Children.Add(new Image() { Source = _bitmapB, BlendMode = blendMode });
+
+ var target = new Decorator
+ {
+ Width = 512,
+ Height = 512,
+ Child = new Border
+ {
+ Background = Brushes.Transparent,
+ Child = panel
+ }
+ };
+
+ await RenderToFile(target,testName);
+ CompareImages(testName);
+ }
+ }
+}
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Cat.jpg b/tests/TestFiles/Direct2D1/Controls/Image/blend/Cat.jpg
new file mode 100644
index 0000000000..01de4614f6
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Cat.jpg differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/ColourShading - by Stib.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/ColourShading - by Stib.png
new file mode 100644
index 0000000000..ef464dedb4
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/ColourShading - by Stib.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Color.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Color.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Color.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorBurn.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorBurn.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorBurn.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorDodge.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorDodge.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_ColorDodge.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Darken.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Darken.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Darken.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Difference.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Difference.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Difference.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Exclusion.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Exclusion.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Exclusion.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_HardLight.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_HardLight.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_HardLight.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Hue.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Hue.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Hue.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Lighten.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Lighten.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Lighten.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Luminosity.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Luminosity.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Luminosity.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Multiply.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Multiply.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Multiply.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Nothing.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Nothing.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Nothing.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Overlay.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Overlay.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Overlay.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Plus.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Plus.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Plus.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Saturation.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Saturation.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Saturation.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Screen.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Screen.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_Screen.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_SoftLight.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_SoftLight.expected.png
new file mode 100644
index 0000000000..c6f12e8b43
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/blend/Image_Blend_SoftLight.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/A.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/A.png
new file mode 100644
index 0000000000..fb3dacda4c
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/A.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/B.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/B.png
new file mode 100644
index 0000000000..13aaf23dde
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/B.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Destination.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Destination.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Destination.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationIn.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationIn.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationIn.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOut.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOut.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOut.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOver.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOver.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_DestinationOver.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Source.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Source.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Source.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceAtop.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceAtop.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceAtop.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceIn.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceIn.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceIn.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOut.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOut.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOut.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOver.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOver.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_SourceOver.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Xor.expected.png b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Xor.expected.png
new file mode 100644
index 0000000000..030552a395
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Controls/Image/composition/Image_Blend_Xor.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Cat.jpg b/tests/TestFiles/Skia/Controls/Image/blend/Cat.jpg
new file mode 100644
index 0000000000..01de4614f6
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Cat.jpg differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/ColourShading - by Stib.png b/tests/TestFiles/Skia/Controls/Image/blend/ColourShading - by Stib.png
new file mode 100644
index 0000000000..ef464dedb4
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/ColourShading - by Stib.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Color.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Color.expected.png
new file mode 100644
index 0000000000..b6e6b7c212
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Color.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorBurn.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorBurn.expected.png
new file mode 100644
index 0000000000..1812a59efd
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorBurn.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorDodge.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorDodge.expected.png
new file mode 100644
index 0000000000..ff12a5d501
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_ColorDodge.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Darken.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Darken.expected.png
new file mode 100644
index 0000000000..c6edbe00c9
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Darken.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Difference.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Difference.expected.png
new file mode 100644
index 0000000000..e9456b699e
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Difference.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Exclusion.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Exclusion.expected.png
new file mode 100644
index 0000000000..ced05f85e2
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Exclusion.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_HardLight.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_HardLight.expected.png
new file mode 100644
index 0000000000..d6d56f99ec
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_HardLight.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Hue.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Hue.expected.png
new file mode 100644
index 0000000000..832793eb1a
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Hue.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Lighten.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Lighten.expected.png
new file mode 100644
index 0000000000..9f0ae673ff
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Lighten.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Luminosity.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Luminosity.expected.png
new file mode 100644
index 0000000000..f772c5ce34
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Luminosity.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Multiply.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Multiply.expected.png
new file mode 100644
index 0000000000..5fc0c93605
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Multiply.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Nothing.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Nothing.expected.png
new file mode 100644
index 0000000000..4a5f0ea2aa
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Nothing.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Overlay.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Overlay.expected.png
new file mode 100644
index 0000000000..843ce50f75
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Overlay.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Plus.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Plus.expected.png
new file mode 100644
index 0000000000..ae159039bb
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Plus.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Saturation.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Saturation.expected.png
new file mode 100644
index 0000000000..9744e24f81
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Saturation.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Screen.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Screen.expected.png
new file mode 100644
index 0000000000..fe448fc3dc
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_Screen.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_SoftLight.expected.png b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_SoftLight.expected.png
new file mode 100644
index 0000000000..d39c01f973
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/blend/Image_Blend_SoftLight.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/A.png b/tests/TestFiles/Skia/Controls/Image/composition/A.png
new file mode 100644
index 0000000000..fb3dacda4c
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/A.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/B.png b/tests/TestFiles/Skia/Controls/Image/composition/B.png
new file mode 100644
index 0000000000..13aaf23dde
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/B.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Destination.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Destination.expected.png
new file mode 100644
index 0000000000..bcb03de2e2
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Destination.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png
new file mode 100644
index 0000000000..1f0cea9360
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationAtop.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationIn.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationIn.expected.png
new file mode 100644
index 0000000000..ebd1b2978d
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationIn.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOut.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOut.expected.png
new file mode 100644
index 0000000000..ebf07dc002
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOut.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOver.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOver.expected.png
new file mode 100644
index 0000000000..adda03eb8b
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_DestinationOver.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Source.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Source.expected.png
new file mode 100644
index 0000000000..cbb1398065
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Source.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceAtop.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceAtop.expected.png
new file mode 100644
index 0000000000..33bdf8efc4
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceAtop.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceIn.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceIn.expected.png
new file mode 100644
index 0000000000..f1989a2a77
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceIn.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOut.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOut.expected.png
new file mode 100644
index 0000000000..a2975afd06
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOut.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOver.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOver.expected.png
new file mode 100644
index 0000000000..1438009f98
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_SourceOver.expected.png differ
diff --git a/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Xor.expected.png b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Xor.expected.png
new file mode 100644
index 0000000000..ee74b79f52
Binary files /dev/null and b/tests/TestFiles/Skia/Controls/Image/composition/Image_Blend_Xor.expected.png differ