Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make frosted glass effect in Windows 10 Universal App? [closed]

So, how to make such effect using C# & XAML?

http://i.stack.imgur.com/L2Zhc.gif

like image 973
SnakeAce Avatar asked Dec 20 '22 01:12

SnakeAce


2 Answers

I've been trying to create something like this ever since iOS 7 introduced the frosted glass. Now thanks to Win2D, it's a lot simpler to create similar effects in WinRT.

First, you will need to get the Win2D.uwp package from NuGet.

The idea is to create a GaussianBlurEffect based on the image source and put it on top of another white colored mask to mimic the frosted glass look.

To get the GaussianBlurEffect ready, you will need to create a xaml control CanvasControl from the Win2D library. So the UI structure is something like this -

<Grid x:Name="ImagePanel2" Width="356" Height="200" Margin="0,0,0,40" VerticalAlignment="Bottom">
    <Image x:Name="Image2" Source="Assets/Food.jpg" Stretch="UniformToFill" />
    <Grid x:Name="Overlay" ManipulationMode="TranslateX" ManipulationStarted="Overlay_ManipulationStarted" ManipulationDelta="Overlay_ManipulationDelta" ManipulationCompleted="Overlay_ManipulationCompleted" RenderTransformOrigin="0.5,0.5">
        <Grid.Clip>
            <RectangleGeometry x:Name="Clip" Rect="0, 0, 356, 200" />
        </Grid.Clip>
        <Rectangle x:Name="WhiteMask" Fill="White" />
        <Xaml:CanvasControl x:Name="Canvas" CreateResources="Canvas_CreateResources" Draw="Canvas_Draw" />
    </Grid>
    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Frosted Glass" VerticalAlignment="Top" Foreground="#FF595959" Margin="12,12,0,0" FontWeight="Light" FontSize="26.667" FontStyle="Italic" TextLineBounds="Tight" />
</Grid>

Note I've created a Clip for the Overlay element, 'cause I need to reduce the Rect's third parameter (i.e. the Width) while I am panning it to the left to make an illusion that the Overlay is sliding along with my finger.

The code behind is quite straight forward -

void Canvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
    args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
}

async Task CreateResourcesAsync(CanvasControl sender)
{
    // give it a little bit delay to ensure the image is load, ideally you want to Image.ImageOpened event instead
    await Task.Delay(200);

    using (var stream = new InMemoryRandomAccessStream())
    {
        // get the stream from the background image
        var target = new RenderTargetBitmap();
        await target.RenderAsync(this.Image2);

        var pixelBuffer = await target.GetPixelsAsync();
        var pixels = pixelBuffer.ToArray();

        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)target.PixelWidth, (uint)target.PixelHeight, 96, 96, pixels);

        await encoder.FlushAsync();
        stream.Seek(0);

        // load the stream into our bitmap
        _bitmap = await CanvasBitmap.LoadAsync(sender, stream);
    }
}

void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
    using (var session = args.DrawingSession)
    {
        var blur = new GaussianBlurEffect
        {
            BlurAmount = 50.0f, // increase this to make it more blurry or vise versa.
            //Optimization = EffectOptimization.Balanced, // default value
            //BorderMode = EffectBorderMode.Soft // default value
            Source = _bitmap
        };

        session.DrawImage(blur, new Rect(0, 0, sender.ActualWidth, sender.ActualHeight),
            new Rect(0, 0, _bitmap.SizeInPixels.Width, _bitmap.SizeInPixels.Height), 0.9f);
    }
}

void Overlay_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
    // reset the inital with of the Rect
    _x = (float)this.ImagePanel2.ActualWidth;
}

void Overlay_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    // get the movement on X axis
    _x += (float)e.Delta.Translation.X;

    // keep the pan within the bountry
    if (_x > this.ImagePanel2.ActualWidth || _x < 0) return;

    // we clip the overlay to reveal the actual image underneath
    this.Clip.Rect = new Rect(0, 0, _x, this.ImagePanel2.ActualHeight);
}

void Overlay_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
    // reset the clip to show the full overlay
    this.Clip.Rect = new Rect(0, 0, this.ImagePanel2.ActualWidth, this.ImagePanel2.ActualHeight);
}

You can further adjust the BlurAmount property as well as the opacity figure (0.9f) to get youself the exact effect you want.

Also to note that there might be another (better?) way to do this in the future. If the new Composition API does support the GaussianBlurEffect in a future release, I will update the answer.

You can find the current working sample from this GitHub repo. And I've attached an image here to showcase how it looks like. :)

enter image description here

like image 59
Justin XL Avatar answered Dec 28 '22 09:12

Justin XL


You should look into the Win2D classes and in there for the Canvas Effects - there is a GaussianBlurEffect that might be helpful. Here's the reference: http://microsoft.github.io/Win2D/html/N_Microsoft_Graphics_Canvas_Effects.htm and for the GaussianBlurEffect: http://microsoft.github.io/Win2D/html/T_Microsoft_Graphics_Canvas_Effects_GaussianBlurEffect.htm including some C# code samples.

Addition: if you want to know how to use win2D, I just found a handy tutorial (which I am following myself right now :)) http://blogs.msdn.com/b/uk_faculty_connection/archive/2014/09/05/win2d.aspx

like image 35
Kristina Avatar answered Dec 28 '22 09:12

Kristina