Creazione e disegno di bitmap SkiaSharp
Si è visto come un'applicazione può caricare bitmap dal Web, dalle risorse dell'applicazione e dalla raccolta foto dell'utente. È anche possibile creare nuove bitmap all'interno dell'applicazione. L'approccio più semplice prevede uno dei costruttori di SKBitmap
:
SKBitmap bitmap = new SKBitmap(width, height);
I width
parametri e height
sono numeri interi e specificano le dimensioni pixel della bitmap. Questo costruttore crea una bitmap a colori intero con quattro byte per pixel: ognuno dei componenti rosso, verde, blu e alfa (opacità).
Dopo aver creato una nuova bitmap, è necessario ottenere qualcosa sulla superficie della bitmap. Questa operazione viene eseguita in genere in uno dei due modi seguenti:
- Disegnare sulla bitmap usando metodi di disegno standard
Canvas
. - Accedere direttamente ai bit pixel.
Questo articolo illustra il primo approccio:
Il secondo approccio è illustrato nell'articolo Accesso ai pixel bitmap SkiaSharp.
Disegno sulla bitmap
Il disegno sulla superficie di una bitmap è identico a quello di un disegno su una visualizzazione video. Per disegnare su una visualizzazione video, si ottiene un SKCanvas
oggetto dagli argomenti dell'evento PaintSurface
. Per disegnare su una bitmap, creare un SKCanvas
oggetto usando il SKCanvas
costruttore :
SKCanvas canvas = new SKCanvas(bitmap);
Al termine del disegno sulla bitmap, è possibile eliminare l'oggetto SKCanvas
. Per questo motivo, il SKCanvas
costruttore viene in genere chiamato in un'istruzione using
:
using (SKCanvas canvas = new SKCanvas(bitmap))
{
··· // call drawing function
}
È quindi possibile visualizzare la bitmap. In un secondo momento, il programma può creare un nuovo SKCanvas
oggetto basato su quella stessa bitmap e disegnare su di esso altri.
La pagina Hello Bitmap nell'applicazione di esempio scrive il testo "Hello, Bitmap!" in una bitmap e quindi visualizza tale bitmap più volte.
Il costruttore di HelloBitmapPage
inizia creando un SKPaint
oggetto per la visualizzazione del testo. Determina le dimensioni di una stringa di testo e crea una bitmap con tali dimensioni. Crea quindi un SKCanvas
oggetto basato su tale bitmap, chiama Clear
e quindi chiama DrawText
. È sempre consigliabile chiamare Clear
con una nuova bitmap perché una bitmap appena creata potrebbe contenere dati casuali.
Il costruttore termina creando un SKCanvasView
oggetto per visualizzare la bitmap:
public partial class HelloBitmapPage : ContentPage
{
const string TEXT = "Hello, Bitmap!";
SKBitmap helloBitmap;
public HelloBitmapPage()
{
Title = TEXT;
// Create bitmap and draw on it
using (SKPaint textPaint = new SKPaint { TextSize = 48 })
{
SKRect bounds = new SKRect();
textPaint.MeasureText(TEXT, ref bounds);
helloBitmap = new SKBitmap((int)bounds.Right,
(int)bounds.Height);
using (SKCanvas bitmapCanvas = new SKCanvas(helloBitmap))
{
bitmapCanvas.Clear();
bitmapCanvas.DrawText(TEXT, 0, -bounds.Top, textPaint);
}
}
// Create SKCanvasView to view result
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(SKColors.Aqua);
for (float y = 0; y < info.Height; y += helloBitmap.Height)
for (float x = 0; x < info.Width; x += helloBitmap.Width)
{
canvas.DrawBitmap(helloBitmap, x, y);
}
}
}
Il PaintSurface
gestore esegue il rendering della bitmap più volte in righe e colonne della visualizzazione. Si noti che il Clear
metodo nel PaintSurface
gestore ha un argomento , SKColors.Aqua
che colora lo sfondo della superficie di visualizzazione:
L'aspetto dello sfondo aqua rivela che la bitmap è trasparente ad eccezione del testo.
Cancellazione e trasparenza
La visualizzazione della pagina Hello Bitmap dimostra che la bitmap creata dal programma è trasparente, ad eccezione del testo nero. Ecco perché il colore azzurro della superficie di visualizzazione si mostra attraverso.
La documentazione dei Clear
metodi di SKCanvas
li descrive con l'istruzione : "Sostituisce tutti i pixel nella clip corrente dell'area di disegno". L'uso della parola "sostituisce" rivela una caratteristica importante di questi metodi: tutti i metodi di disegno di SKCanvas
aggiungere qualcosa alla superficie di visualizzazione esistente. I Clear
metodi sostituiscono ciò che è già presente.
Clear
esiste in due versioni diverse:
Il
Clear
metodo con unSKColor
parametro sostituisce i pixel della superficie di visualizzazione con i pixel di tale colore.Il
Clear
metodo senza parametri sostituisce i pixel con ilSKColors.Empty
colore, ovvero un colore in cui tutti i componenti (rosso, verde, blu e alfa) sono impostati su zero. Questo colore viene talvolta definito "nero trasparente".
La chiamata Clear
senza argomenti in una nuova bitmap inizializza l'intera bitmap in modo che sia completamente trasparente. Qualsiasi elemento successivamente disegnato sulla bitmap in genere sarà opaco o parzialmente opaco.
Ecco qualcosa da provare: nella pagina Hello Bitmap sostituire il Clear
metodo applicato a bitmapCanvas
con questo:
bitmapCanvas.Clear(new SKColor(255, 0, 0, 128));
L'ordine dei parametri del SKColor
costruttore è rosso, verde, blu e alfa, in cui ogni valore può variare da 0 a 255. Tenere presente che un valore alfa pari a 0 è trasparente, mentre un valore alfa pari a 255 è opaco.
Il valore (255, 0, 0, 128) cancella i pixel bitmap in pixel rossi con opacità del 50%. Ciò significa che lo sfondo bitmap è semitrasparente. Lo sfondo rosso semitrasparente della bitmap si combina con lo sfondo aqua della superficie di visualizzazione per creare uno sfondo grigio.
Provare a impostare il colore del testo su nero trasparente inserendo l'assegnazione seguente nell'inizializzatore SKPaint
:
Color = new SKColor(0, 0, 0, 0)
Si potrebbe pensare che questo testo trasparente creerebbe aree completamente trasparenti della bitmap attraverso cui si vedrà lo sfondo aqua della superficie di visualizzazione. Ma questo non è così. Il testo viene disegnato sopra ciò che è già presente nella bitmap. Il testo trasparente non sarà affatto visibile.
Nessun Draw
metodo rende mai più trasparente una bitmap. Solo Clear
in grado di farlo.
Tipi di colori bitmap
Il costruttore più semplice SKBitmap
consente di specificare una larghezza e un'altezza di un numero intero di pixel per la bitmap. Altri SKBitmap
costruttori sono più complessi. Questi costruttori richiedono argomenti di due tipi di enumerazione: SKColorType
e SKAlphaType
. Altri costruttori usano la SKImageInfo
struttura , che consolida queste informazioni.
L'enumerazione SKColorType
ha 9 membri. Ognuno di questi membri descrive un modo specifico per archiviare i pixel bitmap:
Unknown
Alpha8
— ogni pixel è a 8 bit, che rappresenta un valore alfa da completamente trasparente a completamente opacoRgb565
— ogni pixel è a 16 bit, 5 bit per rosso e blu e 6 per il verdeArgb4444
— ogni pixel è di 16 bit, 4 per alfa, rosso, verde e bluRgba8888
— ogni pixel è di 32 bit, 8 per rosso, verde, blu e alfaBgra8888
— ogni pixel è di 32 bit, 8 per blu, verde, rosso e alfaIndex8
— ogni pixel è a 8 bit e rappresenta un indice in unSKColorTable
Gray8
— ogni pixel è a 8 bit che rappresentano una sfumatura grigia dal nero al biancoRgbaF16
— ogni pixel è a 64 bit, con rosso, verde, blu e alfa in un formato a virgola mobile a 16 bit
I due formati in cui ogni pixel è 32 pixel (4 byte) sono spesso chiamati formati a colori completi. Molti degli altri formati datano da un momento in cui i video visualizzano se stessi non erano in grado di colori completi. Le bitmap di colore limitato erano adeguate per questi schermi e consentivano alle bitmap di occupare meno spazio in memoria.
In questi giorni, i programmatori usano quasi sempre bitmap a colori completi e non preoccupano altri formati. L'eccezione è il RgbaF16
formato, che consente una risoluzione dei colori maggiore rispetto ai formati a colori completi. Tuttavia, questo formato viene usato per scopi specializzati, ad esempio l'imaging medico, e non ha molto senso quando usato con schermi standard a colori completi.
Questa serie di articoli si limiterà ai SKBitmap
formati di colore utilizzati per impostazione predefinita quando non viene specificato alcun SKColorType
membro. Questo formato predefinito è basato sulla piattaforma sottostante. Per le piattaforme supportate da Xamarin.Forms, il tipo di colore predefinito è:
Rgba8888
per iOS e AndroidBgra8888
per la piattaforma UWP
L'unica differenza è l'ordine dei 4 byte in memoria e questo diventa un problema solo quando si accede direttamente ai bit pixel. Questo non diventerà importante fino a quando non si arriva all'articolo Accesso ai pixel bitmap skiaSharp.
L'enumerazione SKAlphaType
ha quattro membri:
Unknown
Opaque
— la bitmap non ha trasparenzaPremul
— i componenti di colore vengono pre-moltiplicati per il componente alfaUnpremul
— i componenti di colore non vengono pre-moltiplicati per il componente alfa
Ecco un pixel bitmap rosso a 4 byte con trasparenza del 50%, con i byte visualizzati nell'ordine rosso, verde, blu, alfa:
0xFF 0x00 0x00 0x80
Quando viene eseguito il rendering di una bitmap contenente pixel semitrasparti in una superficie di visualizzazione, i componenti di colore di ogni pixel bitmap devono essere moltiplicati per il valore alfa del pixel e i componenti di colore del pixel corrispondente della superficie di visualizzazione devono essere moltiplicati per 255 meno il valore alfa. I due pixel possono quindi essere combinati. Il rendering della bitmap può essere più veloce se i componenti di colore nei pixel bitmap sono già stati pre-mulitplied dal valore alfa. Lo stesso pixel rosso verrebbe archiviato come segue in un formato pre-moltiplicato:
0x80 0x00 0x00 0x80
Questo miglioramento delle prestazioni è il motivo per cui SkiaSharp
le bitmap vengono create per impostazione predefinita con un Premul
formato. Ma anche in questo caso, diventa necessario conoscerlo solo quando si accede e si modificano i bit di pixel.
Disegno su bitmap esistenti
Non è necessario creare una nuova bitmap per disegnare su di esso. È anche possibile disegnare su una bitmap esistente.
La pagina Monkey Moustache usa il relativo costruttore per caricare l'immagine MonkeyFace.png . Crea quindi un SKCanvas
oggetto basato su tale bitmap e usa SKPaint
oggetti e SKPath
per disegnare un baffo su di esso:
public partial class MonkeyMoustachePage : ContentPage
{
SKBitmap monkeyBitmap;
public MonkeyMoustachePage()
{
Title = "Monkey Moustache";
monkeyBitmap = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.MonkeyFace.png");
// Create canvas based on bitmap
using (SKCanvas canvas = new SKCanvas(monkeyBitmap))
{
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Stroke;
paint.Color = SKColors.Black;
paint.StrokeWidth = 24;
paint.StrokeCap = SKStrokeCap.Round;
using (SKPath path = new SKPath())
{
path.MoveTo(380, 390);
path.CubicTo(560, 390, 560, 280, 500, 280);
path.MoveTo(320, 390);
path.CubicTo(140, 390, 140, 280, 200, 280);
canvas.DrawPath(path, paint);
}
}
}
// Create SKCanvasView to view result
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(monkeyBitmap, info.Rect, BitmapStretch.Uniform);
}
}
Il costruttore termina creando un SKCanvasView
oggetto il cui PaintSurface
gestore visualizza semplicemente il risultato:
Copia e modifica di bitmap
I metodi di SKCanvas
che è possibile usare per disegnare su una bitmap includono DrawBitmap
. Ciò significa che è possibile disegnare una bitmap su un'altra, in genere modificandola in qualche modo.
Il modo più versatile per modificare una bitmap consiste nell'accedere ai bit di pixel effettivi, un oggetto trattato nell'articolo Accesso ai pixel bitmap SkiaSharp. Esistono tuttavia molte altre tecniche per modificare le bitmap che non richiedono l'accesso ai bit pixel.
La bitmap seguente inclusa nell'applicazione di esempio è larga 360 pixel e 480 pixel in altezza:
Si supponga di non aver ricevuto l'autorizzazione dalla scimmia a sinistra per pubblicare questa fotografia. Una soluzione consiste nell'oscurare il viso della scimmia usando una tecnica denominata pixelizzazione. I pixel del viso vengono sostituiti con blocchi di colore in modo da non rendere disponibili le caratteristiche. I blocchi di colore sono in genere derivati dall'immagine originale mediando i colori dei pixel corrispondenti a questi blocchi. Ma non è necessario eseguire questa media. Si verifica automaticamente quando si copia una bitmap in una dimensione pixel più piccola.
La faccia della scimmia sinistra occupa circa un'area quadrata di 72 pixel con un angolo superiore sinistro al punto (112, 238). Sostituiamo l'area quadrata di 72 pixel con una matrice di blocchi colorati 9 per 9, ognuno dei quali è quadrato di 8 per 8 pixel.
La pagina Pixelize Image viene caricata in tale bitmap e crea prima di tutto una piccola bitmap quadrata di 9 pixel denominata faceBitmap
. Questa è una destinazione per copiare solo la faccia della scimmia. Il rettangolo di destinazione è solo un quadrato di 9 pixel, ma il rettangolo di origine è quadrato di 72 pixel. Ogni blocco di pixel di origine da 8 a 8 viene consolidato fino a un solo pixel mediando i colori.
Il passaggio successivo consiste nel copiare la bitmap originale in una nuova bitmap con le stesse dimensioni denominate pixelizedBitmap
. Il minuscolo faceBitmap
viene quindi copiato su quello con un rettangolo di destinazione quadrato a 72 pixel in modo che ogni pixel di faceBitmap
venga espanso fino a 8 volte le dimensioni:
public class PixelizedImagePage : ContentPage
{
SKBitmap pixelizedBitmap;
public PixelizedImagePage ()
{
Title = "Pixelize Image";
SKBitmap originalBitmap = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.MountainClimbers.jpg");
// Create tiny bitmap for pixelized face
SKBitmap faceBitmap = new SKBitmap(9, 9);
// Copy subset of original bitmap to that
using (SKCanvas canvas = new SKCanvas(faceBitmap))
{
canvas.Clear();
canvas.DrawBitmap(originalBitmap,
new SKRect(112, 238, 184, 310), // source
new SKRect(0, 0, 9, 9)); // destination
}
// Create full-sized bitmap for copy
pixelizedBitmap = new SKBitmap(originalBitmap.Width, originalBitmap.Height);
using (SKCanvas canvas = new SKCanvas(pixelizedBitmap))
{
canvas.Clear();
// Draw original in full size
canvas.DrawBitmap(originalBitmap, new SKPoint());
// Draw tiny bitmap to cover face
canvas.DrawBitmap(faceBitmap,
new SKRect(112, 238, 184, 310)); // destination
}
// Create SKCanvasView to view result
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(pixelizedBitmap, info.Rect, BitmapStretch.Uniform);
}
}
Il costruttore termina creando un oggetto SKCanvasView
per visualizzare il risultato:
Rotazione delle bitmap
Un'altra attività comune è la rotazione di bitmap. Ciò è particolarmente utile quando si recuperano bitmap da una libreria foto i Telefono o iPad. A meno che il dispositivo non sia stato mantenuto in un particolare orientamento quando è stata scattata la foto, è probabile che l'immagine sia capovolta o laterale.
L'impostazione di una bitmap a capovolto richiede la creazione di un'altra bitmap con le stesse dimensioni del primo e quindi l'impostazione di una trasformazione per ruotare di 180 gradi durante la copia del primo al secondo. In tutti gli esempi di questa sezione, bitmap
è l'oggetto SKBitmap
che è necessario ruotare:
SKBitmap rotatedBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (SKCanvas canvas = new SKCanvas(rotatedBitmap))
{
canvas.Clear();
canvas.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2);
canvas.DrawBitmap(bitmap, new SKPoint());
}
Quando si ruota di 90 gradi, è necessario creare una bitmap con dimensioni diverse rispetto all'originale scambiando l'altezza e la larghezza. Ad esempio, se la bitmap originale è larga 1200 pixel e 800 pixel di altezza, la bitmap ruotata è larga 800 pixel e 1200 pixel di larghezza. Impostare la conversione e la rotazione in modo che la bitmap venga ruotata attorno all'angolo superiore sinistro e quindi spostata in visualizzazione. Tenere presente che i Translate
metodi e RotateDegrees
vengono chiamati nell'ordine opposto del modo in cui vengono applicati. Ecco il codice per la rotazione di 90 gradi in senso orario:
SKBitmap rotatedBitmap = new SKBitmap(bitmap.Height, bitmap.Width);
using (SKCanvas canvas = new SKCanvas(rotatedBitmap))
{
canvas.Clear();
canvas.Translate(bitmap.Height, 0);
canvas.RotateDegrees(90);
canvas.DrawBitmap(bitmap, new SKPoint());
}
Ed ecco una funzione simile per la rotazione di 90 gradi in senso antiorario:
SKBitmap rotatedBitmap = new SKBitmap(bitmap.Height, bitmap.Width);
using (SKCanvas canvas = new SKCanvas(rotatedBitmap))
{
canvas.Clear();
canvas.Translate(0, bitmap.Width);
canvas.RotateDegrees(-90);
canvas.DrawBitmap(bitmap, new SKPoint());
}
Questi due metodi vengono usati nelle pagine photo puzzle descritte nell'articolo Ritagliare le bitmap SkiaSharp.
Un programma che consente all'utente di ruotare una bitmap in incrementi di 90 gradi richiede l'implementazione di una sola funzione per la rotazione di 90 gradi. L'utente può quindi ruotare in qualsiasi incremento di 90 gradi eseguendo ripetutamente questa funzione.
Un programma può anche ruotare una bitmap in base a qualsiasi quantità. Un approccio semplice consiste nel modificare la funzione che ruota di 180 gradi sostituendo 180 con una variabile generalizzata angle
:
SKBitmap rotatedBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (SKCanvas canvas = new SKCanvas(rotatedBitmap))
{
canvas.Clear();
canvas.RotateDegrees(angle, bitmap.Width / 2, bitmap.Height / 2);
canvas.DrawBitmap(bitmap, new SKPoint());
}
Tuttavia, nel caso generale, questa logica ritaglierà gli angoli della bitmap ruotata. Un approccio migliore consiste nel calcolare le dimensioni della bitmap ruotata usando i trigonometria per includere tali angoli.
Questo trigonometria viene visualizzato nella pagina Rotazione bitmap. Il file XAML crea un'istanza SKCanvasView
di e un oggetto Slider
che può variare da 0 a 360 gradi con un Label
oggetto che mostra il valore corrente:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Bitmaps.BitmapRotatorPage"
Title="Bitmap Rotator">
<StackLayout>
<skia:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Slider x:Name="slider"
Maximum="360"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='Rotate by {0:F0}°'}"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
Il file code-behind carica una risorsa bitmap e lo salva come campo di sola lettura statico denominato originalBitmap
. La bitmap visualizzata nel PaintSurface
gestore è rotatedBitmap
, che inizialmente è impostata su originalBitmap
:
public partial class BitmapRotatorPage : ContentPage
{
static readonly SKBitmap originalBitmap =
BitmapExtensions.LoadBitmapResource(typeof(BitmapRotatorPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
SKBitmap rotatedBitmap = originalBitmap;
public BitmapRotatorPage ()
{
InitializeComponent ();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(rotatedBitmap, info.Rect, BitmapStretch.Uniform);
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
double angle = args.NewValue;
double radians = Math.PI * angle / 180;
float sine = (float)Math.Abs(Math.Sin(radians));
float cosine = (float)Math.Abs(Math.Cos(radians));
int originalWidth = originalBitmap.Width;
int originalHeight = originalBitmap.Height;
int rotatedWidth = (int)(cosine * originalWidth + sine * originalHeight);
int rotatedHeight = (int)(cosine * originalHeight + sine * originalWidth);
rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
using (SKCanvas canvas = new SKCanvas(rotatedBitmap))
{
canvas.Clear(SKColors.LightPink);
canvas.Translate(rotatedWidth / 2, rotatedHeight / 2);
canvas.RotateDegrees((float)angle);
canvas.Translate(-originalWidth / 2, -originalHeight / 2);
canvas.DrawBitmap(originalBitmap, new SKPoint());
}
canvasView.InvalidateSurface();
}
}
Il ValueChanged
gestore dell'oggetto Slider
esegue le operazioni che creano un nuovo rotatedBitmap
oggetto in base all'angolo di rotazione. La nuova larghezza e altezza si basano su valori assoluti di sines e coseni delle larghezze e altezze originali. Le trasformazioni utilizzate per disegnare la bitmap originale sulla bitmap ruotata spostano il centro bitmap originale nell'origine, quindi ruotarlo in base al numero specificato di gradi e quindi traslarlo al centro della bitmap ruotata. I Translate
metodi e RotateDegrees
vengono chiamati nell'ordine opposto rispetto al modo in cui vengono applicati.
Si noti l'uso del Clear
metodo per rendere lo sfondo di rotatedBitmap
un rosa chiaro. Si tratta esclusivamente di illustrare le dimensioni di rotatedBitmap
sullo schermo:
La bitmap ruotata è sufficiente per includere l'intera bitmap originale, ma non più grande.
Capovolgimento di bitmap
Un'altra operazione comunemente eseguita sulle bitmap è detta capovolgimento. Concettualmente, la bitmap viene ruotata in tre dimensioni attorno a un asse verticale o all'asse orizzontale attraverso il centro della bitmap. Il capovolgimento verticale crea un'immagine speculare.
La pagina Bitmap Flipper nell'applicazione di esempio illustra questi processi. Il file XAML contiene un e SKCanvasView
due pulsanti per capovolgere verticalmente e orizzontalmente:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Bitmaps.BitmapFlipperPage"
Title="Bitmap Flipper">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<skia:SKCanvasView x:Name="canvasView"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
PaintSurface="OnCanvasViewPaintSurface" />
<Button Text="Flip Vertical"
Grid.Row="1" Grid.Column="0"
Margin="0, 10"
Clicked="OnFlipVerticalClicked" />
<Button Text="Flip Horizontal"
Grid.Row="1" Grid.Column="1"
Margin="0, 10"
Clicked="OnFlipHorizontalClicked" />
</Grid>
</ContentPage>
Il file code-behind implementa queste due operazioni nei Clicked
gestori per i pulsanti:
public partial class BitmapFlipperPage : ContentPage
{
SKBitmap bitmap =
BitmapExtensions.LoadBitmapResource(typeof(BitmapRotatorPage),
"SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");
public BitmapFlipperPage()
{
InitializeComponent();
}
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, BitmapStretch.Uniform);
}
void OnFlipVerticalClicked(object sender, ValueChangedEventArgs args)
{
SKBitmap flippedBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (SKCanvas canvas = new SKCanvas(flippedBitmap))
{
canvas.Clear();
canvas.Scale(-1, 1, bitmap.Width / 2, 0);
canvas.DrawBitmap(bitmap, new SKPoint());
}
bitmap = flippedBitmap;
canvasView.InvalidateSurface();
}
void OnFlipHorizontalClicked(object sender, ValueChangedEventArgs args)
{
SKBitmap flippedBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (SKCanvas canvas = new SKCanvas(flippedBitmap))
{
canvas.Clear();
canvas.Scale(1, -1, 0, bitmap.Height / 2);
canvas.DrawBitmap(bitmap, new SKPoint());
}
bitmap = flippedBitmap;
canvasView.InvalidateSurface();
}
}
Il capovolgimento verticale viene eseguito da una trasformazione di ridimensionamento con un fattore di ridimensionamento orizzontale pari a –1. Il centro di ridimensionamento è il centro verticale della bitmap. Il capovolgimento orizzontale è una trasformazione di ridimensionamento con un fattore di ridimensionamento verticale pari a -1.
Come si può vedere dalla lettera invertita sulla camicia della scimmia, capovolgimento non è uguale alla rotazione. Tuttavia, come dimostra lo screenshot UWP a destra, capovolgere sia orizzontalmente che verticalmente è uguale alla rotazione di 180 gradi:
Un'altra attività comune che può essere gestita usando tecniche simili consiste nel ritagliare una bitmap in un subset rettangolare. Questo articolo è descritto nell'articolo successivo ritagliare le bitmap SkiaSharp.