Filtry masky SkiaSharp

Download Sample Stažení ukázky

Filtry masky jsou efekty, které manipulují s geometrií a alfa kanálem grafických objektů. Pokud chcete použít filtr masky, nastavte MaskFilter vlastnost SKPaint na objekt typu SKMaskFilter , který jste vytvořili voláním jedné ze SKMaskFilter statických metod.

Nejlepším způsobem, jak se seznámit s filtry masky, je experimentování s těmito statickými metodami. Nejužitečnější filtr masky vytvoří rozostření:

Blur Example

To je jediná funkce filtru masky popsaná v tomto článku. Další článek o filtrech obrázků SkiaSharp popisuje také rozostření efektu, který byste mohli raději použít.

Statická SKMaskFilter.CreateBlur metoda má následující syntaxi:

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

Přetížení umožňují zadat příznaky pro algoritmus použitý k vytvoření rozostření a obdélník, aby se zabránilo rozostření v oblastech, které budou pokryty jinými grafickými objekty.

SKBlurStyle je výčet s následujícími členy:

  • Normal
  • Solid
  • Outer
  • Inner

Efekty těchto stylů jsou uvedeny v následujících příkladech. Parametr sigma určuje rozsah rozostření. Ve starších verzích Skia byl rozsah rozostření označen hodnotou poloměru. Pokud je hodnota poloměru pro vaši aplikaci vhodnější, existuje statická SKMaskFilter.ConvertRadiusToSigma metoda, která může převést z jedné na druhou. Metoda vynásobí poloměr hodnotou 0,57735 a přičte hodnotu 0,5.

Stránka s rozostřením masky v ukázce SkiaSharpFormsDemos umožňuje experimentovat se styly rozostření a hodnotami sigma. Soubor XAML vytvoří Picker instanci se čtyřmi SKBlurStyle členy výčtu a hodnotou Slider pro určení hodnoty 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>

Soubor kódu používá tyto hodnoty k vytvoření objektu SKMaskFilter a jeho nastavení na MaskFilter vlastnost objektu SKPaint . Tento SKPaint objekt se používá k vykreslení textového řetězce i rastrového obrázku:

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

Tady je program běžící na iOSu, Androidu a Univerzální platforma Windows (UPW) s rozostřením Normal a zvýšením sigma úrovní:

Mask Blur Experiment - Normal

Všimněte si, že rozostření ovlivní jenom okraje rastrového obrázku. Třída SKMaskFilter není správný efekt, který se má použít, pokud chcete rozostřit celý rastrový obrázek. Pro to budete chtít použít SKImageFilter třídu, jak je popsáno v dalším článku o filtrech obrázků SkiaSharp.

Text je rozmazanější s rostoucími hodnotami argumentu sigma . Při experimentování s tímto programem si všimnete, že pro určitou sigma hodnotu je rozostření na stolním počítači s Windows 10 mnohem extrémní. K tomuto rozdílu dochází, protože hustota pixelů je nižší na stolním monitoru než na mobilních zařízeních, a proto je výška textu v pixelech nižší. Hodnota sigma je úměrná rozostření v pixelech, takže pro danou sigma hodnotu je efekt na displejích s nižším rozlišením extrémnější. V produkční aplikaci budete pravděpodobně chtít vypočítat sigma hodnotu, která je úměrná velikosti grafiky.

Zkuste několik hodnot před vyrovnáním na rozostření, která vypadá nejlépe pro vaši aplikaci. Například na stránce s rozostřením masky experimentu zkuste nastavit sigma takto:

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

Slider Nyní nemá žádný vliv, ale stupeň rozostření je konzistentní mezi platformami:

Mask Blur Experiment - Consistent

Všechny snímky obrazovky zatím zobrazovaly rozostření vytvořené pomocí člena výčtu SKBlurStyle.Normal . Následující snímky obrazovky znázorňují efekty Solidstylů , Outera Inner rozostření:

Mask Blur Experiment

Snímek obrazovky iOS ukazuje Solid styl: Textové znaky jsou stále přítomné jako plné černé tahy a rozostření se přidá do vnější části těchto znaků textu.

Snímek obrazovky s Androidem uprostřed zobrazuje Outer styl: Samotné tahy znaků jsou eliminovány (stejně jako rastrový obrázek) a rozostření obklopuje prázdné místo, kde se znaky textu objeví.

Snímek obrazovky UPW na pravé straně zobrazuje Inner styl. Rozostření je omezeno na oblast, která je obvykle obsazena textovými znaky.

Článek o lineárním přechodu SkiaSharp popsal program přechodu Reflexe ion, který použil lineární přechod a transformaci k napodobení odrazu textového řetězce:

Reflection Gradient

Stránka rozmazaného Reflexe ionu přidá do kódu jeden příkaz:

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

Nový příkaz přidá filtr rozostření pro odražený text založený na velikosti textu:

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

Tento filtr rozostření způsobí, že odraz bude mnohem realističtější:

Blurry Reflection