선 및 스트로크 단면

Download Sample 샘플 다운로드

SkiaSharp을 사용하여 다른 스트로크 대문자로 선을 그리는 방법 알아보기

SkiaSharp에서 한 줄 렌더링은 일련의 연결된 직선을 렌더링하는 경우와 매우 다릅니다. 그러나 단일 선을 그리는 경우에도 선에 특정 스트로크 너비를 지정해야 하는 경우가 많습니다. 이러한 선이 넓어짐에 따라 선 끝의 모양도 중요해집니다. 선 끝의 모양을 스트로크 캡이라고 합니다.

The three stroke caps options

단일 선을 SKCanvas 그리는 경우 인수가 개체를 사용하여 줄의 시작 및 끝 좌표를 나타내는 간단한 DrawLine 메서드를 SKPaint 정의합니다.

canvas.DrawLine (x0, y0, x1, y1, paint);

기본적으로 StrokeWidth 새로 인스턴스화된 SKPaint 개체의 속성은 0이며, 두께가 1픽셀인 줄을 렌더링할 때 값 1과 같은 효과를 집니다. 휴대폰과 같은 고해상도 디바이스에서는 매우 얇아서 더 큰 값으로 설정할 StrokeWidth 수 있습니다. 그러나 상당한 두께의 선을 그리기 시작하면 또 다른 문제가 발생합니다. 이러한 두꺼운 선의 시작과 끝을 렌더링하려면 어떻게 해야 하나요?

선의 시작과 끝 모양은 선 캡 또는 Skia에서 스트로크 캡이라고 합니다. 이 컨텍스트의 "cap"이라는 단어는 일종의 모자(줄 끝에 있는 것)를 의미합니다. 개체의 StrokeCapSKPaint 속성을 열거형의 SKStrokeCap 다음 멤버 중 하나로 설정합니다.

  • Butt (기본값)
  • Square
  • Round

샘플 프로그램에 가장 잘 설명되어 있습니다. SkiaSharpFormsDemos 프로그램의 SkiaSharp 선 및 경로 섹션은 클래스에 StrokeCapsPage 따라 Stroke Caps라는 페이지로 시작합니다. 이 페이지는 열거형의 세 멤버를 반복하여 열거형 멤버의 SKStrokeCap 이름을 모두 표시하고 해당 스트로크 캡을 사용하여 선을 그리는 이벤트 처리기를 정의 PaintSurface 합니다.

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPaint textPaint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 75,
        TextAlign = SKTextAlign.Center
    };

    SKPaint thickLinePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Orange,
        StrokeWidth = 50
    };

    SKPaint thinLinePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Black,
        StrokeWidth = 2
    };

    float xText = info.Width / 2;
    float xLine1 = 100;
    float xLine2 = info.Width - xLine1;
    float y = textPaint.FontSpacing;

    foreach (SKStrokeCap strokeCap in Enum.GetValues(typeof(SKStrokeCap)))
    {
        // Display text
        canvas.DrawText(strokeCap.ToString(), xText, y, textPaint);
        y += textPaint.FontSpacing;

        // Display thick line
        thickLinePaint.StrokeCap = strokeCap;
        canvas.DrawLine(xLine1, y, xLine2, y, thickLinePaint);

        // Display thin line
        canvas.DrawLine(xLine1, y, xLine2, y, thinLinePaint);
        y += 2 * textPaint.FontSpacing;
    }
}

열거형의 각 멤버에 SKStrokeCap 대해 처리기는 두 개의 선을 그립니다. 하나는 스트로크 두께가 50픽셀이고 다른 선은 2픽셀의 스트로크 두께로 위쪽에 배치됩니다. 이 두 번째 선은 선 두께 및 스트로크 캡과는 별개로 선의 기하학적 시작과 끝을 설명하기 위한 것입니다.

Triple screenshot of the Stroke Caps page

여기에서 볼 수 있듯이 선 Square 과 스트로크 캡은 줄의 시작 부분과 Round 끝에서 스트로크 너비의 절반만큼 줄 길이를 효과적으로 확장합니다. 이 확장은 렌더링된 그래픽 개체의 차원을 확인해야 하는 경우에 중요합니다.

클래스에는 SKCanvas 다소 특이한 여러 선을 그리는 다른 메서드도 포함되어 있습니다.

DrawPoints (SKPointMode mode, points, paint)

매개 변수는 points 값 배열 SKPoint 이며 mode 세 개의 멤버가 SKPointMode 있는 열거형의 멤버입니다.

  • Points 개별 지점을 렌더링하려면
  • Lines 각 지점 쌍을 연결하려면
  • Polygon 연속된 모든 지점을 연결하려면

여러 줄 페이지에서는 이 메서드를 보여 줍니다. MultipleLinesPage.xaml 파일은 열거형의 멤버와 열거형의 SKPointMode 멤버 SKStrokeCap 를 선택할 수 있는 두 개의 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.Paths.MultipleLinesPage"
             Title="Multiple Lines">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Picker x:Name="pointModePicker"
                Title="Point Mode"
                Grid.Row="0"
                Grid.Column="0"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKPointMode}">
                    <x:Static Member="skia:SKPointMode.Points" />
                    <x:Static Member="skia:SKPointMode.Lines" />
                    <x:Static Member="skia:SKPointMode.Polygon" />
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Picker x:Name="strokeCapPicker"
                Title="Stroke Cap"
                Grid.Row="0"
                Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKStrokeCap}">
                    <x:Static Member="skia:SKStrokeCap.Butt" />
                    <x:Static Member="skia:SKStrokeCap.Round" />
                    <x:Static Member="skia:SKStrokeCap.Square" />
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <skiaforms:SKCanvasView x:Name="canvasView"
                                PaintSurface="OnCanvasViewPaintSurface"
                                Grid.Row="1"
                                Grid.Column="0"
                                Grid.ColumnSpan="2" />
    </Grid>
</ContentPage>

스키아샤프 네임스페이스 선언은 네임스페이스가 및 SKStrokeCap 열거형의 SKPointMode 멤버를 참조하는 데 필요하기 때문에 SkiaSharp 약간 다릅니다. SelectedIndexChangedPicker 뷰에 대한 처리기는 개체를 SKCanvasView 무효화합니다.

void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
    if (canvasView != null)
    {
        canvasView.InvalidateSurface();
    }
}

이 처리기는 XAML 파일에서 SKCanvasView 속성 Picker 이 0으로 설정되고 인스턴스화되기 전에 SKCanvasView 발생할 때 SelectedIndex 이벤트 처리기가 먼저 호출되기 때문에 개체의 존재 여부에 대해 검사 합니다.

PaintSurface 처리기는 뷰에서 Picker 다음 두 열거형 값을 가져옵니다.

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    // Create an array of points scattered through the page
    SKPoint[] points = new SKPoint[10];

    for (int i = 0; i < 2; i++)
    {
        float x = (0.1f + 0.8f * i) * info.Width;

        for (int j = 0; j < 5; j++)
        {
            float y = (0.1f + 0.2f * j) * info.Height;
            points[2 * j + i] = new SKPoint(x, y);
        }
    }

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.DarkOrchid,
        StrokeWidth = 50,
        StrokeCap = (SKStrokeCap)strokeCapPicker.SelectedItem
    };

    // Render the points by calling DrawPoints
    SKPointMode pointMode = (SKPointMode)pointModePicker.SelectedItem;
    canvas.DrawPoints(pointMode, points, paint);
}

스크린샷은 다음과 같은 다양한 Picker 선택 항목을 보여 줍니다.

Triple screenshot of the Multiple Lines page

왼쪽의 i전화 열거형 멤버 DrawPoints 가 선 캡 SquareButt 이 있는 경우 배열의 각 점을 SKPoint 사각형으로 렌더링하는 방법을 SKPointMode.Points 보여 줌 선 캡이면 원이 렌더링됩니다 Round.

Android 스크린샷은 .SKPointMode.Lines 이 경우 Round메서드는 DrawPoints 지정된 줄 바꿈을 사용하여 각 값 쌍 SKPoint 사이에 선을 그립니다.

대신 사용하는 SKPointMode.Polygon경우 배열의 연속된 점 사이에 선이 그려지지만 매우 자세히 보면 이러한 선이 연결되지 않은 것을 볼 수 있습니다. 이러한 각 개별 줄은 지정된 줄 바꿈으로 시작되고 끝납니다. 대문자를 Round 선택하면 선이 연결된 것처럼 보일 수 있지만 실제로 연결되지는 않습니다.

선이 연결되어 있는지 여부는 그래픽 경로 작업의 중요한 측면입니다.