So, how to make such effect using C# & XAML?
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. :)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With