경로 및 지역 클리핑Clipping with Paths and Regions

샘플 다운로드 샘플 다운로드Download Sample Download the sample

클립 그래픽에 대 한 경로 사용 하 여 특정 영역을 영역을 만드는 데Use paths to clip graphics to specific areas, and to create regions

특정 영역에 대 한 그래픽 렌더링을 제한 하는 데 필요한 경우가 있습니다.It's sometimes necessary to restrict the rendering of graphics to a particular area. 이 이라고 클리핑합니다.This is known as clipping. 클리핑 구멍을 통해 표시 되는 monkey의이 이미지와 같은 특수 한 효과 대해 사용할 수 있습니다.You can use clipping for special effects, such as this image of a monkey seen through a keyhole:

Keyhole를 통한 원숭이

합니다 클리핑 영역 그래픽 렌더링 되는 화면 영역입니다.The clipping area is the area of the screen in which graphics are rendered. 클리핑 영역 외부에 표시 되는 아무 것도 렌더링 되지 않습니다.Anything that is displayed outside of the clipping area is not rendered. 클리핑 영역을 사각형에 의해 일반적으로 정의 됩니다 요소나 SKPath 수 있지만 개체를 정의할 수 있습니다 또는 사용 하 여 클리핑 영역을 SKRegion 개체.The clipping area is usually defined by a rectangle or an SKPath object, but you can alternatively define a clipping area using an SKRegion object. 이러한 두 가지 유형의 개체에서 먼저 하므로 것 처럼 보일 관련 경로에서 영역을 만들 수 있습니다.These two types of objects at first seem related because you can create a region from a path. 그러나 지역에서 경로를 만들 수 없으며 내부적으로는 서로 다른 위치에 있습니다. 경로는 일련의 선 및 곡선으로 구성 되 고, 영역은 일련의 수평 스캔 선으로 정의 됩니다.However, you cannot create a path from a region, and they are very different internally: A path comprises a series of lines and curves, while a region is defined by a series of horizontal scan lines.

위의 이미지에서 만든 합니다 구멍 통해 Monkey 페이지입니다.The image above was created by the Monkey through Keyhole page. 합니다 MonkeyThroughKeyholePage 클래스 SVG 데이터를 사용 하 여 경로 정의 하 고 프로그램 리소스에서 비트맵을 로드 하는 생성자를 사용 합니다.The MonkeyThroughKeyholePage class defines a path using SVG data and uses the constructor to load a bitmap from program resources:

public class MonkeyThroughKeyholePage : ContentPage
{
    SKBitmap bitmap;
    SKPath keyholePath = SKPath.ParseSvgPathData(
        "M 300 130 L 250 350 L 450 350 L 400 130 A 70 70 0 1 0 300 130 Z");

    public MonkeyThroughKeyholePage()
    {
        Title = "Monkey through Keyhole";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;

        string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
        Assembly assembly = GetType().GetTypeInfo().Assembly;

        using (Stream stream = assembly.GetManifestResourceStream(resourceID))
        {
            bitmap = SKBitmap.Decode(stream);
        }
    }
    ...
}

하지만 keyholePath 는 구멍의 개요를 설명 하는 개체, 좌표를 완전히 임의적 이며 경로 데이터 고안 된 경우 무엇 이었습니까 편리 하 게 반영 합니다.Although the keyholePath object describes the outline of a keyhole, the coordinates are completely arbitrary and reflect what was convenient when the path data was devised. 이러한 이유로 합니다 PaintSurface 처리기는이 경로 호출의 범위를 가져옵니다 TranslateScale 화면 가운데에 경로 이동 하 고 거의 화면으로 길게 설정:For this reason, the PaintSurface handler obtains the bounds of this path and calls Translate and Scale to move the path to the center of the screen and to make it nearly as tall as the screen:

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

        canvas.Clear();

        // Set transform to center and enlarge clip path to window height
        SKRect bounds;
        keyholePath.GetTightBounds(out bounds);

        canvas.Translate(info.Width / 2, info.Height / 2);
        canvas.Scale(0.98f * info.Height / bounds.Height);
        canvas.Translate(-bounds.MidX, -bounds.MidY);

        // Set the clip path
        canvas.ClipPath(keyholePath);

        // Reset transforms
        canvas.ResetMatrix();

        // Display monkey to fill height of window but maintain aspect ratio
        canvas.DrawBitmap(bitmap,
            new SKRect((info.Width - info.Height) / 2, 0,
                       (info.Width + info.Height) / 2, info.Height));
    }
}

하지만 경로 렌더링 되지 않습니다.But the path is not rendered. 대신, 변환, 다음 경로이 문 사용 하 여 클리핑 영역을 설정 하려면:Instead, following the transforms, the path is used to set a clipping area with this statement:

canvas.ClipPath(keyholePath);

합니다 PaintSurface 처리기에 다시 호출 하 여 변환 ResetMatrix 화면의 전체 높이를 확장 하도록 비트맵을 그립니다.The PaintSurface handler then resets the transforms with a call to ResetMatrix and draws the bitmap to extend to the full height of the screen. 이 코드 가정 비트맵 정사각형이 비트맵 인 합니다.This code assumes that the bitmap is square, which this particular bitmap is. 클리핑 경로 의해 정의 되는 영역 내 에서만 비트맵 렌더링 됩니다.The bitmap is rendered only within the area defined by the clipping path:

Keyhole 페이지를 통한 원숭이의 세 번째 스크린샷Triple screenshot of the Monkey through Keyhole page

클리핑 패스가 적용 변환을 적용 시기를 ClipPath 메서드를 호출 하 고 변환에 적용 하면 그래픽 개체 (예: 비트맵)이 표시 되지 않습니다.The clipping path is subject to the transforms in effect when the ClipPath method is called, and not to the transforms in effect when a graphical object (such as a bitmap) is displayed. 클리핑 패스를 사용 하 여 저장 되는 캔버스 상태의 일부인 합니다 Save 메서드 사용 하 여 복원는 Restore 메서드.The clipping path is part of the canvas state that is saved with the Save method and restored with the Restore method.

클리핑 패스 결합Combining Clipping Paths

엄격히 말해, 클리핑 영역 설정 되지 않습니다""는 ClipPath 메서드.Strictly speaking, the clipping area is not "set" by the ClipPath method. 대신, 캔버스 크기가 같은 사각형으로 시작 하는 기존 클리핑 패스를 함께 사용 됩니다.Instead, it is combined with the existing clipping path, which begins as a rectangle equal in size to the canvas. 사용 하 여 클리핑 영역의 사각형 범위를 가져올 수 있습니다 합니다 ClipBounds 속성 또는 ClipDeviceBounds 속성입니다.You can obtain the rectangular bounds of the clipping area using the ClipBounds property or the ClipDeviceBounds property. 합니다 ClipBounds 속성이 반환을 SKRect 반영 하는 모든 변환 하는 값이 적용 되는 합니다.The ClipBounds property returns an SKRect value that reflects any transforms that might be in effect. ClipDeviceBounds 속성에서 반환 된 RectI 값입니다.The ClipDeviceBounds property returns a RectI value. 정수 치수를 사용 하 여 사각형 이며 실제 픽셀 크기의 클리핑 영역을 설명 합니다.This is a rectangle with integer dimensions, and describes the clipping area in actual pixel dimensions.

호출 하 여 ClipPath 새 영역을 사용 하 여 클리핑 영역을 결합 하 여 클리핑 영역을 축소 합니다.Any call to ClipPath reduces the clipping area by combining the clipping area with a new area. 전체 구문은 합니다 ClipPath 메서드는:The full syntax of the ClipPath method is:

public void ClipPath(SKPath path, SKClipOperation operation = SKClipOperation.Intersect, Boolean antialias = false);

이기도 한 ClipRect 사각형을 사용 하 여 클리핑 영역을 결합 하는 메서드:There is also a ClipRect method that combines the clipping area with a rectangle:

public Void ClipRect(SKRect rect, SKClipOperation operation = SKClipOperation.Intersect, Boolean antialias = false);

기본적으로 결과 클리핑 영역은 기존 클리핑 영역의 교집합 및 SKPath 또는 SKRect 에 지정 된 된 ClipPath 또는 ClipRect 메서드.By default, the resultant clipping area is an intersection of the existing clipping area and the SKPath or SKRect that is specified in the ClipPath or ClipRect method. 에 설명 되어이 원 네 개의 교차 클립 페이지입니다.This is demonstrated in the Four Circles Intersect Clip page. PaintSurface 처리기에는 FourCircleInteresectClipPage 클래스를 다시 사용 된 동일한 SKPath 개체는 각 연속 호출을 통해 클리핑 영역을 축소 하는 4 개의 겹치는 원 만들려면 ClipPath:The PaintSurface handler in the FourCircleInteresectClipPage class reuses the same SKPath object to create four overlapping circles, each of which reduces the clipping area through successive calls to ClipPath:

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

    canvas.Clear();

    float size = Math.Min(info.Width, info.Height);
    float radius = 0.4f * size;
    float offset = size / 2 - radius;

    // Translate to center
    canvas.Translate(info.Width / 2, info.Height / 2);

    using (SKPath path = new SKPath())
    {
        path.AddCircle(-offset, -offset, radius);
        canvas.ClipPath(path, SKClipOperation.Intersect);

        path.Reset();
        path.AddCircle(-offset, offset, radius);
        canvas.ClipPath(path, SKClipOperation.Intersect);

        path.Reset();
        path.AddCircle(offset, -offset, radius);
        canvas.ClipPath(path, SKClipOperation.Intersect);

        path.Reset();
        path.AddCircle(offset, offset, radius);
        canvas.ClipPath(path, SKClipOperation.Intersect);

        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Fill;
            paint.Color = SKColors.Blue;
            canvas.DrawPaint(paint);
        }
    }
}

남은 이러한 4 개의 원의 교집합입니다.What's left is the intersection of these four circles:

네 개의 원형 교차 클립 페이지의 삼중 스크린샷Triple screenshot of the Four Circle Intersect Clip page

합니다 SKClipOperation 열거형에는 두 명의 멤버:The SKClipOperation enumeration has only two members:

  • Difference 기존 클리핑 영역에서 지정 된 경로 또는 사각형을 제거합니다.Difference removes the specified path or rectangle from the existing clipping area

  • Intersect 지정 된 경로 또는 기존 클리핑 영역을 사용 하 여 사각형을 교차Intersect intersects the specified path or rectangle with the existing clipping area

4를 대체 하는 경우 SKClipOperation.Intersect 인수에는 FourCircleIntersectClipPage 클래스 SKClipOperation.Difference, 다음과 같이 표시 됩니다.If you replace the four SKClipOperation.Intersect arguments in the FourCircleIntersectClipPage class with SKClipOperation.Difference, you'll see the following:

차이 작업을 포함 하는 네 개의 원 교차 클립 페이지의 3 차 스크린샷Triple screenshot of the Four Circle Intersect Clip page with difference operation

4 개의 겹치는 원 클리핑 영역에서 제거 되었습니다.Four overlapping circles have been removed from the clipping area.

합니다 클립 작업 페이지 원 쌍만을 사용 하 여 이러한 두 작업 간의 차이점을 보여 줍니다.The Clip Operations page illustrates the difference between these two operations with just a pair of circles. 왼쪽의 첫 번째 원 기본 클립 작업을 사용 하 여 클리핑 영역에 추가 됩니다 Intersect반면 두 번째 원의 오른쪽 텍스트 레이블에 의해 표시 된 클립 작업을 사용 하 여 클리핑 영역에 추가 됩니다.The first circle on the left is added to the clipping area with the default clip operation of Intersect, while the second circle on the right is added to the clipping area with the clip operation indicated by the text label:

클립 작업 페이지의 세 번째 스크린샷Triple screenshot of the Clip Operations page

ClipOperationsPage 클래스를 정의 두 SKPaint 필드로, 개체 및 다음 두 개의 사각형 영역으로 화면을 나눕니다.The ClipOperationsPage class defines two SKPaint objects as fields, and then divides the screen up into two rectangular areas. 이러한 영역은 가로 또는 세로 모드로 휴대폰 인지에 따라 다릅니다.These areas are different depending on whether the phone is in portrait or landscape mode. 합니다 DisplayClipOp 클래스에는 다음 텍스트와 호출 표시 ClipPath 각 클립 작업을 설명 하기 위해 두 개의 원 경로 사용 하 여:The DisplayClipOp class then displays the text and calls ClipPath with the two circle paths to illustrate each clip operation:

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

    canvas.Clear();

    float x = 0;
    float y = 0;

    foreach (SKClipOperation clipOp in Enum.GetValues(typeof(SKClipOperation)))
    {
        // Portrait mode
        if (info.Height > info.Width)
        {
            DisplayClipOp(canvas, new SKRect(x, y, x + info.Width, y + info.Height / 2), clipOp);
            y += info.Height / 2;
        }
        // Landscape mode
        else
        {
            DisplayClipOp(canvas, new SKRect(x, y, x + info.Width / 2, y + info.Height), clipOp);
            x += info.Width / 2;
        }
    }
}

void DisplayClipOp(SKCanvas canvas, SKRect rect, SKClipOperation clipOp)
{
    float textSize = textPaint.TextSize;
    canvas.DrawText(clipOp.ToString(), rect.MidX, rect.Top + textSize, textPaint);
    rect.Top += textSize;

    float radius = 0.9f * Math.Min(rect.Width / 3, rect.Height / 2);
    float xCenter = rect.MidX;
    float yCenter = rect.MidY;

    canvas.Save();

    using (SKPath path1 = new SKPath())
    {
        path1.AddCircle(xCenter - radius / 2, yCenter, radius);
        canvas.ClipPath(path1);

        using (SKPath path2 = new SKPath())
        {
            path2.AddCircle(xCenter + radius / 2, yCenter, radius);
            canvas.ClipPath(path2, clipOp);

            canvas.DrawPaint(fillPaint);
        }
    }

    canvas.Restore();
}

호출 DrawPaint 일반적으로 채울 전체 캔버스를 하면 SKPaint 개체 하지만 경우 메서드가 방금 그리는 클리핑 영역 내에서.Calling DrawPaint normally causes the entire canvas to be filled with that SKPaint object, but in this case, the method just paints within the clipping area.

지역 살펴보기Exploring Regions

클리핑 영역을 정의할 수도 있습니다는 SKRegion 개체입니다.You can also define a clipping area in terms of an SKRegion object.

새로 만든 SKRegion 빈 영역을 설명 하는 개체입니다.A newly created SKRegion object describes an empty area. 일반적으로 개체의 첫 번째 호출은 SetRect 는 지역에 있는 사각형 영역에 설명 합니다.Usually the first call on the object is SetRect so that the region describes a rectangular area. 매개 변수를 SetRectSKRectI 값 — 픽셀 측면에서 사각형을 지정 하기 때문에 정수를 사용 하 여 사각형을 조정 합니다.The parameter to SetRect is an SKRectI value — a rectangle with integer coordinates because it specifies the rectangle in terms of pixels. 호출할 수 있습니다 SetPath 사용 하 여는 SKPath 개체입니다.You can then call SetPath with an SKPath object. 이 경로의 내부와 동일 하지만 잘린 초기 사각형 영역의 영역을 만듭니다.This creates a region that is the same as the interior of the path, but clipped to the initial rectangular region.

지역 중 하나를 호출 하 여 수정할 수도 있습니다는 Op 이 0.09716216215와 같은 메서드 오버 로드 합니다.The region can also be modified by calling one of the Op method overloads, such as this one:

public Boolean Op(SKRegion region, SKRegionOperation op)

합니다 SKRegionOperation 열거형은 유사한 SKClipOperation 더 많은 멤버가 있지만:The SKRegionOperation enumeration is similar to SKClipOperation but it has more members:

  • Difference

  • Intersect

  • Union

  • XOR

  • ReverseDifference

  • Replace

수행 하면 해당 지역 합니다 Op 에 따라 매개 변수로 지정 된 지역에 대 한 호출이 함께 SKRegionOperation 멤버입니다.The region that you're making the Op call on is combined with the region specified as a parameter based on the SKRegionOperation member. 마지막으로 가져올 때 지역 클리핑에 대 한 적합 한, 사용 하 여 캔버스 클리핑 영역으로 설정할 수 있습니다 합니다 ClipRegion 메서드의 SKCanvas:When you finally get a region suitable for clipping, you can set that as the clipping area of the canvas using the ClipRegion method of SKCanvas:

public void ClipRegion(SKRegion region, SKClipOperation operation = SKClipOperation.Intersect)

다음 스크린샷은 6 개 지역 작업을 기반으로 하는 클리핑 영역을 보여 줍니다.The following screenshot shows clipping areas based on the six region operations. 왼쪽된 원을 지역은 합니다 Op 메서드가 호출 되 고 오른쪽 원이 전달할 지역은 Op 메서드:The left circle is the region that the Op method is called on, and the right circle is the region passed to the Op method:

영역 작업 페이지의 세 번째 스크린샷Triple screenshot of the Region Operations page

이러한 모든 가능성 결합 하는 이러한 두 개의 원을?합니다Are these all the possibilities of combining these two circles? 결과 이미지 자체에 표시 되는 세 가지 구성 요소 조합으로 고려해 야 합니다 Difference, Intersect, 및 ReverseDifference 작업.Consider the resultant image as a combination of three components, which by themselves are seen in the Difference, Intersect, and ReverseDifference operations. 조합 총 번호가을 세 제곱 2 개 또는 8입니다.The total number of combinations is two to the third power, or eight. 누락 된 두 가지를 원래 지역 (에서 호출 하지 않으면 결과 Op 전혀) 및 완전히 빈 영역을 합니다.The two that are missing are the original region (which results from not calling Op at all) and an entirely empty region.

하기가 어렵다는 문제가 먼저 경로 및 지역 해당 경로에서 만들고 그런 다음 여러 영역을 결합 해야 하기 때문에 클리핑에 대 한 영역을 사용 합니다.It's harder to use regions for clipping because you need to first create a path, and then a region from that path, and then combine multiple regions. 전체 구조를 영역 작업 페이지는 매우 비슷합니다 클립 Operations 되지만 RegionOperationsPage 클래스 6 개의 영역으로 화면을 분할 및 이 작업에 대 한 영역을 사용 하는 데 필요한 추가 작업을 보여 줍니다.The overall structure of the Region Operations page is very similar to Clip Operations but the RegionOperationsPage class divides the screen up into six areas and shows the extra work required to use regions for this job:

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

    canvas.Clear();

    float x = 0;
    float y = 0;
    float width = info.Height > info.Width ? info.Width / 2 : info.Width / 3;
    float height = info.Height > info.Width ? info.Height / 3 : info.Height / 2;

    foreach (SKRegionOperation regionOp in Enum.GetValues(typeof(SKRegionOperation)))
    {
        DisplayClipOp(canvas, new SKRect(x, y, x + width, y + height), regionOp);

        if ((x += width) >= info.Width)
        {
            x = 0;
            y += height;
        }
    }
}

void DisplayClipOp(SKCanvas canvas, SKRect rect, SKRegionOperation regionOp)
{
    float textSize = textPaint.TextSize;
    canvas.DrawText(regionOp.ToString(), rect.MidX, rect.Top + textSize, textPaint);
    rect.Top += textSize;

    float radius = 0.9f * Math.Min(rect.Width / 3, rect.Height / 2);
    float xCenter = rect.MidX;
    float yCenter = rect.MidY;

    SKRectI recti = new SKRectI((int)rect.Left, (int)rect.Top,
                                (int)rect.Right, (int)rect.Bottom);

    using (SKRegion wholeRectRegion = new SKRegion())
    {
        wholeRectRegion.SetRect(recti);

        using (SKRegion region1 = new SKRegion(wholeRectRegion))
        using (SKRegion region2 = new SKRegion(wholeRectRegion))
        {
            using (SKPath path1 = new SKPath())
            {
                path1.AddCircle(xCenter - radius / 2, yCenter, radius);
                region1.SetPath(path1);
            }

            using (SKPath path2 = new SKPath())
            {
                path2.AddCircle(xCenter + radius / 2, yCenter, radius);
                region2.SetPath(path2);
            }

            region1.Op(region2, regionOp);

            canvas.Save();
            canvas.ClipRegion(region1);
            canvas.DrawPaint(fillPaint);
            canvas.Restore();
        }
    }
}

다음 사이 큰 차이가는 ClipPath 메서드 및 ClipRegion 메서드:Here's a big difference between the ClipPath method and the ClipRegion method:

중요

달리 합니다 ClipPath 메서드는 ClipRegion 메서드 변환의 영향을 받지 않습니다.Unlike the ClipPath method, the ClipRegion method is not affected by transforms.

이러한 차이 대 한 근거를 이해 하려면 이해 하면 도움이 됩니다 어떤 지역이 있습니다.To understand the rationale for this difference, it's helpful to understand what a region is. 클립 작업 또는 지역 작업 수 구현 방법을 내부적으로 하는 방법에 대 한 고려 하는 경우 아마도 것이 매우 복잡 합니다.If you've thought about how the clip operations or region operations might be implemented internally, it probably seems very complicated. 여러 잠재적으로 매우 복잡 한 경로 결합 및 결과 경로의 윤곽선을 알고리즘 악몽 될 수입니다.Several potentially very complex paths are being combined, and the outline of the resultant path is likely an algorithmic nightmare.

이 작업은 각 경로 가로 검색, 여러 줄 구식 진공 tube Tv의에서 함수와 같이 축소 된 경우 상당히 간소화 됩니다.This job is simplified considerably if each path is reduced to a series of horizontal scan lines, such as those in old-fashioned vacuum tube TVs. 각 스캐닝선은 시작점 및 끝점을 사용 하 여 가로줄 하기만 하면 됩니다.Each scan line is simply a horizontal line with a start point and an end point. 예를 들어 10 픽셀의 radius 사용 하 여 원은 원의 왼쪽된 부분에서 시작 하 고 오른쪽 부분에서 끝납니다 각각 20 가로 검색 선으로 분해할 수 있습니다.For example, a circle with a radius of 10 pixels can be decomposed into 20 horizontal scan lines, each of which starts at the left part of the circle and ends at the right part. 영역 작업을 사용 하 여 두 개의 원을 결합 됩니다 해당 스캐닝선의 각 쌍의 시작 및 끝 좌표를 검사 하는 단순히 이기 때문에 매우 간단 합니다.Combining two circles with any region operation becomes very simple because it's simply a matter of examining the start and end coordinates of each pair of corresponding scan lines.

지역은 다음과 같습니다. 영역을 정의 하는 일련의 수평 스캔 선입니다.This is what a region is: A series of horizontal scan lines that define an area.

그러나 일련의 검색 영역 축소 된 경우 줄 줄 특정 픽셀 크기를 기반으로 이러한 검색 합니다.However, when an area is reduced to a series of scan lines, these scan lines are based on a particular pixel dimension. 엄격히 말해서, 지역 벡터 그래픽 개체가 아닙니다.Strictly speaking, the region is not a vector graphics object. 경로 보다 압축 된 흑백 비트맵에 본질적으로 더 가까운 것입니다.It is closer in nature to a compressed monochrome bitmap than to a path. 따라서 지역 크기를 조정 하거나 회전 클리핑 영역에 사용 되는 경우 변환 되지 않습니다이 따라서 한 충실도 유지 하면서 수 없습니다.Consequently, regions cannot be scaled or rotated without losing fidelity, and for this reason they are not transformed when used for clipping areas.

그러나 그리기 위해 지역에 변환을 적용할 수 있습니다.However, you can apply transforms to regions for painting purposes. 합니다 지역 그리기 프로그램 뛰어난 영역의 내부 특성을 보여 줍니다.The Region Paint program vividly demonstrates the inner nature of regions. RegionPaintPage 클래스를 만듭니다는 SKRegion 기준으로 개체를 SKPath 10 단위 radius 원입니다.The RegionPaintPage class creates an SKRegion object based on an SKPath of a 10-unit radius circle. 변환에는 다음 페이지를 채우기에 원을 확장 합니다.A transform then expands that circle to fill the page:

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

    canvas.Clear();

    int radius = 10;

    // Create circular path
    using (SKPath circlePath = new SKPath())
    {
        circlePath.AddCircle(0, 0, radius);

        // Create circular region
        using (SKRegion circleRegion = new SKRegion())
        {
            circleRegion.SetRect(new SKRectI(-radius, -radius, radius, radius));
            circleRegion.SetPath(circlePath);

            // Set transform to move it to center and scale up
            canvas.Translate(info.Width / 2, info.Height / 2);
            canvas.Scale(Math.Min(info.Width / 2, info.Height / 2) / radius);

            // Fill region
            using (SKPaint fillPaint = new SKPaint())
            {
                fillPaint.Style = SKPaintStyle.Fill;
                fillPaint.Color = SKColors.Orange;

                canvas.DrawRegion(circleRegion, fillPaint);
            }

            // Stroke path for comparison
            using (SKPaint strokePaint = new SKPaint())
            {
                strokePaint.Style = SKPaintStyle.Stroke;
                strokePaint.Color = SKColors.Blue;
                strokePaint.StrokeWidth = 0.1f;

                canvas.DrawPath(circlePath, strokePaint);
            }
        }
    }
}

합니다 DrawRegion 호출 주황색 영역을 채우는 동안는 DrawPath 호출 원래 경로 비교에 대 한 파란색 선:The DrawRegion call fills the region in orange, while the DrawPath call strokes the original path in blue for comparison:

영역 페인트 페이지의 삼중 스크린샷Triple screenshot of the Region Paint page

지역은 일련의 개별 좌표 명확 하 게 합니다.The region is clearly a series of discrete coordinates.

변형을 사용 하 여 클리핑 영역와 관련 하 여 필요 하지 않으면,으로 사용할 수 있습니다 지역 클리핑에 대 한 합니다 네-잎 클로버 페이지를 보여 줍니다.If you don't need to use transforms in connection with your clipping areas, you can use regions for clipping, as the Four-Leaf Clover page demonstrates. 합니다 FourLeafCloverPage 클래스 순환 네 개 지역에서 복합 영역 생성 복합 지역 클리핑 영역으로 설정 하 고 다음 일련의 페이지는 페이지의 가운데에서 360 직선을 그립니다.The FourLeafCloverPage class constructs a composite region from four circular regions, sets that composite region as the clipping area, and then draws a series of 360 straight lines emanating from the center of the page:

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

    canvas.Clear();

    float xCenter = info.Width / 2;
    float yCenter = info.Height / 2;
    float radius = 0.24f * Math.Min(info.Width, info.Height);

    using (SKRegion wholeScreenRegion = new SKRegion())
    {
        wholeScreenRegion.SetRect(new SKRectI(0, 0, info.Width, info.Height));

        using (SKRegion leftRegion = new SKRegion(wholeScreenRegion))
        using (SKRegion rightRegion = new SKRegion(wholeScreenRegion))
        using (SKRegion topRegion = new SKRegion(wholeScreenRegion))
        using (SKRegion bottomRegion = new SKRegion(wholeScreenRegion))
        {
            using (SKPath circlePath = new SKPath())
            {
                // Make basic circle path
                circlePath.AddCircle(xCenter, yCenter, radius);

                // Left leaf
                circlePath.Transform(SKMatrix.MakeTranslation(-radius, 0));
                leftRegion.SetPath(circlePath);

                // Right leaf
                circlePath.Transform(SKMatrix.MakeTranslation(2 * radius, 0));
                rightRegion.SetPath(circlePath);

                // Make union of right with left
                leftRegion.Op(rightRegion, SKRegionOperation.Union);

                // Top leaf
                circlePath.Transform(SKMatrix.MakeTranslation(-radius, -radius));
                topRegion.SetPath(circlePath);

                // Combine with bottom leaf
                circlePath.Transform(SKMatrix.MakeTranslation(0, 2 * radius));
                bottomRegion.SetPath(circlePath);

                // Make union of top with bottom
                bottomRegion.Op(topRegion, SKRegionOperation.Union);

                // Exclusive-OR left and right with top and bottom
                leftRegion.Op(bottomRegion, SKRegionOperation.XOR);

                // Set that as clip region
                canvas.ClipRegion(leftRegion);

                // Set transform for drawing lines from center
                canvas.Translate(xCenter, yCenter);

                // Draw 360 lines
                for (double angle = 0; angle < 360; angle++)
                {
                    float x = 2 * radius * (float)Math.Cos(Math.PI * angle / 180);
                    float y = 2 * radius * (float)Math.Sin(Math.PI * angle / 180);

                    using (SKPaint strokePaint = new SKPaint())
                    {
                        strokePaint.Color = SKColors.Green;
                        strokePaint.StrokeWidth = 2;

                        canvas.DrawLine(0, 0, x, y, strokePaint);
                    }
                }
            }
        }
    }
}

네-잎 클로버 처럼 실제로 표시 되지 않습니다 이지만 하드 클리핑 없이 렌더링 될 수 있는 이미지:It doesn't really look like a four-leaf clover, but it's an image that might otherwise be hard to render without clipping:

네 리프 클로버 페이지의 삼중 스크린샷Triple screenshot of the Four-Leaf Clover page