다음을 통해 공유


SkiaSharp 비트맵 표시

SkiaSharp 비트맵의 주제는 SkiaSharp의 비트맵 기본 문서에서 소개되었습니다. 이 문서에서는 비트맵을 로드하는 세 가지 방법과 비트맵을 표시하는 세 가지 방법을 보여 줬습니다. 이 문서에서는 비트맵을 로드하는 기술을 검토하고 메서드 SKCanvas사용에 DrawBitmap 대해 자세히 설명합니다.

샘플 표시

및 메서드는 DrawBitmapLattice SkiaSharp 비트맵의 분할된 표시 문서에서 설명합니다.DrawBitmapNinePatch

이 페이지의 샘플은 샘플 애플리케이션에서 가져옵니다. 해당 애플리케이션의 홈페이지에서 SkiaSharp 비트맵을 선택한 다음, 비트맵 표시 섹션으로 이동합니다.

비트맵 로드

SkiaSharp 애플리케이션에서 사용하는 비트맵은 일반적으로 세 가지 소스 중 하나에서 제공됩니다.

  • 인터넷을 통해
  • 실행 파일에 포함된 리소스에서
  • 사용자의 사진 라이브러리에서

SkiaSharp 애플리케이션에서 새 비트맵을 만든 다음 해당 비트맵을 그리거나 비트맵 비트를 알고리즘적으로 설정할 수도 있습니다. 이러한 기술은 SkiaSharp 비트맵 만들기 및 그리기 및 SkiaSharp 비트맵 픽셀 액세스 문서에서 설명합니다.

비트맵을 로드하는 다음 세 가지 코드 예제에서 클래스는 형식 SKBitmap의 필드를 포함하는 것으로 간주됩니다.

SKBitmap bitmap;

SkiaSharp의 Bitmap Basics 문서에서 설명한 것처럼 인터넷을 통해 비트맵을 로드하는 가장 좋은 방법은 클래스를 HttpClient 사용하는 것입니다. 클래스의 단일 인스턴스를 필드로 정의할 수 있습니다.

HttpClient httpClient = new HttpClient();

iOS 및 Android 애플리케이션을 사용하는 HttpClient 경우 TLS(전송 계층 보안) 1.2문서에 설명된 대로 프로젝트 속성을 설정하려고 합니다.

자주 사용하는 HttpClient 코드에는 연산자가 await 포함되므로 메서드에 async 상주해야 합니다.

try
{
    using (Stream stream = await httpClient.GetStreamAsync("https:// ··· "))
    using (MemoryStream memStream = new MemoryStream())
    {
        await stream.CopyToAsync(memStream);
        memStream.Seek(0, SeekOrigin.Begin);

        bitmap = SKBitmap.Decode(memStream);
        ···
    };
}
catch
{
    ···
}

가져온 GetStreamAsync 개체가 Stream 에 복사됩니다MemoryStream. Android는 비동기 메서드를 제외하고 기본 스레드에서 from HttpClient 을 처리할 수 Stream 없습니다.

SKBitmap.Decode 많은 작업을 수행합니다. 이 개체에 전달된 개체는 Stream 일반적인 비트맵 파일 형식(일반적으로 JPEG, PNG 또는 GIF) 중 하나로 전체 비트맵을 포함하는 메모리 블록을 참조합니다. 메서드는 Decode 형식을 확인한 다음 비트맵 파일을 SkiaSharp의 자체 내부 비트맵 형식으로 디코딩해야 합니다.

코드가 호출 SKBitmap.Decode된 후 처리기가 새로 로드된 비트맵을 CanvasView 표시할 수 있도록 PaintSurface 무효화될 수 있습니다.

비트맵을 로드하는 두 번째 방법은 개별 플랫폼 프로젝트에서 참조하는 .NET Standard 라이브러리에 비트맵을 포함된 리소스로 포함하는 것입니다. 리소스 ID가 메서드에 GetManifestResourceStream 전달됩니다. 이 리소스 ID는 마침표로 구분된 리소스의 어셈블리 이름, 폴더 이름 및 파일 이름으로 구성됩니다.

string resourceID = "assemblyName.folderName.fileName";
Assembly assembly = GetType().GetTypeInfo().Assembly;

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

비트맵 파일은 iOS, Android 및 UWP(유니버설 Windows 플랫폼)용 개별 플랫폼 프로젝트에 리소스로 저장할 수도 있습니다. 그러나 이러한 비트맵을 로드하려면 플랫폼 프로젝트에 있는 코드가 필요합니다.

비트맵을 가져오는 세 번째 방법은 사용자의 그림 라이브러리에서 가져온 것입니다. 다음 코드는 샘플 애플리케이션에 포함된 종속성 서비스를 사용합니다. SkiaSharpFormsDemo .NET 표준 라이브러리에는 인터페이스가 IPhotoLibrary 포함되며 각 플랫폼 프로젝트에는 해당 인터페이스를 PhotoLibrary 구현하는 클래스가 포함되어 있습니다.

IPhotoicturePicker picturePicker = DependencyService.Get<IPhotoLibrary>();

using (Stream stream = await picturePicker.GetImageStreamAsync())
{
    if (stream != null)
    {
        bitmap = SKBitmap.Decode(stream);
        ···
    }
}

일반적으로 이러한 코드는 처리기가 새 비트맵을 CanvasView PaintSurface 표시할 수 있도록 무효화됩니다.

이 클래스는 SKBitmap 비트맵의 픽셀 차원뿐만 아니라 비트맵을 만들고 복사하고 Height픽셀 비트를 노출하는 메서드를 비롯한 여러 메서드를 표시하는 몇 가지 유용한 속성을 Width 정의합니다.

픽셀 차원으로 표시

SkiaSharp Canvas 클래스는 네 DrawBitmap 가지 메서드를 정의합니다. 이러한 메서드를 사용하면 기본적으로 서로 다른 두 가지 방법으로 비트맵을 표시할 수 있습니다.

  • 값(또는 별개 xy 값)을 지정하면 SKPoint 비트맵이 픽셀 차원으로 표시됩니다. 비트맵의 픽셀은 비디오 디스플레이의 픽셀에 직접 매핑됩니다.
  • 사각형을 지정하면 비트맵이 사각형의 크기와 모양으로 확장됩니다.

매개 변수를 사용하거나 DrawBitmap 별도의 x y 매개 변수와 매개 변수를 사용하여 DrawBitmap SKPoint 해당 픽셀 차원에 비트맵을 표시합니다.

DrawBitmap(SKBitmap bitmap, SKPoint pt, SKPaint paint = null)

DrawBitmap(SKBitmap bitmap, float x, float y, SKPaint paint = null)

이러한 두 메서드는 기능적으로 동일합니다. 지정한 점은 캔버스를 기준으로 비트맵의 왼쪽 위 모서리 위치를 나타냅니다. 모바일 디바이스의 픽셀 해상도가 너무 높기 때문에 일반적으로 이러한 디바이스에서는 작은 비트맵이 매우 작게 표시됩니다.

선택적 SKPaint 매개 변수를 사용하면 투명도를 사용하여 비트맵을 표시할 수 있습니다. 이렇게 하려면 개체를 SKPaint 만들고 알파 채널이 Color 1보다 작은 값 SKColor 으로 속성을 설정합니다. 예시:

paint.Color = new SKColor(0, 0, 0, 0x80);

마지막 인수로 전달된 0x80 50% 투명도를 나타냅니다. 미리 정의된 색 중 하나에서 알파 채널을 설정할 수도 있습니다.

paint.Color = SKColors.Red.WithAlpha(0x80);

그러나 색 자체는 관련이 없습니다. 호출에서 개체를 사용할 SKPaint 때 알파 채널만 검사됩니다 DrawBitmap .

SKPaint 혼합 모드 또는 필터 효과를 사용하여 비트맵을 표시할 때도 개체가 역할을 합니다. SkiaSharp 작성 및 혼합 모드 및 SkiaSharp 이미지 필터 문서에서 설명합니다.

샘플 프로그램의 픽셀 차원 페이지에는 너비가 320픽셀 x 240픽셀인 비트맵 리소스가 표시됩니다.

public class PixelDimensionsPage : ContentPage
{
    SKBitmap bitmap;

    public PixelDimensionsPage()
    {
        Title = "Pixel Dimensions";

        // Load the bitmap from a resource
        string resourceID = "SkiaSharpFormsDemos.Media.Banana.jpg";
        Assembly assembly = GetType().GetTypeInfo().Assembly;

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

        // Create the SKCanvasView and set the PaintSurface handler
        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();

        float x = (info.Width - bitmap.Width) / 2;
        float y = (info.Height - bitmap.Height) / 2;

        canvas.DrawBitmap(bitmap, x, y);
    }
}

PaintSurface 처리기는 표시 화면의 픽셀 차원과 y 비트맵의 픽셀 차원을 기반으로 값을 계산 x 하여 비트맵의 중심을 지정합니다.

픽셀 차원

애플리케이션이 비트맵을 왼쪽 위 모서리에 표시하려는 경우 (0, 0)의 좌표를 전달하기만 하면 됩니다.

리소스 비트맵을 로드하는 메서드

앞으로 제공되는 많은 샘플은 비트맵 리소스를 로드해야 합니다. 샘플 솔루션의 정적 BitmapExtensions 클래스에는 다음을 도와주는 메서드가 포함되어 있습니다.

static class BitmapExtensions
{
    public static SKBitmap LoadBitmapResource(Type type, string resourceID)
    {
        Assembly assembly = type.GetTypeInfo().Assembly;

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

매개 변수를 확인합니다 Type . 비트맵 리소스를 Type 저장하는 어셈블리의 모든 형식과 연결된 개체일 수 있습니다.

LoadBitmapResource 메서드는 비트맵 리소스가 필요한 모든 후속 샘플에서 사용됩니다.

사각형을 채우기 위해 늘이기

또한 이 클래스는 SKCanvas 비트맵을 사각형으로 렌더링하는 메서드와 비트맵의 사각형 하위 집합을 사각형으로 렌더링하는 다른 DrawBitmap 메서드를 정의 DrawBitmap 합니다.

DrawBitmap(SKBitmap bitmap, SKRect dest, SKPaint paint = null)

DrawBitmap(SKBitmap bitmap, SKRect source, SKRect dest, SKPaint paint = null)

두 경우 모두 비트맵이 확장되어 명명 dest된 사각형을 채웁니다. 두 번째 메서드 source 에서 사각형을 사용하면 비트맵의 하위 집합을 선택할 수 있습니다. 사각형은 dest 출력 디바이스 source 를 기준으로 합니다. 사각형은 비트맵을 기준으로 합니다.

사각형 채우기 페이지에서는 앞의 예제에서 캔버스와 동일한 크기의 사각형에 사용된 동일한 비트맵을 표시하여 이러한 두 메서드 중 첫 번째 메서드를 보여 줍니다.

public class FillRectanglePage : ContentPage
{
    SKBitmap bitmap =
        BitmapExtensions.LoadBitmapResource(typeof(FillRectanglePage),
                                            "SkiaSharpFormsDemos.Media.Banana.jpg");
    public FillRectanglePage ()
    {
        Title = "Fill Rectangle";

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

        canvas.DrawBitmap(bitmap, info.Rect);
    }
}

BitmapExtensions.LoadBitmapResource 메서드를 사용하여 필드를 설정합니다 SKBitmap . 대상 사각형은 표시 화면의 SKImageInfo크기를 역사용하는 속성에서 Rect 가져옵니다.

채우기 사각형

이것은 일반적으로 당신이 원하는 것이 아닙니다 . 이미지는 가로 방향과 세로 방향으로 다르게 확장되어 왜곡됩니다. 비트맵을 픽셀 크기가 아닌 다른 값으로 표시할 때는 일반적으로 비트맵의 원래 가로 세로 비율을 유지하려고 합니다.

가로 세로 비율을 유지하면서 늘이기

가로 세로 비율을 유지하면서 비트맵을 확장하는 것은 균일한 크기 조정이라고도 하는 프로세스입니다. 이 용어는 알고리즘 접근 방식을 제안합니다. 한 가지 가능한 솔루션은 균일한 크기 조정 페이지에 표시됩니다.

public class UniformScalingPage : ContentPage
{
    SKBitmap bitmap =
        BitmapExtensions.LoadBitmapResource(typeof(UniformScalingPage),
                                            "SkiaSharpFormsDemos.Media.Banana.jpg");
    public UniformScalingPage()
    {
        Title = "Uniform Scaling";

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

        float scale = Math.Min((float)info.Width / bitmap.Width,
                               (float)info.Height / bitmap.Height);
        float x = (info.Width - scale * bitmap.Width) / 2;
        float y = (info.Height - scale * bitmap.Height) / 2;
        SKRect destRect = new SKRect(x, y, x + scale * bitmap.Width,
                                           y + scale * bitmap.Height);

        canvas.DrawBitmap(bitmap, destRect);
    }
}

PaintSurface 처리기는 비트맵 너비 및 높이에 대한 표시 너비 및 높이 비율의 최소 비율인 요소를 계산 scale 합니다. x y 그런 다음, 크기 조정된 비트맵을 표시 너비와 높이 내에서 가운데에 배치하기 위해 값과 값을 계산할 수 있습니다. 대상 사각형의 왼쪽 위 모서리와 y 해당 값의 x 오른쪽 아래 모서리와 비트맵의 배율 너비 및 높이가 있습니다.

균일한 크기 조정

휴대폰을 옆으로 돌려 해당 영역으로 뻗어 있는 비트맵을 확인합니다.

균일한 크기 조정 환경

약간 다른 알고리즘을 구현하려는 경우 이 scale 요소를 사용하는 장점이 분명해집니다. 비트맵의 가로 세로 비율을 유지하고 대상 사각형도 채우려고 하는 경우를 가정해 보겠습니다. 이것이 가능한 유일한 방법은 이미지의 일부를 자르는 것이지만 위의 코드로 변경 Math.Min 하여 해당 알고리즘을 구현할 Math.Max 수 있습니다. 결과:

균일한 크기 조정 대체

비트맵의 가로 세로 비율은 유지되지만 비트맵의 왼쪽과 오른쪽 영역은 잘립니다.

다양한 비트맵 표시 함수

XAML 기반 프로그래밍 환경(예: UWP 및 Xamarin.Forms)에는 가로 세로 비율을 유지하면서 비트맵의 크기를 확장하거나 축소할 수 있는 기능이 있습니다. SkiaSharp에는 이 기능이 포함되지 않지만 직접 구현할 수 있습니다.

샘플 애플리케이션에 포함된 클래스는 BitmapExtensions 방법을 보여줍니다. 클래스는 가로 세로 비율 계산을 수행하는 두 가지 새 DrawBitmap 메서드를 정의합니다. 이러한 새 메서드는 .의 확장 메서드입니다 SKCanvas.

DrawBitmap 메서드에는 BitmapExtensions.cs 파일에 정의된 열거형 형식BitmapStretch의 매개 변수가 포함됩니다.

public enum BitmapStretch
{
    None,
    Fill,
    Uniform,
    UniformToFill,
    AspectFit = Uniform,
    AspectFill = UniformToFill
}

None, FillUniform멤버는 UWP Stretch 열거형의 멤버와 UniformToFill 동일합니다. 유사한 Xamarin.Forms열거형은 멤버 FillAspectFitAspectFill.Aspect

위에 표시된 균일한 크기 조정 페이지는 비트맵을 사각형 내의 가운데에 배치하지만 사각형의 왼쪽이나 오른쪽에 비트맵을 배치하거나 위쪽 또는 아래쪽에 배치하는 등의 다른 옵션을 원할 수 있습니다. 이것이 열거형의 BitmapAlignment 목적입니다.

public enum BitmapAlignment
{
    Start,
    Center,
    End
}

맞춤 설정은 .와 함께 BitmapStretch.Fill사용할 때 영향을 주지 않습니다.

첫 번째 DrawBitmap 확장 함수는 대상 사각형을 포함하지만 원본 사각형은 포함하지 않습니다. 비트맵을 가운데에 배치하려면 멤버만 지정하면 되도록 기본값이 BitmapStretch 정의됩니다.

static class BitmapExtensions
{
    ···
    public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect dest,
                                  BitmapStretch stretch,
                                  BitmapAlignment horizontal = BitmapAlignment.Center,
                                  BitmapAlignment vertical = BitmapAlignment.Center,
                                  SKPaint paint = null)
    {
        if (stretch == BitmapStretch.Fill)
        {
            canvas.DrawBitmap(bitmap, dest, paint);
        }
        else
        {
            float scale = 1;

            switch (stretch)
            {
                case BitmapStretch.None:
                    break;

                case BitmapStretch.Uniform:
                    scale = Math.Min(dest.Width / bitmap.Width, dest.Height / bitmap.Height);
                    break;

                case BitmapStretch.UniformToFill:
                    scale = Math.Max(dest.Width / bitmap.Width, dest.Height / bitmap.Height);
                    break;
            }

            SKRect display = CalculateDisplayRect(dest, scale * bitmap.Width, scale * bitmap.Height,
                                                  horizontal, vertical);

            canvas.DrawBitmap(bitmap, display, paint);
        }
    }
    ···
}

이 메서드의 주요 목적은 메서드를 호출할 때 비트맵 너비 및 높이에 적용되는 명명된 scale 배율 인수를 계산하는 CalculateDisplayRect 것입니다. 다음은 가로 및 세로 맞춤을 기반으로 비트맵을 표시하기 위한 사각형을 계산하는 메서드입니다.

static class BitmapExtensions
{
    ···
    static SKRect CalculateDisplayRect(SKRect dest, float bmpWidth, float bmpHeight,
                                       BitmapAlignment horizontal, BitmapAlignment vertical)
    {
        float x = 0;
        float y = 0;

        switch (horizontal)
        {
            case BitmapAlignment.Center:
                x = (dest.Width - bmpWidth) / 2;
                break;

            case BitmapAlignment.Start:
                break;

            case BitmapAlignment.End:
                x = dest.Width - bmpWidth;
                break;
        }

        switch (vertical)
        {
            case BitmapAlignment.Center:
                y = (dest.Height - bmpHeight) / 2;
                break;

            case BitmapAlignment.Start:
                break;

            case BitmapAlignment.End:
                y = dest.Height - bmpHeight;
                break;
        }

        x += dest.Left;
        y += dest.Top;

        return new SKRect(x, y, x + bmpWidth, y + bmpHeight);
    }
}

클래스에는 BitmapExtensions 비트맵의 하위 집합을 지정하기 위한 원본 사각형이 있는 추가 DrawBitmap 메서드가 포함되어 있습니다. 이 메서드는 배율 인수가 사각형을 기반으로 계산된 다음 다음 호출CalculateDisplayRectsource 사각형에 source 적용된다는 점을 제외하고 첫 번째 메서드와 비슷합니다.

static class BitmapExtensions
{
    ···
    public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect source, SKRect dest,
                                  BitmapStretch stretch,
                                  BitmapAlignment horizontal = BitmapAlignment.Center,
                                  BitmapAlignment vertical = BitmapAlignment.Center,
                                  SKPaint paint = null)
    {
        if (stretch == BitmapStretch.Fill)
        {
            canvas.DrawBitmap(bitmap, source, dest, paint);
        }
        else
        {
            float scale = 1;

            switch (stretch)
            {
                case BitmapStretch.None:
                    break;

                case BitmapStretch.Uniform:
                    scale = Math.Min(dest.Width / source.Width, dest.Height / source.Height);
                    break;

                case BitmapStretch.UniformToFill:
                    scale = Math.Max(dest.Width / source.Width, dest.Height / source.Height);
                    break;
            }

            SKRect display = CalculateDisplayRect(dest, scale * source.Width, scale * source.Height,
                                                  horizontal, vertical);

            canvas.DrawBitmap(bitmap, source, display, paint);
        }
    }
    ···
}

이러한 두 가지 새로운 DrawBitmap 방법 중 첫 번째는 크기 조정 모드 페이지에서 보여 줍니다 . XAML 파일에는 열거형의 BitmapStretch 멤버를 BitmapAlignment 선택할 수 있는 세 Picker 가지 요소가 포함되어 있습니다.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SkiaSharpFormsDemos"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Bitmaps.ScalingModesPage"
             Title="Scaling Modes">

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

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

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

        <Label Text="Stretch:"
               Grid.Row="1" Grid.Column="0"
               VerticalOptions="Center" />

        <Picker x:Name="stretchPicker"
                Grid.Row="1" Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type local:BitmapStretch}">
                    <x:Static Member="local:BitmapStretch.None" />
                    <x:Static Member="local:BitmapStretch.Fill" />
                    <x:Static Member="local:BitmapStretch.Uniform" />
                    <x:Static Member="local:BitmapStretch.UniformToFill" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Label Text="Horizontal Alignment:"
               Grid.Row="2" Grid.Column="0"
               VerticalOptions="Center" />

        <Picker x:Name="horizontalPicker"
                Grid.Row="2" Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type local:BitmapAlignment}">
                    <x:Static Member="local:BitmapAlignment.Start" />
                    <x:Static Member="local:BitmapAlignment.Center" />
                    <x:Static Member="local:BitmapAlignment.End" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Label Text="Vertical Alignment:"
               Grid.Row="3" Grid.Column="0"
               VerticalOptions="Center" />

        <Picker x:Name="verticalPicker"
                Grid.Row="3" Grid.Column="1"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type local:BitmapAlignment}">
                    <x:Static Member="local:BitmapAlignment.Start" />
                    <x:Static Member="local:BitmapAlignment.Center" />
                    <x:Static Member="local:BitmapAlignment.End" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>
    </Grid>
</ContentPage>

코드 숨김 파일은 항목이 CanvasView 변경된 경우 Picker 를 무효화합니다. PaintSurface 처리기는 확장 메서드를 호출하기 위한 세 Picker 가지 보기에 DrawBitmap 액세스합니다.

public partial class ScalingModesPage : ContentPage
{
    SKBitmap bitmap =
        BitmapExtensions.LoadBitmapResource(typeof(ScalingModesPage),
                                            "SkiaSharpFormsDemos.Media.Banana.jpg");
    public ScalingModesPage()
    {
        InitializeComponent();
    }

    private void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

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

        canvas.Clear();

        SKRect dest = new SKRect(0, 0, info.Width, info.Height);

        BitmapStretch stretch = (BitmapStretch)stretchPicker.SelectedItem;
        BitmapAlignment horizontal = (BitmapAlignment)horizontalPicker.SelectedItem;
        BitmapAlignment vertical = (BitmapAlignment)verticalPicker.SelectedItem;

        canvas.DrawBitmap(bitmap, dest, stretch, horizontal, vertical);
    }
}

옵션의 몇 가지 조합은 다음과 같습니다.

크기 조정 모드

사각형 하위 집합 페이지에는 크기 조정 모드거의 동일한 XAML 파일이 있지만 코드 숨김 파일은 필드에서 제공하는 SOURCE 비트맵의 사각형 하위 집합을 정의합니다.

public partial class ScalingModesPage : ContentPage
{
    SKBitmap bitmap =
        BitmapExtensions.LoadBitmapResource(typeof(ScalingModesPage),
                                            "SkiaSharpFormsDemos.Media.Banana.jpg");

    static readonly SKRect SOURCE = new SKRect(94, 12, 212, 118);

    public RectangleSubsetPage()
    {
        InitializeComponent();
    }

    private void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }

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

        canvas.Clear();

        SKRect dest = new SKRect(0, 0, info.Width, info.Height);

        BitmapStretch stretch = (BitmapStretch)stretchPicker.SelectedItem;
        BitmapAlignment horizontal = (BitmapAlignment)horizontalPicker.SelectedItem;
        BitmapAlignment vertical = (BitmapAlignment)verticalPicker.SelectedItem;

        canvas.DrawBitmap(bitmap, SOURCE, dest, stretch, horizontal, vertical);
    }
}

이 사각형 소스는 다음 스크린샷과 같이 원숭이의 머리를 격리합니다.

사각형 하위 집합