Blur effects are getting pretty common in app designs, especially since iOS 7 started introducing them in some OS components like Control Center – and even the Windows 10 Start Menu uses the same effect to display a “frosted glass” look over the current background window.

Instead of a simple blur, which has been already explained by the awesome Deani Hansen, we are going to implement an iris blur (as Photoshop calls it; other resources call it “blur around borders”, and Instagram names it “tilt shift” with a radial blur in an UWP app by using the awesome Win2D library. It consists of a circular or ellipsoid area where the image shows focused, but everything else around it is defocused (or “blurred”) progressively, to give it a nice fading effect with no solid transition. So, let’s get started!

Approach

To achieve the result shown above, we are going to draw a blurred version of the image (in our case, a very beautiful one taken from Windows 10’s Spotlight backgrounds) over the original one – however, it will have a transparency mask applied so it can show a “hole” where there is no blurring. For additional artistic result, the hole won’t have clearly defined borders – instead we are going to use a radial gradient so it blends progressively over the non-blurred image. The following image describes how the blurred image with mask applied will be obtained:

We could store the resulting image in a CanvasRenderTarget instance and then draw it to our CanvasControl when needed – however, we can skip this intermediate step if we directly draw the original image and then the blurred one on top, just like the followind diagram shows:

With all concepts clear, let’s go ahead with the implementation – I promise you it’s going to be really easy!

Implementation

Start by adding the Win2D.UWP library to your project from NuGet, and creating a CanvasControl in XAML. Hook up its CreateResources event and instantiate a new member variable of type CanvasRadialGradientBrush – along with loading the image we are going to draw. Our radial brush will have Colors.Transparent as a starting colour and Colors.Black as the ending one – the ending one could have been Colors.White or any other solid one though, as the layer will only take the alpha (transparency) component into account.

private void Canvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { // Create instance of radial gradient brush; the center will be transparent and the extremes opaque black. radialBrush = new CanvasRadialGradientBrush(sender, Colors.Transparent, Colors.Black); // Load image to draw. args.TrackAsyncAction(Task.Run(async () => { image = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///SpotlightImage.png")); }).AsAsyncAction()); }

Next, we are going to wire up the Draw event – and perform all of our drawing there. Start by clearing the CanvasDrawingSession ’s background to a colour of your choice, and then set the Center , RadiusX and RadiusY parameters of the radial gradient brush to meaningful values (in our case the center is always the center of the image/canvas, and the radius will be updated through a Slider control); then, draw the untouched image through CanvasDrawingSession.DrawImage :

// Start drawing session and clear background to white. var session = args.DrawingSession; args.DrawingSession.Clear(Colors.White); // Set the center of the radial gradient as the center of the image. radialBrush.Center = new System.Numerics.Vector2((float)(image.Size.Width / 2.0f), (float)(image.Size.Height / 2.0f)); // Assing gradient radius from slider control. radialBrush.RadiusX = radialBrush.RadiusY = (float)BlurRadius.Value; // Draw unaltered image first. session.DrawImage(image, image.Bounds);

Now comes the fun part – working with layers. The logic behind is that you create a layer by calling CanvasDrawingSession.CreateLayer and passing an opacity value, ICanvasBrush or CanvasGeometry and everything that is drawn from that point is affected by the opacity/mask/clipping area – pretty convenient, huh? Then, to stop using it, you just have to Dispose the CanvasActiveLayer – or instead, wrap everything inside an using block.

So, we are going to pass the CanvasRadialGradientBrush as the mask parameter, and then draw the image again but after applying a GaussianBlurEffect on it. This way, the masked, blurred version of the image will draw on top of the solid one, composing the desided effect:

// Create a layer, this way all elements drawn will be affected by a transparent mask // which in our case is the radial gradient. using (session.CreateLayer(radialBrush)) { // Create gaussian blur effect. using (var blurEffect = new GaussianBlurEffect()) { // Set image to blur. blurEffect.Source = image; // Set blur amount from slider control. blurEffect.BlurAmount = (float)BlurAmount.Value; // Explicitly set optimization mode to highest quality, since we are using big blur amount values. blurEffect.Optimization = EffectOptimization.Quality; // This prevents the blur effect from wrapping around. blurEffect.BorderMode = EffectBorderMode.Hard; // Draw blurred image on top of the unaltered one. It will be masked by the radial gradient // thus showing a transparent hole in the middle, and properly overlaying the alpha values. session.DrawImage(blurEffect, 0, 0); } }

I told you it was easy, wasn’t it? And just for reference, here is a video of how the effect looks in the sample project that complements this tutorial:

Source code

Get the source code for the entire sample project in the Win2D-Samples GitHub repository, under the IrisBlurWin2D subfolder.