13
<Grid>
    <Image x:Name="BackgroundImage" Source="/Assets/background.png" />
    <Rectangle x:Name="ClippingRect" Margin="50" Fill="#30f0" />
</Grid>

How do I apply alpha mask, or clipping mask, so everything except the rectangle will be blurred?

I do the usual: GraphicsEffect->EffectFactory->Brush->Set to SpriteVisual

 var graphicsEffect = new BlendEffect
 {
     Mode = BlendEffectMode.Multiply,
     Background = new ColorSourceEffect
     {
         Name = "Tint",
         Color = Windows.UI.Color.FromArgb(50,0,255,0),
     },

     Foreground = new GaussianBlurEffect()
     {
         Name = "Blur",
         Source =  new CompositionEffectSourceParameter("Backdrop"),
         BlurAmount = (float)20,
         BorderMode = EffectBorderMode.Hard,
     }
 };

 var blurEffectFactory = _compositor.CreateEffectFactory(graphicsEffect,
     new[] { "Blur.BlurAmount", "Tint.Color" });

 var _brush = blurEffectFactory.CreateBrush();
 _brush.SetSourceParameter("Backdrop", _compositor.CreateBackdropBrush());

 var blurSprite = _compositor.CreateSpriteVisual();
 blurSprite.Size = new Vector2((float)BackgroundImage.ActualWidth, (float)BackgroundImage.ActualHeight);
 blurSprite.Brush = _brush;
 ElementCompositionPreview.SetElementChildVisual(BackgroundImage, blurSprite);

enter image description here

Liero
  • 25,216
  • 29
  • 151
  • 297
  • could you please provide screenshot with expected result? – Andrii Krupka Feb 14 '17 at 13:49
  • Barring a solution by someone more knowledgeable of WPF than me, could you just make the entire background blurry, and then superimpose a snippet of the image with no blur on top of that? – wablab Feb 14 '17 at 14:28
  • Be me - I would got for GDI+ tools and bitmap modifying of current pixels – Tatranskymedved Feb 14 '17 at 22:04
  • @Tatranskymedved: first of all, GDI+ is not a way to go in UWP. Second, I know it is possible using composition api, I just haven't been able to get it working in appropriate amount of time, since I'm new to the API. I will probably go back and try it again. – Liero Feb 15 '17 at 07:55
  • @Liero: sorry I haven't reallized this is UWP & honestly I didn't know that GDI+ is not worth using there. Will get lesson from this. Thanks =) – Tatranskymedved Feb 15 '17 at 08:30

2 Answers2

2

You can use the following solution which is using twice the same image. I'm using one for the blurred background and one for the clipped foreground.

The idea is to draw the background blurred full-size and over it only the clipped region you want using the Clip property for the foreground visual.

The XAML for the page/control:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image x:Name="BackgroundImage" Source="/Assets/Purple Tentacle.png" />
    <Image x:Name="ClippedImage" Source="/Assets/Purple Tentacle.png" />
</Grid>

The code behind:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        _compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        _backgroundImageVisual  = ElementCompositionPreview.GetElementVisual(BackgroundImage);

        var graphicEffect   = new BlendEffect
        {
            Mode    = BlendEffectMode.Multiply,
            Background  = new ColorSourceEffect
            {
                Color= Color.FromArgb(50, 0, 255, 0)
            },

            Foreground = new GaussianBlurEffect
            {
                Source = new CompositionEffectSourceParameter("Backdrop"),
                BlurAmount  = 20.0f,
                BorderMode = EffectBorderMode.Hard
            }
        };


        var backdropBrush       = _compositor.CreateBackdropBrush();

        var blurEffectFactory   = _compositor.CreateEffectFactory(graphicEffect);
        _brush                  = blurEffectFactory.CreateBrush();
        _brush.SetSourceParameter("Backdrop", backdropBrush);

        _blurSprite          = _compositor.CreateSpriteVisual();
        _blurSprite.Brush    = _brush;

        ElementCompositionPreview.SetElementChildVisual(BackgroundImage, _blurSprite);

        _foregroundImageVisual  = ElementCompositionPreview.GetElementVisual(ClippedImage);
        _foregroundImageVisual.Clip = _compositor.CreateInsetClip(100, 100, 100, 100);

        SizeChanged += MainPage_SizeChanged;
        MainPage_SizeChanged(this, null);
    }

    private void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        _blurSprite.Size    = new Vector2((float) BackgroundImage.ActualWidth, (float) BackgroundImage.ActualHeight);

        // change the clip values here to change the non-blurred region
        _foregroundImageVisual.Clip = _compositor.CreateInsetClip(100, 100, 100, 100);
    }

enter image description here

Vincent
  • 3,656
  • 1
  • 23
  • 32
0

In Creators update, I can create class derived from XamlCompositionBrushBase and the apply it to the xaml element, so it does the blurring:

<Grid>
    <Image x:Name="BackgroundImage" Source="/Assets/background.png" />
    <Path>
       <Path.Fill>
          <local:BlurTintBrush BlurRadius="5" TintColor="Black" TintOpacity="0.7" />
       </Path.Fill>
       <Path.Data>
           <GeometryGroup>
               <RectangleGeometry x:Name="ImageGeometry" Rect="0,0,1027,768" /
               <RectangleGeometry x:Name="CropGeometry" Rect="50,50,25,25" />
           </GeometryGroup>
       </Path.Data>
    </Path>
</Grid>
Liero
  • 25,216
  • 29
  • 151
  • 297