Partager via


Filtres de masque SkiaSharp

Les filtres de masque sont des effets qui manipulent la géométrie et le canal alpha des objets graphiques. Pour utiliser un filtre de masque, définissez la MaskFilter propriété sur SKPaint un objet de type SKMaskFilter que vous avez créé en appelant l’une des SKMaskFilter méthodes statiques.

La meilleure façon de se familiariser avec les filtres de masque consiste à expérimenter ces méthodes statiques. Le filtre de masque le plus utile crée un flou :

Exemple de flou

Il s’agit de la seule fonctionnalité de filtre de masque décrite dans cet article. L’article suivant sur les filtres d’images SkiaSharp décrit également un effet flou que vous pouvez préférer à celui-ci.

La méthode statique SKMaskFilter.CreateBlur a la syntaxe suivante :

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

Les surcharges permettent de spécifier des indicateurs pour l’algorithme utilisé pour créer le flou et un rectangle pour éviter le flou dans les zones couvertes par d’autres objets graphiques.

SKBlurStyle est une énumération avec les membres suivants :

  • Normal
  • Solid
  • Outer
  • Inner

Les effets de ces styles sont présentés dans les exemples ci-dessous. Le sigma paramètre spécifie l’étendue du flou. Dans les versions antérieures de Skia, l’étendue du flou a été indiquée avec une valeur de rayon. Si une valeur radius est préférable pour votre application, il existe une méthode statique SKMaskFilter.ConvertRadiusToSigma qui peut passer d’une valeur à l’autre. La méthode multiplie le rayon de 0,57735 et ajoute 0,5.

La page Masquer l’expérience de flou dans l’exemple vous permet d’expérimenter les styles flous et les valeurs sigma. Le fichier XAML instancie un Picker avec les quatre SKBlurStyle membres d’énumération et un Slider pour spécifier la valeur sigma :

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

Le fichier code-behind utilise ces valeurs pour créer un SKMaskFilter objet et le définir sur la MaskFilter propriété d’un SKPaint objet. Cet SKPaint objet est utilisé pour dessiner à la fois une chaîne de texte et une 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);
        }
    }
}

Voici le programme en cours d’exécution sur iOS, Android et le plateforme Windows universelle (UWP) avec le style flou et les Normal niveaux croissants sigma :

Expérience de flou de masque - Normal

Vous remarquerez que seuls les bords de la bitmap sont affectés par le flou. La SKMaskFilter classe n’est pas l’effet correct à utiliser si vous souhaitez flouter une image bitmap entière. Pour cela, vous souhaiterez utiliser la SKImageFilter classe comme décrit dans l’article suivant sur les filtres d’images SkiaSharp.

Le texte est flou davantage avec les valeurs croissantes de l’argument sigma . Dans l’expérience de ce programme, vous remarquerez que pour une valeur particulière sigma , le flou est plus extrême sur le bureau Windows 10. Cette différence se produit parce que la densité de pixels est inférieure sur un moniteur de bureau que sur les appareils mobiles, et par conséquent la hauteur du texte en pixels est inférieure. La sigma valeur est proportionnelle à une étendue floue en pixels. Par conséquent, pour une valeur donnée sigma , l’effet est plus extrême sur les affichages de résolution inférieure. Dans une application de production, vous souhaiterez probablement calculer une sigma valeur proportionnelle à la taille du graphique.

Essayez plusieurs valeurs avant de vous installer sur un niveau flou qui semble le mieux pour votre application. Par exemple, dans la page Flou du masque, essayez de définir sigma comme suit :

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

Maintenant, le Slider degré de flou n’a aucun effet, mais le degré de flou est cohérent entre les plateformes :

Expérience de flou de masque - Cohérence

Toutes les captures d’écran jusqu’à présent ont montré un flou créé avec le membre d’énumération SKBlurStyle.Normal . Les captures d’écran suivantes montrent les effets des Solidstyles , Outeret Inner flou :

Masquer l’expérience floue

La capture d’écran iOS montre le Solid style : les caractères de texte sont toujours présents sous forme de traits noirs solides, et le flou est ajouté à l’extérieur de ces caractères de texte.

La capture d’écran Android au milieu montre le Outer style : les traits de caractères eux-mêmes sont éliminés (comme c’est le bitmap) et le flou entoure l’espace vide où les caractères de texte sont apparus une fois.

La capture d’écran UWP à droite montre le Inner style. Le flou est limité à la zone occupée normalement par les caractères de texte.

L’article de dégradé linéaire SkiaSharp a décrit un programme de dégradé d’Réflexions ion qui a utilisé un dégradé linéaire et une transformation pour imiter une réflexion d’une chaîne de texte :

dégradé d’Réflexions ion

La page Floue Réflexions ion ajoute une instruction unique à ce 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);
        }
    }
}

La nouvelle instruction ajoute un filtre flou pour le texte réfléchi basé sur la taille du texte :

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

Ce filtre flou provoque la réflexion beaucoup plus réaliste :

Flou Réflexions ion