SkiaSharp 掩码筛选器SkiaSharp mask filters

下载示例下载示例Download Sample Download the sample

掩码筛选器是操作几何图形和 alpha 通道的图形对象的效果。Mask filters are effects that manipulate the geometry and alpha channel of graphical objects. 若要使用掩码筛选器,设置 MaskFilter 的属性SKPaint对象的类型 SKMaskFilter 已通过调用之一创建了SKMaskFilter静态方法。To use a mask filter, set the MaskFilter property of SKPaint to an object of type SKMaskFilter that you've created by calling one of the SKMaskFilter static methods.

熟悉掩码筛选器的最佳方法是通过使用这些静态方法。The best way to become familiar with mask filters is by experimenting with these static methods. 最有用的掩码筛选器创建模糊:The most useful mask filter creates a blur:

使示例变得模糊Blur Example

这是本文中所述的唯一掩码筛选器功能。That's the only mask filter feature described in this article. 在下一篇文章 SkiaSharp 映像筛选器还介绍了你可能更倾向于此的模糊效果。The next article on SkiaSharp image filters also describes a blur effect that you might prefer to this one.

静态 SKMaskFilter.CreateBlur 方法具有以下语法:The static SKMaskFilter.CreateBlur method has the following syntax:

public static SKMaskFilter CreateBlur (SKBlurStyle blurStyle, float sigma);

重载允许指定用来创建模糊和一个矩形,以避免模糊将与其他图形对象所覆盖的区域中的算法的标志。Overloads allow specifying flags for the algorithm used to create the blur, and a rectangle to avoid blurring in areas that will be covered with other graphical objects.

SKBlurStyle 是一个枚举,包含下列成员:SKBlurStyle is an enumeration with the following members:

  • Normal
  • Solid
  • Outer
  • Inner

以下示例中显示了这些样式的效果。The effects of these styles are shown in the examples below. sigma参数指定的模糊程度。The sigma parameter specifies the extent of the blur. 在较旧版本的 Skia,radius 值指出了模糊程度。In older versions of Skia, the extent of the blur was indicated with a radius value. 如果为应用程序适合的半径值,则静态 SKMaskFilter.ConvertRadiusToSigma 可以从另一个转换的方法。If a radius value is preferable for your application, there is a static SKMaskFilter.ConvertRadiusToSigma method that can convert from one to the other. 该方法乘以 0.57735 半径,并将 0.5。The method multiplies the radius by 0.57735 and adds 0.5.

掩码模糊试验页面 SkiaSharpFormsDemos 示例允许用户体验与模糊样式和 sigma 的值。The Mask Blur Experiment page in the SkiaSharpFormsDemos sample allows you to experiment with the blur styles and sigma values. XAML 文件实例化Picker具有四个SKBlurStyle枚举成员和一个Slider函数指定 sigma 值:The XAML file instantiates a Picker with the four SKBlurStyle enumeration members and a Slider for specifying the sigma value:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
             xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.MaskBlurExperimentPage"
             Title="Mask Blur Experiment">
    
    <StackLayout>
        <skiaforms:SKCanvasView x:Name="canvasView"
                                VerticalOptions="FillAndExpand"
                                PaintSurface="OnCanvasViewPaintSurface" />

        <Picker x:Name="blurStylePicker" 
                Title="Filter Blur Style" 
                Margin="10, 0"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKBlurStyle}">
                    <x:Static Member="skia:SKBlurStyle.Normal" />
                    <x:Static Member="skia:SKBlurStyle.Solid" />
                    <x:Static Member="skia:SKBlurStyle.Outer" />
                    <x:Static Member="skia:SKBlurStyle.Inner" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Slider x:Name="sigmaSlider"
                Maximum="10"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Label Text="{Binding Source={x:Reference sigmaSlider},
                              Path=Value,
                              StringFormat='Sigma = {0:F1}'}"
               HorizontalTextAlignment="Center" />
    </StackLayout>
</ContentPage>

代码隐藏文件使用这些值以创建SKMaskFilter对象,并将其设置为MaskFilter属性的SKPaint对象。The code-behind file uses those values to create an SKMaskFilter object and set it to the MaskFilter property of an SKPaint object. SKPaint对象用于绘制文本字符串和位图:This SKPaint object is used to draw both a text string and a bitmap:

public partial class MaskBlurExperimentPage : ContentPage
{
    const string TEXT = "Blur My Text";

    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                            typeof(MaskBlurExperimentPage), 
                            "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");

    public MaskBlurExperimentPage ()
    {
        InitializeComponent ();
    }

    void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear(SKColors.Pink);

        // Get values from XAML controls
        SKBlurStyle blurStyle =
            (SKBlurStyle)(blurStylePicker.SelectedIndex == -1 ?
                                        0 : blurStylePicker.SelectedItem);

        float sigma = (float)sigmaSlider.Value;

        using (SKPaint paint = new SKPaint())
        {
            // Set SKPaint properties
            paint.TextSize = (info.Width - 100) / (TEXT.Length / 2);
            paint.MaskFilter = SKMaskFilter.CreateBlur(blurStyle, sigma);

            // Get text bounds and calculate display rectangle
            SKRect textBounds = new SKRect();
            paint.MeasureText(TEXT, ref textBounds);
            SKRect textRect = new SKRect(0, 0, info.Width, textBounds.Height + 50);

            // Center the text in the display rectangle
            float xText = textRect.Width / 2 - textBounds.MidX;
            float yText = textRect.Height / 2 - textBounds.MidY;

            canvas.DrawText(TEXT, xText, yText, paint);

            // Calculate rectangle for bitmap
            SKRect bitmapRect = new SKRect(0, textRect.Bottom, info.Width, info.Height);
            bitmapRect.Inflate(-50, -50);

            canvas.DrawBitmap(bitmap, bitmapRect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

下面是在 iOS、 Android 和与通用 Windows 平台 (UWP) 上运行的程序Normal模糊样式和增加sigma级别:Here's the program running on iOS, Android, and the Universal Windows Platform (UWP) with the Normal blur style and increasing sigma levels:

屏蔽模糊试验-NormalMask Blur Experiment - Normal

您会注意到,位图边缘受变得模糊。You'll notice that only the edges of the bitmap are affected by the blur. SKMaskFilter类不是要使用如果你想要使整个位图图像模糊的正确效果。The SKMaskFilter class is not the correct effect to use if you want to blur an entire bitmap image. 为此,你将想要使用 SKImageFilter 类,如在下一篇文章中所述 SkiaSharp 映像筛选器For that you'll want to use the SKImageFilter class as described in the next article on SkiaSharp image filters.

为增加方向的更模糊文本sigma参数。The text is blurred more with increasing values of the sigma argument. 在与此程序的试验,你会注意到,为特定sigma值,是 Windows 10 桌面版上更极端变得模糊。In experimenting with this program, you'll notice that for a particular sigma value, the blur is more extreme on the Windows 10 desktop. 这种差异是因为像素密度较低比移动设备上的桌面监视器上,并且因此较低的文本框高度以像素为单位。This difference occurs because the pixel density is lower on a desktop monitor than on mobile devices, and hence the text height in pixels is lower. sigma值成正比在模糊程度上,以像素为单位,因此,对于给定sigma值的效果是更极端上较低分辨率显示。The sigma value is proportional to a blur extent in pixels, so for a given sigma value, the effect is more extreme on lower resolution displays. 在生产应用程序中,您可能需要计算sigma是图形的大小成正比的值。In a production application, you'll probably want to calculate a sigma value that is proportional to the size of the graphic.

在你的应用程序将查找最佳的模糊级别确定之前尝试几个值。Try several values before settling on a blur level that looks the best for your application. 例如,在掩码模糊实验页上,请尝试设置sigma如下所示:For example, in the Mask Blur Experiment page, try setting sigma like this:

sigma = paint.TextSize / 18;
paint.MaskFilter = SKMaskFilter.CreateBlur(blurStyle, sigma);

现在Slider不起作用,但在平台之间保持一致的模糊程度:Now the Slider has no effect, but the degree of blur is consistent among the platforms:

屏蔽模糊试验-一致Mask Blur Experiment - Consistent

所有屏幕截图到目前为止显示了使用创建的模糊SKBlurStyle.Normal枚举成员。All the screenshots so far have shown blur created with the SKBlurStyle.Normal enumeration member. 以下屏幕截图显示的效果SolidOuter,和Inner模糊样式:The following screenshots show the effects of the Solid, Outer, and Inner blur styles:

屏蔽模糊实验Mask Blur Experiment

IOS 屏幕快照显示Solid样式:文本字符仍以纯黑色笔划形式出现, 并且模糊将添加到这些文本字符的外部。The iOS screenshot shows the Solid style: The text characters are still present as solid black strokes, and the blur is added to the outside of these text characters.

中间的 Android 屏幕截图显示Outer样式:将消除字符笔划本身 (如位图), 模糊会将文本字符出现的空白区域环绕在空白区域。The Android screenshot in the middle shows the Outer style: The character strokes themselves are eliminated (as is the bitmap) and the blur surrounds the empty space where the text characters once appeared.

UWP 上正确显示的屏幕截图Inner样式。The UWP screenshot on the right shows the Inner style. 模糊被限制为文本字符通常占用的区域。The blur is restricted to the area normally occupied by the text characters.

SkiaSharp 线性渐变一文所述反射渐变使用线性渐变和一个转换来模拟的文本字符串的反射程序:The SkiaSharp linear gradient article described a Reflection Gradient program that used a linear gradient and a transform to mimic a reflection of a text string:

反射渐变Reflection Gradient

模糊反射页会将一条语句添加到该代码:The Blurry Reflection page adds a single statement to that code:

public class BlurryReflectionPage : ContentPage
{
    const string TEXT = "Reflection";

    public BlurryReflectionPage()
    {
        Title = "Blurry Reflection";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            // Set text color to blue
            paint.Color = SKColors.Blue;

            // Set text size to fill 90% of width
            paint.TextSize = 100;
            float width = paint.MeasureText(TEXT);
            float scale = 0.9f * info.Width / width;
            paint.TextSize *= scale;

            // Get text bounds
            SKRect textBounds = new SKRect();
            paint.MeasureText(TEXT, ref textBounds);

            // Calculate offsets to position text above center
            float xText = info.Width / 2 - textBounds.MidX;
            float yText = info.Height / 2;

            // Draw unreflected text
            canvas.DrawText(TEXT, xText, yText, paint);

            // Shift textBounds to match displayed text
            textBounds.Offset(xText, yText);

            // Use those offsets to create a gradient for the reflected text
            paint.Shader = SKShader.CreateLinearGradient(
                                new SKPoint(0, textBounds.Top),
                                new SKPoint(0, textBounds.Bottom),
                                new SKColor[] { paint.Color.WithAlpha(0),
                                                paint.Color.WithAlpha(0x80) },
                                null,
                                SKShaderTileMode.Clamp);

            // Create a blur mask filter
            paint.MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, paint.TextSize / 36);

            // Scale the canvas to flip upside-down around the vertical center
            canvas.Scale(1, -1, 0, yText);

            // Draw reflected text
            canvas.DrawText(TEXT, xText, yText, paint);
        }
    }
}

新的语句将添加文本大小为基础的反射文本的模糊筛选的器:The new statement adds a blur filter for the reflected text that is based on the text size:

paint.MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, paint.TextSize / 36);

此模糊筛选器会导致看起来更实际的反射:This blur filter causes the reflection to seem much more realistic:

模糊反射Blurry Reflection