Condividi tramite


Nozioni di base sulle bitmap in SkiaSharp

Caricare bitmap da varie origini e visualizzarle.

Il supporto delle bitmap in SkiaSharp è piuttosto esteso. Questo articolo illustra solo le nozioni di base: come caricare bitmap e come visualizzarle:

Visualizzazione di due bitmap

Un'esplorazione più approfondita delle bitmap è disponibile nella sezione Bitmap SkiaSharp.

Una bitmap SkiaSharp è un oggetto di tipo SKBitmap. Esistono molti modi per creare una bitmap, ma questo articolo si limita al SKBitmap.Decode metodo , che carica la bitmap da un oggetto .NET Stream .

La pagina Bitmap di base del programma SkiaSharpFormsDemos illustra come caricare bitmap da tre origini diverse:

  • Da Internet
  • Da una risorsa incorporata nell'eseguibile
  • Dalla raccolta foto dell'utente

Tre SKBitmap oggetti per queste tre origini sono definiti come campi nella BasicBitmapsPage classe :

public class BasicBitmapsPage : ContentPage
{
    SKCanvasView canvasView;
    SKBitmap webBitmap;
    SKBitmap resourceBitmap;
    SKBitmap libraryBitmap;

    public BasicBitmapsPage()
    {
        Title = "Basic Bitmaps";

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

Caricamento di una bitmap dal Web

Per caricare una bitmap basata su un URL, è possibile usare la HttpClient classe . È consigliabile creare un'istanza di HttpClient e riutilizzarla, quindi archiviarla come campo:

HttpClient httpClient = new HttpClient();

Quando si usa HttpClient con le applicazioni iOS e Android, è necessario impostare le proprietà del progetto come descritto nei documenti di Transport Layer Security (TLS) 1.2.

Poiché è più pratico usare l'operatore await con HttpClient, il codice non può essere eseguito nel BasicBitmapsPage costruttore. Fa invece parte dell'override OnAppearing . L'URL qui punta a un'area nel sito Web Xamarin con alcune bitmap di esempio. Un pacchetto nel sito Web consente di aggiungere una specifica per ridimensionare la bitmap a una larghezza specifica:

protected override async void OnAppearing()
{
    base.OnAppearing();

    // Load web bitmap.
    string url = "https://developer.xamarin.com/demo/IMG_3256.JPG?width=480";

    try
    {
        using (Stream stream = await httpClient.GetStreamAsync(url))
        using (MemoryStream memStream = new MemoryStream())
        {
            await stream.CopyToAsync(memStream);
            memStream.Seek(0, SeekOrigin.Begin);

            webBitmap = SKBitmap.Decode(memStream);
            canvasView.InvalidateSurface();
        };
    }
    catch
    {
    }
}

Il sistema operativo Android genera un'eccezione quando si usa l'oggetto Stream restituito da GetStreamAsync nel SKBitmap.Decode metodo perché esegue un'operazione lunga su un thread principale. Per questo motivo, il contenuto del file bitmap viene copiato in un MemoryStream oggetto usando CopyToAsync.

Il metodo statico SKBitmap.Decode è responsabile della decodifica dei file bitmap. Funziona con formati bitmap JPEG, PNG e GIF e archivia i risultati in un formato SkiaSharp interno. A questo punto, deve SKCanvasView essere invalidato per consentire al PaintSurface gestore di aggiornare la visualizzazione.

Caricamento di una risorsa bitmap

In termini di codice, l'approccio più semplice per caricare le bitmap consiste nell'includere una risorsa bitmap direttamente nell'applicazione. Il programma SkiaSharpFormsDemos include una cartella denominata Media contenente diversi file bitmap, tra cui uno denominato monkey.png. Per le bitmap archiviate come risorse del programma, è necessario usare la finestra di dialogo Proprietà per assegnare al file un'azionedi compilazione della risorsa incorporata.

Ogni risorsa incorporata ha un ID risorsa costituito dal nome del progetto, dalla cartella e dal nome file, tutti connessi da punti: SkiaSharpFormsDemos.Media.monkey.png. È possibile ottenere l'accesso a questa risorsa specificando tale ID risorsa come argomento per il GetManifestResourceStream metodo della Assembly classe :

string resourceID = "SkiaSharpFormsDemos.Media.monkey.png";
Assembly assembly = GetType().GetTypeInfo().Assembly;

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

Questo Stream oggetto può essere passato direttamente al SKBitmap.Decode metodo .

Caricamento di una bitmap dalla raccolta foto

È anche possibile che l'utente carichi una foto dalla raccolta immagini del dispositivo. Questa struttura non è fornita da Xamarin.Forms se stessa. Il processo richiede un servizio di dipendenza, ad esempio quello descritto nell'articolo Selezione di una foto dalla raccolta immagini.

Il file IPhotoLibrary.cs nel progetto SkiaSharpFormsDemos e i tre file PhotoLibrary.cs nei progetti della piattaforma sono stati adattati da tale articolo. Inoltre, il file di MainActivity.cs Android è stato modificato come descritto nell'articolo e al progetto iOS è stato concesso l'autorizzazione per accedere alla raccolta foto con due righe verso la fine del file info.plist.

Il BasicBitmapsPage costruttore aggiunge un TapGestureRecognizer oggetto a SKCanvasView per ricevere una notifica dei tap. Al ricevimento di un tocco, il Tapped gestore ottiene l'accesso al servizio di dipendenza di selezione immagini e chiama PickPhotoAsync. Se viene restituito un Stream oggetto, viene passato al SKBitmap.Decode metodo :

// Add tap gesture recognizer
TapGestureRecognizer tapRecognizer = new TapGestureRecognizer();
tapRecognizer.Tapped += async (sender, args) =>
{
    // Load bitmap from photo library
    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();

    using (Stream stream = await photoLibrary.PickPhotoAsync())
    {
        if (stream != null)
        {
            libraryBitmap = SKBitmap.Decode(stream);
            canvasView.InvalidateSurface();
        }
    }
};
canvasView.GestureRecognizers.Add(tapRecognizer);

Si noti che il Tapped gestore chiama anche il InvalidateSurface metodo dell'oggetto SKCanvasView . Verrà generata una nuova chiamata al PaintSurface gestore.

Visualizzazione delle bitmap

Il PaintSurface gestore deve visualizzare tre bitmap. Il gestore presuppone che il telefono sia in modalità verticale e divide l'area di disegno verticalmente in tre parti uguali.

La prima bitmap viene visualizzata con il metodo più semplice DrawBitmap . È sufficiente specificare le coordinate X e Y in cui deve essere posizionato l'angolo superiore sinistro della bitmap:

public void DrawBitmap (SKBitmap bitmap, Single x, Single y, SKPaint paint = null)

Anche se è definito un SKPaint parametro, ha un valore predefinito e null può essere ignorato. I pixel della bitmap vengono semplicemente trasferiti ai pixel della superficie di visualizzazione con un mapping uno-a-uno. Verrà visualizzata un'applicazione per questo SKPaint argomento nella sezione successiva di SkiaSharp Transparency.

Un programma può ottenere le dimensioni pixel di una bitmap con le Width proprietà e Height . Queste proprietà consentono al programma di calcolare le coordinate per posizionare la bitmap al centro del terzo superiore dell'area di disegno:

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

    canvas.Clear();

    if (webBitmap != null)
    {
        float x = (info.Width - webBitmap.Width) / 2;
        float y = (info.Height / 3 - webBitmap.Height) / 2;
        canvas.DrawBitmap(webBitmap, x, y);
    }
    ...
}

Le altre due bitmap vengono visualizzate con una versione di DrawBitmap con un SKRect parametro :

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

Una terza versione di DrawBitmap ha due SKRect argomenti per specificare un subset rettangolare della bitmap da visualizzare, ma tale versione non viene usata in questo articolo.

Ecco il codice per visualizzare la bitmap caricata da una bitmap di risorse incorporata:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    if (resourceBitmap != null)
    {
        canvas.DrawBitmap(resourceBitmap,
            new SKRect(0, info.Height / 3, info.Width, 2 * info.Height / 3));
    }
    ...
}

La bitmap viene estesa alle dimensioni del rettangolo, motivo per cui la scimmia viene estesa orizzontalmente in questi screenshot:

Screenshot triplo della pagina Bitmap di base

La terza immagine, che è possibile vedere solo se si esegue il programma e si carica una foto dalla propria raccolta immagini, viene visualizzata anche all'interno di un rettangolo, ma la posizione e le dimensioni del rettangolo vengono modificate per mantenere le proporzioni della bitmap. Questo calcolo è un po' più complesso perché richiede il calcolo di un fattore di ridimensionamento in base alle dimensioni della bitmap e del rettangolo di destinazione e al centro del rettangolo in tale area:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    if (libraryBitmap != null)
    {
        float scale = Math.Min((float)info.Width / libraryBitmap.Width,
                               info.Height / 3f / libraryBitmap.Height);

        float left = (info.Width - scale * libraryBitmap.Width) / 2;
        float top = (info.Height / 3 - scale * libraryBitmap.Height) / 2;
        float right = left + scale * libraryBitmap.Width;
        float bottom = top + scale * libraryBitmap.Height;
        SKRect rect = new SKRect(left, top, right, bottom);
        rect.Offset(0, 2 * info.Height / 3);

        canvas.DrawBitmap(libraryBitmap, rect);
    }
    else
    {
        using (SKPaint paint = new SKPaint())
        {
            paint.Color = SKColors.Blue;
            paint.TextAlign = SKTextAlign.Center;
            paint.TextSize = 48;

            canvas.DrawText("Tap to load bitmap",
                info.Width / 2, 5 * info.Height / 6, paint);
        }
    }
}

Se non è ancora stata caricata alcuna bitmap dalla raccolta immagini, il else blocco visualizza del testo per chiedere all'utente di toccare lo schermo.

È possibile visualizzare bitmap con vari gradi di trasparenza e l'articolo successivo su SkiaSharp Transparency descrive come.