how to apply mask to CompositionBrush

1.1k views Asked by At
<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

2

There are 2 answers

0
Liero On BEST ANSWER

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>
0
Vincent On

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