Implementing Image blur and gaussian blur in a Windows universal app

Image blur and gaussian blur can give a nice visual effect if used right . Blurred images for backgrounds can give a nice subtle effect and for the same reason it has been used by designers for years. However it's not supported out of the box on Windows Universal apps platform. Luckily there's atleast  two different nuget packages which can help us get started. 
I tried both the Lumia Imaging SDK 2.0 and Win2D. 

Between the two I see Win2D as the winner because the rendering quality, speed and amount of documentation. The downside is  that you don't have the same layout flexibility out of the box as with the Lumia Image SDK. 
Below you'll find source for both implementations.

Win2D Gaussian Blur

Tap to see the Gaussian Blur rendering. The rendering quality way better than the Lumia Image SDK.

Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering. It makes use of the Direct2D engine and utilizes the GPU to create the new blur effect. 
Win2D comes with a great documentation that gets you started in seconds and it works on both Windows Phone and Windows Store. 
The rendering is smooth, crisp and it's really really fast. Only downside is that you have to work the with the Win2D CanvasControl and CanvasBitmap rather than a regular Bitmap or WriteableBitmap.

 

Download demo and sample source

 

Lumia Image SDK 2.0

Tap to see the Blur rendering. The rendering quality not quite as good as the Win2D rendering.

The Lumia Image SDK is a Nokia and now Microsoft owned SDK created to provide easy-to-use filtering and image manipulation capabilities. The Image SDK is known for being fast - especially when working with live camera feeds and it has been a part of the platform for a while. I assume it makes use of the GPU but didn't find any material on the core of the Lumia Image SDK.

The rendering is not nearly as smooth as the Win2D though. If you compare the images it looks like the Lumia Image SDK makes use of a blur algorithm that blurs in squares. Not nearly is neat and good looking as Win2D but on the upside you get to work directly with Bitmaps and Writeable bitmaps with offers layout flexibility compared to Win2D where you have to some of the calculations yourself to get the image in the right size. 

Download source and sample

 

Wrapup

Win2D is the clear winner here though the Lumia SDK is a bit easier to implement but offers less flexibility and quality. A huge shout out to Rodrigo Diaz (@r2d2rigo) for introducing me to Win2D! He's a absolutely brilliant and clever guy. One to follow for sure! 

If you prefer not downloading the source you can find it below this section.

Feel free to contact contact me or write in the comments below if you have any questions or problems getting the sample to work.

P.S Make sure you follow me on twitter @deanihansen for more news, design tips, articles and how-to's.


Code snippets for Lumia Image SDK blur and Win2D Gaussian Blur

Lumia Image SDK implementation:

1) This code snippet is a part of a templated control. The template contains an Image named "imagePresenter":

private async Task RenderImage()
{
    if (!string.IsNullOrWhiteSpace(ImageUrl))
    {
        var imageControl = GetTemplateChild("imagePresenter") as Image;

        if (imageControl != null)
        {
            var client = new HttpClient();

            // or get stream locally
            var stream = await client.GetStreamAsync(ImageUrl);

            var source = new Lumia.Imaging.StreamImageSource(stream, ImageFormat.Undefined);

            var source = new Lumia.Imaging.StreamImageSource(stream, ImageFormat.Undefined);

            var info = await source.GetInfoAsync();

            double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / 96.0;


            double pixelWidth = Window.Current.Bounds.Width * displayScaling;

            var scalefactor = pixelWidth / info.ImageSize.Width;

            using (var filterEffect = new FilterEffect(source))
            {
                WriteableBitmap target = new WriteableBitmap((int)pixelWidth, (int)(info.ImageSize.Height * scalefactor));

                var filter = new BlurFilter(45);

                filterEffect.Filters = new IFilter[] { filter };

                using (var renderer = new WriteableBitmapRenderer(filterEffect, target, OutputOption.PreserveAspectRatio))
                {
                    await renderer.RenderAsync();

                    imageControl.Source = target;
                }
            }
        }
    }
}

Win2D Gaussian blur implementation

1) Create the CanvasControl which will host our Image and hook into the two events. Finally set the CanvasControl as Content on a contentpresenter or control.

control = new CanvasControl();
control.Draw += OnDraw;
control.CreateResources += OnCreateResources;
contentPresenter.Content = control;

2) Create and load the image from a URL

private async void OnCreateResources(CanvasControl sender, object args)
{
    if (!string.IsNullOrWhiteSpace(ImageUrl))
    {
        scaleEffect = new ScaleEffect();
        blurEffect = new GaussianBlurEffect();

        image = await CanvasBitmap.LoadAsync(sender.Device,
          new Uri(ImageUrl));

        imageLoaded = true;

        sender.Invalidate();
    }
}

3) On Draw we take the draw session and apply a scale effect to resize to the appropriate siize for the screen and DPI. Afterwards the blur effect is applied and finally the draw is called to render the image onto the Canvas.

private void OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    if (imageLoaded)
    {
        using (var session = args.DrawingSession)
        {
            session.Units = CanvasUnits.Pixels;

            double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / 96.0;

            double pixelWidth = sender.ActualWidth * displayScaling;

            var scalefactor = pixelWidth / image.Size.Width;

            scaleEffect.Source = this.image;
            scaleEffect.Scale = new Vector2()
            {
                X = (float)scalefactor,
                Y = (float)scalefactor
            };

            blurEffect.Source = scaleEffect;
            blurEffect.BlurAmount = Blur;

            session.DrawImage(blurEffect, 0.0f, 0.0f);
        }
    }
}