Sdílet prostřednictvím


Zobrazení rastrových obrázků SkiaSharp

Předmět rastrových obrázků SkiaSharp byl představen v článku Základy bitmap v SkiaSharp. Tento článek ukázal tři způsoby, jak načíst rastrové obrázky a tři způsoby zobrazení rastrových obrázků. Tento článek se zabývá technikami načítání rastrových obrázků a podrobněji se zabývá používáním DrawBitmap metod SKCanvas.

Zobrazení ukázky

Tyto DrawBitmapLattice a DrawBitmapNinePatch metody jsou popsány v článku Segmented display of SkiaSharp bitmaps.

Ukázky na této stránce pocházejí z ukázkové aplikace. Na domovské stránce této aplikace zvolte SkiaSharp Bitmaps a pak přejděte do části Zobrazení rastrových obrázků .

Načtení rastrového obrázku

Rastrový obrázek používaný aplikací SkiaSharp obecně pochází z jednoho ze tří různých zdrojů:

  • Z internetu
  • Z prostředku vloženého do spustitelného souboru
  • Z knihovny fotek uživatele

Aplikaci SkiaSharp je také možné vytvořit nový rastrový obrázek a pak na něj kreslit nebo nastavit bity bitmapy algoritmicky. Tyto techniky jsou popsány v článcích Vytváření a kreslení na bitmapy SkiaSharp a přístup k bitmapám SkiaSharp Bitmap Pixels.

V následujících třech příkladech kódu načtení bitmapy se předpokládá, že třída obsahuje pole typu SKBitmap:

SKBitmap bitmap;

Jak uvádí článek Základy rastrového obrázku ve SkiaSharpu , nejlepší způsob, jak načíst rastrový obrázek přes internet, je s HttpClient třídou. Jednu instanci třídy lze definovat jako pole:

HttpClient httpClient = new HttpClient();

Při použití HttpClient s aplikacemi pro iOS a Android budete chtít nastavit vlastnosti projektu, jak je popsáno v dokumentech tls (Transport Layer Security) 1.2.

Kód, který často používá HttpClient , zahrnuje await operátor, takže se musí nacházet v async metodě:

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
{
    ···
}

Všimněte si, že Stream objekt získaný zkopírovaný GetStreamAsync do objektu MemoryStream. Android neumožňuje Stream zpracování z HttpClient hlavního vlákna s výjimkou asynchronních metod.

Dělá SKBitmap.Decode hodně práce: Objekt Stream předaný do něj odkazuje na blok paměti obsahující celý rastrový obrázek v jednom z běžných formátů rastrových souborů, obecně JPEG, PNG nebo GIF. Metoda Decode musí určit formát a potom dekódovat rastrový soubor do vlastního interního rastrového formátu SkiaSharp.

Po volání SKBitmap.Decodekódu pravděpodobně zneplatní CanvasView , aby PaintSurface obslužná rutina mohla zobrazit nově načtený rastrový obrázek.

Druhým způsobem, jak načíst rastrový obrázek, je zahrnutím rastru jako vloženého prostředku do knihovny .NET Standard, na kterou odkazují jednotlivé projekty platformy. Metodě se předá GetManifestResourceStream ID prostředku. Toto ID prostředku se skládá z názvu sestavení, názvu složky a názvu souboru prostředku odděleného tečkami:

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

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

Rastrové soubory lze také uložit jako prostředky v projektu jednotlivých platforem pro iOS, Android a Univerzální platforma Windows (UPW). Načtení těchto rastrových obrázků však vyžaduje kód umístěný v projektu platformy.

Třetí přístup k získání rastrového obrázku je z knihovny obrázků uživatele. Následující kód používá službu závislostí, která je součástí ukázkové aplikace. Knihovna SkiaSharpFormsDemo .NET Standard zahrnuje IPhotoLibrary rozhraní, zatímco každý z projektů platformy obsahuje PhotoLibrary třídu, která implementuje toto rozhraní.

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

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

Obecně platí, že takový kód také zneplatňuje CanvasView , aby obslužná rutina PaintSurface mohl zobrazit nový rastrový obrázek.

Třída SKBitmap definuje několikužitečných Width Height

Zobrazení v rozměrech pixelů

Třída SkiaSharp Canvas definuje čtyři DrawBitmap metody. Tyto metody umožňují zobrazení rastrových obrázků dvěma základními způsoby:

  • Zadáním SKPoint hodnoty (nebo samostatných x hodnot) y se rastrový obrázek zobrazí v rozměrech jeho pixelů. Pixely rastrového obrázku jsou mapovány přímo na pixely zobrazení videa.
  • Určení obdélníku způsobí, že se rastrový obrázek roztáhne na velikost a tvar obdélníku.

Rastrový obrázek se zobrazí v rozměrech jeho pixelů pomocí DrawBitmap parametru SKPoint nebo DrawBitmap s samostatnými x a y parametry:

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

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

Tyto dvě metody jsou funkčně identické. Zadaný bod označuje umístění levého horního rohu rastrového obrázku vzhledem k plátnu. Vzhledem k tomu, že rozlišení pixelů mobilních zařízení je tak vysoké, menší rastrové obrázky se obvykle na těchto zařízeních zobrazují poměrně malé.

Volitelný SKPaint parametr umožňuje zobrazit rastrový obrázek pomocí průhlednosti. Uděláte to tak, že vytvoříte SKPaint objekt a nastavíte Color vlastnost na libovolnou SKColor hodnotu s alfa kanálem menším než 1. Příklad:

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

0x80 předaný jako poslední argument označuje 50% transparentnost. Alfa kanál můžete také nastavit na jednu z předdefinovaných barev:

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

Samotná barva je však irelevantní. Při použití objektu SKPaint ve DrawBitmap volání se zkoumá pouze alfa kanál.

Objekt SKPaint hraje také roli při zobrazení rastrových obrázků pomocí režimů blendu nebo efektů filtru. Ty jsou znázorněny v článcích SkiaSharp kompoziting a režimy směsi a filtry obrázků SkiaSharp.

Stránka Rozměry pixelů v ukázkovém programu zobrazuje rastrový zdroj, který je široký o 320 pixelů o 240 pixelů vysoko:

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

Obslužná rutina PaintSurface zacentruje rastrový obrázek výpočtem x a y hodnotami na základě rozměrů obrazových bodů povrchu zobrazení a rozměrů pixelů rastrového obrázku:

Rozměry pixelů

Pokud by aplikace chtěla zobrazit rastrový obrázek v levém horním rohu, jednoduše by prošel souřadnicemi (0, 0).

Metoda načítání rastrových obrázků prostředků

Mnoho z připravovaných ukázek bude muset načíst rastrové prostředky. Statická BitmapExtensions třída v ukázkovém řešení obsahuje metodu, která vám pomůže:

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

Všimněte si parametru Type . Může to být objekt přidružený k libovolnému Type typu v sestavení, který ukládá rastrový prostředek.

Tato LoadBitmapResource metoda se použije ve všech následných ukázkách, které vyžadují rastrové prostředky.

Roztažení pro vyplnění obdélníku

Třída SKCanvas také definuje metodu DrawBitmap , která vykreslí rastrový obrázek do obdélníku, a další DrawBitmap metoda, která vykresluje obdélníkovou podmnožinu rastrového obrázku obdélníku:

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

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

V oboupřípadechch dest Ve druhé metodě source umožňuje obdélník vybrat podmnožinu rastrového obrázku. dest Obdélník je relativní vůči výstupnímu zařízení; source obdélník je relativní vůči rastru.

Stránka Vyplnit obdélník ukazuje první z těchto dvou metod zobrazením stejného rastrového obrázku použitého v předchozím příkladu v obdélníku se stejnou velikostí jako plátno:

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

Všimněte si použití nové BitmapExtensions.LoadBitmapResource metody k nastavení SKBitmap pole. Cílový obdélník se získá z Rect vlastnosti SKImageInfo, která označuje velikost povrchu displeje:

Obdélník výplně

To obvykle není to, co chcete. Obrázek je zkreslený roztažením v vodorovném a svislém směru. Při zobrazení rastrového obrázku v jiném než jeho pixelové velikosti, obvykle chcete zachovat původní poměr stran rastrového obrázku.

Roztažení při zachování poměru stran

Roztažení rastrového obrázku při zachování poměru stran je proces známý také jako jednotné měřítko. Tento termín naznačuje algoritmus. Jedno z možných řešení je zobrazeno na stránce Jednotné škálování :

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

Obslužná PaintSurface rutina vypočítá faktor, který je minimálním poměrem šířky scale a výšky zobrazení k šířce a výšce rastrového obrázku. Hodnoty x a y hodnoty se pak dají vypočítat pro na střed měřítka rastrového obrázku v rámci šířky a výšky zobrazení. Cílový obdélník má levý horní roh x těchto hodnot a y pravý dolní roh těchto hodnot a šířku a výšku rastrového obrázku:

Jednotné škálování

Otočte telefon do strany a zobrazte rastrový obrázek roztažený do této oblasti:

Jednotné měřítko na šířku

Výhodou použití tohoto scale faktoru je zřejmé, když chcete implementovat trochu jiný algoritmus. Předpokládejme, že chcete zachovat poměr stran rastrového obrázku, ale také vyplnit cílový obdélník. Jediným možným způsobem je oříznutím části obrázku, ale tento algoritmus můžete implementovat jednoduše tak, že se změníte Math.Min na Math.Max výše uvedený kód. Tady je výsledek:

Alternativa k jednotnému škálování

Poměr stran rastrového obrázku je zachován, ale oblasti vlevo a vpravo od rastru se oříznou.

Univerzální funkce rastrového zobrazení

Programovací prostředí založená na XAML (například UPW a Xamarin.Forms) mají možnost rozšířit nebo zmenšit velikost rastrových obrázků při zachování jejich poměrů stran. I když SkiaSharp tuto funkci neobsahuje, můžete ji implementovat sami.

Tato BitmapExtensions třída, která je součástí ukázkové aplikace, ukazuje, jak na to. Třída definuje dvě nové DrawBitmap metody, které provádějí výpočet poměru stran. Tyto nové metody jsou rozšiřující metody SKCanvas.

Nové DrawBitmap metody zahrnují parametr typu BitmapStretch, výčet definovaný v souboru BitmapExtensions.cs :

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

, NoneFillUniforma UniformToFill členy jsou stejné jako v výčtu UPWStretch. Podobný Xamarin.FormsAspect výčet definuje členy Fill, AspectFita AspectFill.

Stránka Uniform Scaling (Uniform Scaling ) zobrazená nad středem rastrového obrázku uvnitř obdélníku, ale můžete chtít jiné možnosti, jako je umístění rastrového obrázku na levé nebo pravé straně obdélníku nebo nahoře nebo dole. To je účel výčtu BitmapAlignment :

public enum BitmapAlignment
{
    Start,
    Center,
    End
}

Nastavení zarovnání nemá žádný vliv při použití s BitmapStretch.Fill.

První DrawBitmap funkce rozšíření obsahuje cílový obdélník, ale žádný zdrojový obdélník. Výchozí hodnoty jsou definovány tak, aby pokud chcete rastrový obrázek zacentrovat, stačí zadat BitmapStretch pouze člen:

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

Primárním účelem této metody je vypočítat faktor měřítka s názvem scale , který se pak použije na šířku a výšku rastrového obrázku CalculateDisplayRect při volání metody. Toto je metoda, která vypočítá obdélník pro zobrazení rastrového obrázku na základě vodorovného a svislého zarovnání:

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

Třída BitmapExtensions obsahuje další DrawBitmap metodu se zdrojovým obdélníkem pro určení podmnožina rastrového obrázku. Tato metoda se podobá první metodě s tím rozdílem, že koeficient měřítka se vypočítá na základě obdélníku source a pak se použije na source obdélník ve volání:CalculateDisplayRect

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

První z těchto dvou nových DrawBitmap metod je znázorněn na stránce Režimy škálování. Soubor XAML obsahuje tři Picker prvky, které umožňují vybrat členy a BitmapStretch BitmapAlignment výčty:

<?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>

Soubor kódu jednoduše zneplatní CanvasView , když se nějaká Picker položka změnila. Obslužná rutina PaintSurface přistupuje ke třem Picker zobrazením pro volání DrawBitmap metody rozšíření:

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

Tady jsou některé kombinace možností:

Režimy škálování

Stránka Podmnožina obdélníku má prakticky stejný soubor XAML jako režimy škálování, ale soubor s kódem za kódem definuje obdélníkovou podmnožinu rastrového obrázku zadaného SOURCE polem:

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

Tento obdélníkový zdroj izoluje hlavu opice, jak je znázorněno na těchto snímcích obrazovky:

Podmnožina obdélníku