次の方法で共有


SkiaSharp マスク フィルター

マスク フィルターは、グラフィカル オブジェクトのジオメトリとアルファ チャネルを操作する効果です。 マスク フィルターを使用するには、SKMaskFilter 静的メソッドのいずれかを呼び出して作成した、種類が SKMaskFilter のオブジェクトに SKPaintMaskFilter プロパティを設定します。

マスク フィルターについてよく理解するための最善の方法は、これらの静的メソッドを試すことです。 最も便利なマスク フィルターは、ぼかしを作成するものです。

ぼかしの例

この記事で説明するマスク フィルター機能はそれだけです。 SkiaSharp 画像フィルターに関する次の記事では、この効果よりも好ましい場合があるぼかし効果についても説明します。

静的メソッド SKMaskFilter.CreateBlur の構文は次のとおりです。

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

オーバーロードを使用すると、ぼかしの作成に使用するアルゴリズムのフラグと、他のグラフィカル オブジェクトで覆われる領域のぼかしを回避する四角形を指定できます。

SKBlurStyle は、次のメンバーを持つ列挙体です。

  • Normal
  • Solid
  • Outer
  • Inner

これらのスタイルの効果を次の例に示します。 sigma パラメーターは、ぼかしの範囲を指定します。 以前のバージョンの Skia では、ぼかしの範囲は半径の値で示されていました。 アプリケーションに半径の値が適している場合は、静的メソッド SKMaskFilter.ConvertRadiusToSigma を使用して、あるものを他のものに変換できます。 このメソッドは、半径に 0.57735 を乗算し、0.5 を加算します。

サンプルの [Mask Blur Experiment] ページでは、ぼかしスタイルとシグマ値を試すことができます。 XAML ファイルは、4 つの Picker 列挙メンバーと、シグマ値を指定するための SKBlurStyle を使用して、Slider をインスタンス化します。

<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 オブジェクトを作成し、それを SKPaint オブジェクトの MaskFilter プロパティに設定します。 この SKPaint オブジェクトは、テキスト文字列とビットマップの両方を描画するために使用されます。

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

ぼかしのスタイル Normal と増加する sigma レベルを使用した、iOS、Android、ユニバーサル Windows プラットフォーム (UWP) で実行されているプログラムを次に示します。

マスクぼかし実験 - 標準

ビットマップの端のみがぼかしの影響を受けることがわかります。 SKMaskFilter クラスは、ビットマップ イメージ全体をぼかす場合に使用する正しい効果ではありません。 そのため、SkiaSharp 画像フィルターに関する次の記事で説明するように、SKImageFilter クラスを使用します。

sigma 引数の値を増やすと、テキストのぼかしが増えます。 このプログラムを使用した実験では、特定の sigma 値について、Windows 10 デスクトップでは、ぼかしがより極端であることがわかります。 この違いは、デスクトップ モニターではモバイル デバイスよりもピクセル密度が低いため、テキストの高さがピクセル単位で低くなるために発生します。 sigma 値はピクセル単位のぼかし範囲に比例するため、特定の sigma 値について、解像度の低いディスプレイでは効果がより極端になります。 実稼働アプリケーションでは、グラフィックのサイズに比例する sigma 値を計算することが必要になる場合があります。

アプリケーションに最適なぼかしレベルを決定する前に、いくつかの値を試してください。 たとえば、[Mask Blur Experiment] ページで、sigma を次のように設定してみてください。

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

現在は Slider の効果はありませんが、ぼかしの程度はプラットフォーム間で一貫しています。

マスクぼかし実験 - 一致

ここまでのすべてのスクリーンショットでは、SKBlurStyle.Normal 列挙メンバーで作成されたぼかしが示されています。 次のスクリーンショットは、SolidOuterInner のぼかしスタイルの効果を示しています。

マスクぼかし実験

iOS のスクリーンショットは Solid スタイルを示しています。テキスト文字は黒の実線ストロークのままであり、ぼかしはこれらのテキスト文字の外側に追加されます。

中央の Android のスクリーンショットは、Outer スタイルを示しています。文字ストローク自体は (ビットマップと同様に) 削除され、ぼかしはテキスト文字が表示されていた空のスペースを囲んでいます。

右側の UWP のスクリーンショットは、Inner スタイルを示しています。 ぼかしは、テキスト文字によって通常占有される領域に制限されます。

SkiaSharp 線形グラデーションに関する記事では、線形グラデーションと変換を使用してテキスト文字列のリフレクションを模倣するリフレクション グラデーション プログラムについて説明しています。

反射グラデーション

[Blurry Reflection] ページでは、そのコードに 1 つのステートメントを追加されます。

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

新しいステートメントは、テキスト サイズに基づいて、反射したテキストのぼかしフィルターを追加します。

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

このぼかしフィルターを使用すると、反射がより現実的に見えます。

ぼやけた反射