SkiaSharp 마스크 필터

Download Sample 샘플 다운로드

마스크 필터는 그래픽 개체의 기하 도형 및 알파 채널을 조작하는 효과입니다. 마스크 필터를 사용하려면 정적 메서드 중 하나를 SKMaskFilter 호출하여 만든 형식 SKMaskFilter 의 개체로 속성을 SKPaint 설정합니다MaskFilter.

마스크 필터에 익숙해지는 가장 좋은 방법은 이러한 정적 메서드를 실험하는 것입니다. 가장 유용한 마스크 필터는 흐림 효과를 만듭니다.

Blur Example

이 문서에서 설명하는 유일한 마스크 필터 기능입니다. SkiaSharp 이미지 필터에 대한 다음 문서에서는 이 필터에 선호할 수 있는 흐림 효과도 설명합니다.

정적 SKMaskFilter.CreateBlur 메서드의 구문은 다음과 같습니다.

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

오버로드를 사용하면 흐림 효과를 만드는 데 사용되는 알고리즘에 대한 플래그를 지정하고 사각형은 다른 그래픽 개체로 덮일 영역에서 흐리게 표시되지 않도록 할 수 있습니다.

SKBlurStyle 는 다음 멤버를 사용하는 열거형입니다.

  • Normal
  • Solid
  • Outer
  • Inner

이러한 스타일의 효과는 아래 예제에 나와 있습니다. 매개 변수는 sigma 흐림 효과의 범위를 지정합니다. 이전 버전의 Skia에서는 흐림 효과의 범위가 반지름 값으로 표시되었습니다. 애플리케이션에 반경 값이 바람직한 경우 한 쪽에서 다른 값으로 변환할 수 있는 정적 SKMaskFilter.ConvertRadiusToSigma 메서드가 있습니다. 이 메서드는 반지름을 0.57735로 곱하고 0.5를 추가합니다.

SkiaSharpFormsDemos 샘플의 마스크 흐림 실험 페이지에서 흐림 스타일 및 시그마 값을 실험할 수 있습니다. XAML 파일은 4개의 SKBlurStyle 열거형 멤버와 Slider 시그마 값을 지정하는 a를 인스턴스화 Picker 합니다.

<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 설정합니다. 이 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);
        }
    }
}

다음은 iOS, Android 및 UWP(유니버설 Windows 플랫폼)Normal에서 실행되는 프로그램으로, 흐림 스타일과 수준 증가 sigma 가 있습니다.

Mask Blur Experiment - Normal

비트맵의 가장자리만 흐림의 영향을 받습니다. SKMaskFilter 전체 비트맵 이미지를 흐리게 표시하려는 경우 클래스가 사용할 올바른 효과가 아닙니다. 이를 위해 SkiaSharp 이미지 필터에 대한 다음 문서에 설명된 대로 클래스를 사용 SKImageFilter 하려고 합니다.

인수 값이 늘어나면 텍스트가 더 흐리게 표시됩니다 sigma . 이 프로그램을 실험할 때 특정 sigma 값의 경우 흐림이 Windows 10 데스크톱에서 더 극단적이라는 것을 알 수 있습니다. 이 차이는 데스크톱 모니터에서 픽셀 밀도가 모바일 디바이스보다 낮기 때문에 픽셀의 텍스트 높이가 낮기 때문에 발생합니다. 값은 sigma 픽셀 단위의 흐림 효과에 비례하므로 지정된 sigma 값의 경우 낮은 해상도 디스플레이에서 효과가 더 극단적입니다. 프로덕션 애플리케이션에서는 그래픽 크기에 비례하는 값을 계산 sigma 하려고 할 것입니다.

애플리케이션에 가장 적합한 흐림 수준에 정착하기 전에 몇 가지 값을 시도합니다. 예를 들어 마스크 흐림 실험 페이지에서 다음과 같이 설정을 sigma 시도합니다.

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

이제는 Slider 효과가 없지만 흐림 정도는 플랫폼 간에 일치합니다.

Mask Blur Experiment - Consistent

지금까지의 모든 스크린샷은 열거형 멤버를 사용하여 SKBlurStyle.Normal 만든 흐림 효과를 보여 줍니다. 다음 스크린샷은 , OuterInner 흐리게 스타일의 효과를 Solid보여 줍니다.

Mask Blur Experiment

iOS 스크린샷은 스타일을 보여 Solid 줍니다. 텍스트 문자는 여전히 단색 검은색 스트로크로 존재하며 이러한 텍스트 문자의 바깥쪽에 흐림 효과가 추가됩니다.

중간에 있는 Android 스크린샷은 스타일을 보여 Outer 줍니다. 문자 스트로크 자체는 제거되고(비트맵과 마찬가지로) 흐림 효과가 텍스트 문자가 나타난 빈 공간을 둘러쌉니다.

오른쪽의 UWP 스크린샷에는 스타일이 Inner 표시됩니다. 흐림은 일반적으로 텍스트 문자가 차지하는 영역으로 제한됩니다.

SkiaSharp 선형 그라데이션 문서에서는 선형 그라데이션과 변환을 사용하여 텍스트 문자열의 반사를 모방하는 리플렉션 그라데이션 프로그램을 설명했습니다.

Reflection Gradient

흐릿한 리플렉션 페이지는 해당 코드에 단일 문을 추가합니다.

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

이 흐림 필터는 리플렉션을 훨씬 더 사실적으로 보이게 합니다.

Blurry Reflection