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:
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:
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.