Visualizzazione di bitmap di SkiaSharpDisplaying SkiaSharp bitmaps

Scaricare l'esempio scaricare l'esempioDownload Sample Download the sample

Nell'articolo è stato introdotto il soggetto di bitmap di SkiaSharp nozioni di base di Bitmap in SkiaSharp .The subject of SkiaSharp bitmaps was introduced in the article Bitmap Basics in SkiaSharp. Questo articolo ha illustrato tre modi per bitmap di carico e i tre modi per visualizzare le bitmap.That article showed three ways to load bitmaps and three ways to display bitmaps. Questo articolo vengono esaminate le tecniche per caricare le immagini bitmap e diventa più approfondito l'utilizzo dei DrawBitmap metodi di SKCanvas.This article reviews the techniques to load bitmaps and goes deeper into the use of the DrawBitmap methods of SKCanvas.

Visualizzazione campioneDisplaying Sample

Il DrawBitmapLattice e DrawBitmapNinePatch metodi sono descritti nell'articolo visualizzazione delle bitmap di SkiaSharp segmentata .The DrawBitmapLattice and DrawBitmapNinePatch methods are discussed in the article Segmented display of SkiaSharp bitmaps.

Esempi in questa pagina sono compresi i SkiaSharpFormsDemos dell'applicazione.Samples on this page are from the SkiaSharpFormsDemos application. Dalla home page dell'applicazione, scegliere SkiaSharp Bitmaps, quindi passare al la visualizzazione di bitmap sezione.From the home page of that application, choose SkiaSharp Bitmaps, and then go to the Displaying Bitmaps section.

Il caricamento di una bitmapLoading a bitmap

Una bitmap utilizzata da un'applicazione di SkiaSharp in genere deriva da una delle tre origini diverse:A bitmap used by a SkiaSharp application generally comes from one of three different sources:

  • Da InternetFrom over the Internet
  • Da una risorsa incorporata nel file eseguibileFrom a resource embedded in the executable
  • Da Raccolta foto dell'utenteFrom the user's photo library

È anche possibile per un'applicazione di SkiaSharp creare una nuova bitmap, quindi disegnare su di esso o impostare i bit della bitmap tramite algoritmo.It is also possible for a SkiaSharp application to create a new bitmap, and then draw on it or set the bitmap bits algorithmically. Queste tecniche vengono illustrate negli articoli creazione e la creazione su SkiaSharp Bitmaps e l'accesso a pixel Bitmap SkiaSharp .Those techniques are discussed in the articles Creating and Drawing on SkiaSharp Bitmaps and Accessing SkiaSharp Bitmap Pixels.

Negli esempi di codice di tre seguenti del caricamento di una bitmap, viene usata la classe contenga un campo di tipo SKBitmap:In the following three code examples of loading a bitmap, the class is assumed to contain a field of type SKBitmap:

SKBitmap bitmap;

Come l'articolo nozioni di base di Bitmap in SkiaSharp indicato, è il modo migliore per caricare una bitmap tramite Internet con il HttpClient classe.As the article Bitmap Basics in SkiaSharp stated, the best way to load a bitmap over the Internet is with the HttpClient class. Una singola istanza della classe può essere definita come campo:A single instance of the class can be defined as a field:

HttpClient httpClient = new HttpClient();

Quando si usa HttpClient con applicazioni iOS e Android, è opportuno impostare le proprietà del progetto come descritto nei documenti sul Transport Layer Security (TLS) 1.2 .When using HttpClient with iOS and Android applications, you'll want to set project properties as described in the documents on Transport Layer Security (TLS) 1.2.

Codice che usa HttpClient spesso comporta il await operatore, in modo che si trova un async metodo:Code that uses HttpClient often involves the await operator, so it must reside in an async method:

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(stream);
        ···
    };
}
catch
{
    ···
}

Si noti che il Stream ottenuto dall'oggetto GetStreamAsync viene copiato in un MemoryStream.Notice that the Stream object obtained from GetStreamAsync is copied into a MemoryStream. Android non supporta il Stream da HttpClient devono essere elaborati dal thread principale, ad eccezione di metodi asincroni.Android does not allow the Stream from HttpClient to be processed by the main thread except in asynchronous methods.

Il SKBitmap.Decode esegue una grande quantità di lavoro: L' Stream oggetto passato fa riferimento a un blocco di memoria contenente un'intera bitmap in uno dei formati di file bitmap comuni, generalmente JPEG, PNG o gif.The SKBitmap.Decode does a lot of work: The Stream object passed to it references a block of memory containing an entire bitmap in one of the common bitmap file formats, generally JPEG, PNG, or GIF. Il Decode metodo deve determinare il formato e quindi decodificare il file bitmap in formato bitmap interne di SkiaSharp.The Decode method must determine the format, and then decode the bitmap file into SkiaSharp's own internal bitmap format.

Dopo il codice chiama SKBitmap.Decode, probabilmente invaliderà le CanvasView in modo che il PaintSurface gestore di è possibile visualizzare la bitmap appena caricata.After your code calls SKBitmap.Decode, it will probably invalidate the CanvasView so that the PaintSurface handler can display the newly loaded bitmap.

Il secondo modo per caricare una bitmap, includendo la mappa di bit come risorsa incorporata nella libreria .NET Standard fanno riferimento i singoli progetti di piattaforma.The second way to load a bitmap is by including the bitmap as an embedded resource in the .NET Standard library referenced by the individual platform projects. Una risorsa ID viene passato per il GetManifestResourceStream (metodo).A resource ID is passed to the GetManifestResourceStream method. Questo ID di risorsa include il nome dell'assembly, nome della cartella e il nome della risorsa separato da punti:This resource ID consists of the assembly name, folder name, and filename of the resource separated by periods:

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

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

File bitmap possono essere archiviati anche come risorse nel progetto singoli platform per iOS, Android e Universal Windows Platform (UWP).Bitmap files can also be stored as resources in the individual platform project for iOS, Android, and the Universal Windows Platform (UWP). Tuttavia, il caricamento di tali bitmap richiede codice di cui si trova il progetto della piattaforma.However, loading those bitmaps requires code that is located in the platform project.

Un terzo approccio per ottenere una bitmap è dalla raccolta immagini dell'utente.A third approach to obtaining a bitmap is from the user's picture library. Il codice seguente usa un servizio di dipendenza che è incluso nel SkiaSharpFormsDemos dell'applicazione.The following code uses a dependency service that is included in the SkiaSharpFormsDemos application. Il SkiaSharpFormsDemo libreria .NET Standard include la IPhotoLibrary interfaccia, mentre ciascun progetto della piattaforma contiene un PhotoLibrary classe che implementa tale interfaccia.The SkiaSharpFormsDemo .NET Standard Library includes the IPhotoLibrary interface, while each of the platform projects contains a PhotoLibrary class that implements that interface.

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

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

In genere, tale codice invalida il CanvasView in modo che il PaintSurface gestore di è possibile visualizzare la nuova bitmap.Generally, such code also invalidates the CanvasView so that the PaintSurface handler can display the new bitmap.

Il SKBitmap classe definisce diverse proprietà utili, tra cui Width e Height , che mostra le dimensioni in pixel della bitmap, nonché molti metodi, tra cui metodi per creare bitmap, copiarli di esporre i bit di pixel.The SKBitmap class defines several useful properties, including Width and Height, that reveal the pixel dimensions of the bitmap, as well as many methods, including methods to create bitmaps, to copy them, and to expose the pixel bits.

Visualizzazione in dimensioni in pixelDisplaying in pixel dimensions

Di SkiaSharp Canvas classe definisce quattro DrawBitmap metodi.The SkiaSharp Canvas class defines four DrawBitmap methods. Questi metodi consentono di bitmap da visualizzare in due modi fondamentalmente diversi:These methods allow bitmaps to be displayed in two fundamentally different ways:

  • Specifica un SKPoint valore (o separata x e y valori) consente di visualizzare la mappa di bit in relative dimensioni in pixel.Specifying an SKPoint value (or separate x and y values) displays the bitmap in its pixel dimensions. I pixel della bitmap vengono eseguito il mapping direttamente al pixel dello schermo del video.The pixels of the bitmap are mapped directly to pixels of the video display.
  • Se si specifica un rettangolo, la bitmap per estenderla per le dimensioni del rettangolo.Specifying a rectangle causes the bitmap to be stretched to the size and shape of the rectangle.

Visualizzare una bitmap nella usando le dimensioni in pixel DrawBitmap con un SKPoint parametro oppure DrawBitmap con separato x e y parametri:You display a bitmap in its pixel dimensions using DrawBitmap with an SKPoint parameter or DrawBitmap with separate x and y parameters:

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

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

Questi due metodi sono funzionalmente identici.These two methods are functionally identical. Il punto specificato indica la posizione dell'angolo superiore sinistro della bitmap rispetto all'area di disegno.The specified point indicates the location of the upper-left corner of the bitmap relative to the canvas. Poiché la risoluzione i pixel dei dispositivi mobili è talmente elevata, più piccole bitmap visualizzato in genere abbastanza ridotti in questi dispositivi.Because the pixel resolution of mobile devices is so high, smaller bitmaps usually appear quite tiny on these devices.

L'opzione facoltativa SKPaint parametro consente di visualizzare la mappa di bit con la trasparenza.The optional SKPaint parameter allows you to display the bitmap using transparency. A questo scopo, creare un SKPaint dell'oggetto e impostare il Color a qualsiasi proprietà SKColor minore di 1 valore con un valore alfa del canale.To do this, create an SKPaint object and set the Color property to any SKColor value with an alpha channel less than 1. Ad esempio:For example:

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

Il 0x80 passato come ultimo argomento indica la trasparenza di 50%.The 0x80 passed as the last argument indicates 50% transparency. È anche possibile impostare un canale alfa su uno dei colori predefiniti:You can also set an alpha channel on one of the pre-defined colors:

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

Tuttavia, al colore stesso è irrilevante.However, the color itself is irrelevant. Viene esaminato solo il canale alfa quando si usa la SKPaint dell'oggetto un DrawBitmap chiamare.Only the alpha channel is examined when you use the SKPaint object in a DrawBitmap call.

Il SKPaint oggetto svolge un ruolo anche quando si nasconde le bitmap con le modalità di blend o filtrare gli effetti.The SKPaint object also plays a role when displaying bitmaps using blend modes or filter effects. Questi vengono illustrati negli articoli modalità di composizione e blend SkiaSharp e filtri immagini di SkiaSharp.These are demonstrated in the articles SkiaSharp compositing and blend modes and SkiaSharp image filters.

Il dimensioni in Pixel pagina il SkiaSharpFormsDemos programma di esempio consente di visualizzare una risorsa della bitmap che 320 pixel in larghezza 240 pixel di altezza:The Pixel Dimensions page in the SkiaSharpFormsDemos sample program displays a bitmap resource that is 320 pixels wide by 240 pixels high:

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

Il PaintSurface gestore consente di centrare la mappa di bit calcolando x e y valori basati sulle dimensioni in pixel dell'area di visualizzazione e le dimensioni in pixel della bitmap:The PaintSurface handler centers the bitmap by calculating x and y values based on the pixel dimensions of the display surface and the pixel dimensions of the bitmap:

Dimensioni in pixelPixel Dimensions

Se l'applicazione desidera visualizzare la bitmap all'angolo superiore sinistro, lo passerebbe semplicemente le coordinate di (0, 0).If the application wishes to display the bitmap in its upper-left corner, it would simply pass coordinates of (0, 0).

Un metodo per il caricamento delle bitmap di risorsaA method for loading resource bitmaps

Molti degli esempi di presentarsi sarà necessario caricare le risorse di bitmap.Many of the samples coming up will need to load bitmap resources. Il metodo statico BitmapExtensions classe la SkiaSharpFormsDemos soluzione contiene un metodo di supporto:The static BitmapExtensions class in the SkiaSharpFormsDemos solution contains a method to help out:

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

Si noti che il Type parametro.Notice the Type parameter. Può trattarsi di Type oggetto associato a qualsiasi tipo nell'assembly che archivia la risorsa della bitmap.This can be the Type object associated with any type in the assembly that stores the bitmap resource.

Ciò LoadBitmapResource verrà utilizzato il metodo in tutti i campioni successivi che richiedono risorse bitmap.This LoadBitmapResource method will be used in all subsequent samples that require bitmap resources.

L'estensione per riempire un rettangoloStretching to fill a rectangle

Il SKCanvas classe definisce anche una DrawBitmap metodo che esegue il rendering di bitmap da un rettangolo e un altro DrawBitmap metodo che esegue il rendering di un sottoinsieme rettangolare della bitmap da un rettangolo:The SKCanvas class also defines a DrawBitmap method that renders the bitmap to a rectangle, and another DrawBitmap method that renders a rectangular subset of the bitmap to a rectangle:

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

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

In entrambi i casi, la bitmap viene adattata per riempire il rettangolo denominato dest.In both cases, the bitmap is stretched to fill the rectangle named dest. Il secondo metodo, il source rettangolo consente di selezionare un subset della bitmap.In the second method, the source rectangle allows you to select a subset of the bitmap. Il dest rettangolo è relativo alla periferica di output; i source rettangolo è relativo alla bitmap.The dest rectangle is relative to the output device; the source rectangle is relative to the bitmap.

Il rettangolo con riempimento pagina viene illustrato il primo di questi due metodi tramite la visualizzazione stessa bitmap usato nell'esempio precedente in un rettangolo le stesse dimensioni come area di disegno:The Fill Rectangle page demonstrates the first of these two methods by displaying the same bitmap used in the earlier example in a rectangle the same size as the canvas:

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

Si noti l'uso della nuova BitmapExtensions.LoadBitmapResource per impostare il SKBitmap campo.Notice the use of the new BitmapExtensions.LoadBitmapResource method to set the SKBitmap field. Il rettangolo di destinazione viene ottenuto dal Rect proprietà SKImageInfo, che vengono indicate le dimensioni dell'area di visualizzazione:The destination rectangle is obtained from the Rect property of SKImageInfo, which desribes the size of the display surface:

Riempire rettangoloFill Rectangle

Si tratta in genere non risultato desiderato.This is usually not what you want. L'immagine risulta distorta dal verrà estesa in modo diverso nelle direzioni orizzontale e verticale.The image is distorted by being stretched differently in the horizontal and vertical directions. La visualizzazione di una mappa di bit in un valore diverso da relative dimensioni in pixel, in genere si desidera mantenere le proporzioni originali della bitmap.When displaying a bitmap in something other than its pixel size, usually you want to preserve the bitmap's original aspect ratio.

L'estensione mantenendo le proporzioniStretching while preserving the aspect ratio

L'estensione di una bitmap, mantenendo tuttavia le proporzioni è un processo noto anche come ridimensionamento uniforme.Stretching a bitmap while preserving the aspect ratio is a process also known as uniform scaling. A tale termine algoritmico suggerite.That term suggests an algorithmic approach. Una possibile soluzione è illustrata nella ridimensionamento uniforme pagina:One possible solution is shown in the Uniform Scaling page:

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

Il PaintSurface gestore calcola un scale fattore che è il requisito minimo del rapporto tra l'altezza e la larghezza della bitmap e l'altezza e larghezza di visualizzazione.The PaintSurface handler calculates a scale factor that is the minimum of the ratio of the display width and height to the bitmap width and height. Il x e y valori possono quindi essere calcolati per centrare la mappa di bit con scalabilità all'interno della larghezza di visualizzazione e l'altezza.The x and y values can then be calculated for centering the scaled bitmap within the display width and height. Il rettangolo di destinazione ha un angolo superiore sinistro di x e y e un angolo inferiore destro di tali valori oltre la larghezza in scala e l'altezza della bitmap:The destination rectangle has an upper-left corner of x and y and a lower-right corner of those values plus the scaled width and height of the bitmap:

La scalabilità uniformeUniform Scaling

Ruotare il telefono lateralmente per visualizzare la bitmap adattata per quell'area:Turn the phone sideways to see the bitmap stretched to that area:

Uniforme di scalabilità orizzontaleUniform Scaling landscape

Il vantaggio di usare lo scale fattore diventa evidente quando si desidera implementare un algoritmo leggermente diverso.The advantage of using this scale factor becomes obvious when you want to implement a slightly different algorithm. Si supponga di che voler conservare le proporzioni della bitmap, ma anche riempire il rettangolo di destinazione.Suppose you want to preserve the bitmap's aspect ratio but also fill the destination rectangle. È l'unico modo è possibile per il ritaglio parte dell'immagine, ma è possibile implementare tale algoritmo semplicemente modificando Math.Min a Math.Max nel codice precedente.The only way this is possible is by cropping part of the image, but you can implement that algorithm simply by changing Math.Min to Math.Max in the above code. Ecco il risultato:Here's the result:

In alternativa all'adattamento dei UniformUniform Scaling alternative

Vengono mantenute le proporzioni della bitmap, ma vengono ritagliate le aree a sinistra e a destra della bitmap.The bitmap's aspect ratio is preserved but areas on the left and right of the bitmap are cropped.

Una funzione di visualizzazione di bitmap versatileA versatile bitmap display function

Ambienti di programmazione basato su XAML (ad esempio UWP e xamarin. Forms) hanno una struttura per espandere o ridurre le dimensioni delle bitmap, mantenendo tuttavia le proporzioni.XAML-based programming environments (such as UWP and Xamarin.Forms) have a facility to expand or shrink the size of bitmaps while preserving their aspect ratios. Sebbene SkiaSharp non include questa funzionalità, è possibile implementarlo manualmente.Although SkiaSharp does not include this feature, you can implement it yourself. Il BitmapExtensions incluso nella classe la SkiaSharpFormsDemos applicazione viene illustrato come.The BitmapExtensions class included in the SkiaSharpFormsDemos application shows how. La classe definisce due nuove DrawBitmap metodi che eseguono il calcolo delle proporzioni.The class defines two new DrawBitmap methods that perform the aspect ratio calculation. Questi nuovi metodi sono metodi di estensione di SKCanvas.These new methods are extension methods of SKCanvas.

Il nuovo DrawBitmap metodi includono un parametro di tipo BitmapStretch, un'enumerazione definita nel BitmapExtensions.cs file:The new DrawBitmap methods include a parameter of type BitmapStretch, an enumeration defined in the BitmapExtensions.cs file:

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

Il None, Fill, Uniform, e UniformToFill membri sono identici a quelli nella piattaforma UWP Stretch enumerazione.The None, Fill, Uniform, and UniformToFill members are the same as those in the UWP Stretch enumeration. Xamarin. Forms simili Aspect enumerazione definisce i membri Fill, AspectFit, e AspectFill.The similar Xamarin.Forms Aspect enumeration defines members Fill, AspectFit, and AspectFill.

Il ridimensionamento uniforme pagina riportata sopra Centra la bitmap all'interno del rettangolo, ma è possibile altre opzioni, ad esempio il posizionamento della bitmap nel lato sinistro o destro del rettangolo, o la parte superiore o inferiore.The Uniform Scaling page shown above centers the bitmap within the rectangle, but you might want other options, such as positioning the bitmap at the left or right side of the rectangle, or the top or bottom. Lo scopo del BitmapAlignment enumerazione:That's the purpose of the BitmapAlignment enumeration:

public enum BitmapAlignment
{
    Start,
    Center,
    End
}

Impostazioni di allineamento non hanno alcun effetto se usato con BitmapStretch.Fill.Alignment settings have no effect when used with BitmapStretch.Fill.

Il primo DrawBitmap funzione di estensione contiene un rettangolo di destinazione, ma nessun rettangolo di origine.The first DrawBitmap extension function contains a destination rectangle but no source rectangle. Valori predefiniti sono definiti in modo che se si desidera che la bitmap al centro, è necessario specificare solo un BitmapStretch membro:Defaults are defined so that if you want the bitmap centered, you need only specify a BitmapStretch member:

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

Lo scopo principale di questo metodo consiste nel calcolare un fattore di scala denominato scale che viene quindi applicato alla larghezza della bitmap e all'altezza quando si chiama il CalculateDisplayRect (metodo).The primary purpose of this method is to calculate a scaling factor named scale that is then applied to the bitmap width and height when calling the CalculateDisplayRect method. Si tratta del metodo che calcola un rettangolo per la visualizzazione della bitmap in base all'allineamento orizzontale e verticale:This is the method that calculates a rectangle for displaying the bitmap based on the horizontal and vertical alignment:

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

Il BitmapExtensions contiene un'ulteriore classe DrawBitmap metodo con un rettangolo di origine per la specifica di un subset della bitmap.The BitmapExtensions class contains an additional DrawBitmap method with a source rectangle for specifying a subset of the bitmap. Questo metodo è simile a quella del primo ad eccezione del fatto che il fattore di scala viene calcolato in base il source rettangolo e quindi applicate al source rettangolo nella chiamata a CalculateDisplayRect:This method is similar to the first one except that the scaling factor is calculated based on the source rectangle, and then applied to the source rectangle in the call to 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);
        }
    }
    ···
}

Il primo di questi due nuovi DrawBitmap metodi è illustrato nel modalità di ridimensionamento pagina.The first of these two new DrawBitmap methods is demonstrated in the Scaling Modes page. Il file XAML include tre Picker gli elementi che consentono di selezionare i membri del BitmapStretch e BitmapAlignment enumerazioni:The XAML file contains three Picker elements that let you select members of the BitmapStretch and BitmapAlignment enumerations:

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

Il file code-behind semplicemente invalida il CanvasView quando una qualsiasi Picker elemento è stato modificato.The code-behind file simply invalidates the CanvasView when any Picker item has changed. Il PaintSurface gestore accede a tre Picker viste per la chiamata di DrawBitmap metodo di estensione:The PaintSurface handler accesses the three Picker views for calling the DrawBitmap extension method:

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

Ecco alcune combinazioni di opzioni:Here are some combinations of options:

Modalità di ridimensionamentoScaling Modes

Il rettangolo Subset pagina ha praticamente allo stesso file XAML modalità di ridimensionamento, ma il file code-behind definisce un sottoinsieme rettangolare della bitmap specificata dal SOURCE campo:The Rectangle Subset page has virtually the same XAML file as Scaling Modes, but the code-behind file defines a rectangular subset of the bitmap given by the SOURCE field:

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

Questa origine rettangolo isola head della monkey, come illustrato nelle schermate illustrate:This rectangle source isolates the monkey's head, as shown in these screenshots:

Rettangolo SubsetRectangle Subset