Freigeben über


SkiaSharp Mask Filter

Maskenfilter sind Effekte, die die Geometrie und den Alphakanal grafischer Objekte bearbeiten. Um einen Maskenfilter zu verwenden, legen Sie die MaskFilter Eigenschaft eines SKPaint Typs SKMaskFilter fest, das Sie durch Aufrufen einer der SKMaskFilter statischen Methoden erstellt haben.

Die beste Möglichkeit, sich mit Maskenfiltern vertraut zu machen, besteht darin, mit diesen statischen Methoden zu experimentieren. Der nützlichste Maskenfilter erstellt einen Weichzeichner:

Weichzeichnen (Beispiel)

Dies ist das einzige Maskenfilterfeature, das in diesem Artikel beschrieben wird. Im nächsten Artikel zu SkiaSharp-Bildfiltern wird auch ein Weichzeichnereffekt beschrieben, den Sie diesem vorziehen könnten.

Die statische SKMaskFilter.CreateBlur Methode weist die folgende Syntax auf:

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

Überladungen ermöglichen das Angeben von Flags für den Algorithmus, der zum Erstellen des Weichzeichnens verwendet wird, und ein Rechteck, um zu vermeiden, dass in Bereichen, die mit anderen grafischen Objekten abgedeckt werden, verschwommen werden.

SKBlurStyle ist eine Aufzählung mit den folgenden Membern:

  • Normal
  • Solid
  • Outer
  • Inner

Die Effekte dieser Formatvorlagen werden in den folgenden Beispielen gezeigt. Der sigma Parameter gibt den Umfang des Weichzeichners an. In älteren Versionen von Skia wurde der Umfang des Weichzeichners mit einem Radiuswert angegeben. Wenn ein Radiuswert für Ihre Anwendung bevorzugt wird, gibt es eine statische SKMaskFilter.ConvertRadiusToSigma Methode, die von einer in die andere konvertiert werden kann. Die Methode multipliziert den Radius um 0,57735 und addiert 0,5.

Auf der Seite "Mask Blur Experiment" im Beispiel können Sie mit den Weichzeichnerarten und Sigmawerten experimentieren. Die XAML-Datei instanziiert eine Picker mit den vier SKBlurStyle Enumerationsmembern und eine Slider zum Angeben des Sigmawerts:

<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>

Die CodeBehind-Datei verwendet diese Werte, um ein SKMaskFilter Objekt zu erstellen und auf die MaskFilter Eigenschaft eines SKPaint Objekts festzulegen. Dieses SKPaint Objekt wird verwendet, um sowohl eine Textzeichenfolge als auch eine Bitmap zu zeichnen:

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);
        }
    }
}

Hier ist das Programm, das unter iOS, Android und dem Universelle Windows-Plattform (UWP) ausgeführt wird, mit dem Weichzeichnerstil und der Erhöhung sigma der Normal Ebenen:

Mask Blur Experiment - Normal

Sie werden feststellen, dass nur die Kanten der Bitmap vom Weichzeichner betroffen sind. Die SKMaskFilter Klasse ist nicht der richtige Effekt, der verwendet werden soll, wenn Sie ein gesamtes Bitmapbild weichzeichnen möchten. Dafür sollten Sie die SKImageFilter Klasse wie im nächsten Artikel zu SkiaSharp-Bildfiltern beschrieben verwenden.

Der Text wird mit zunehmenden Werten des sigma Arguments verschwommen. Beim Experimentieren mit diesem Programm werden Sie feststellen, dass der Weichzeichner für einen bestimmten sigma Wert auf dem Windows 10-Desktop extremer ist. Dieser Unterschied tritt auf, da die Pixeldichte auf einem Desktopmonitor niedriger ist als auf mobilen Geräten, und daher ist die Texthöhe in Pixeln niedriger. Der sigma Wert ist proportional zu einem Weichzeichner in Pixeln, daher ist der Effekt für einen bestimmten sigma Wert extremer auf Displays mit niedrigerer Auflösung. In einer Produktionsanwendung möchten Sie wahrscheinlich einen sigma Wert berechnen, der proportional zur Größe der Grafik ist.

Probieren Sie mehrere Werte aus, bevor Sie sich auf einer Weichzeichnerebene niederlassen, die für Ihre Anwendung am besten geeignet ist. Versuchen Sie z. B. auf der Seite "Mask blur Experiment " die Einstellung sigma wie folgt:

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

Jetzt hat dies Slider keine Wirkung, aber der Grad des Weichzeichnens ist unter den Plattformen konsistent:

Mask blur Experiment - Konsistent

Alle bisher erstellten Screenshots haben den Weichzeichner mit dem SKBlurStyle.Normal Enumerationselement erstellt. Die folgenden Screenshots zeigen die Effekte der SolidFormatvorlagen , Outerund Inner Weichzeichner:

Mask Blur Experiment

Der iOS-Screenshot zeigt die Solid Formatvorlage: Die Textzeichen sind weiterhin als einfarbige schwarze Striche vorhanden, und der Weichzeichner wird außerhalb dieser Textzeichen hinzugefügt.

Der Android-Screenshot in der Mitte zeigt die Outer Formatvorlage: Die Zeichenstriche selbst werden entfernt (wie die Bitmap), und der Weichzeichner umgibt den leeren Bereich, in dem die Textzeichen einmal angezeigt wurden.

Der UWP-Screenshot auf der rechten Seite zeigt die Inner Formatvorlage. Der Weichzeichner ist auf den Bereich beschränkt, der normalerweise von den Textzeichen belegt wird.

Der Linearverlaufsartikel "SkiaSharp" beschreibt ein Reflection Gradient-Programm, das einen linearen Farbverlauf und eine Transformation verwendet hat, um eine Spiegelung einer Textzeichenfolge nachzuahmen:

Spiegelungsverlauf

Die Seite "Verschwommene Spiegelung " fügt diesem Code eine einzelne Anweisung hinzu:

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);
        }
    }
}

Die neue Anweisung fügt einen Weichzeichnerfilter für den reflektierten Text hinzu, der auf der Textgröße basiert:

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

Dieser Weichzeichnerfilter bewirkt, dass die Reflexion viel realistischer erscheint:

Verschwommene Spiegelung