Affichage des bitmaps SkiaSharp
L’objet des bitmaps SkiaSharp a été introduit dans l’article Bitmap Basics in SkiaSharp. Cet article a montré trois façons de charger des bitmaps et trois façons d’afficher des bitmaps. Cet article passe en revue les techniques de chargement des bitmaps et approfondit l’utilisation des DrawBitmap
méthodes de SKCanvas
.
Les DrawBitmapLattice
méthodes et DrawBitmapNinePatch
les méthodes sont décrites dans l’article Affichage segmenté des bitmaps SkiaSharp.
Les exemples de cette page proviennent de l’exemple d’application. Dans la page d’accueil de cette application, choisissez Bitmaps SkiaSharp, puis accédez à la section Affichage des bitmaps .
Chargement d’une bitmap
Une bitmap utilisée par une application SkiaSharp provient généralement d’une des trois sources différentes :
- À partir d’Internet
- À partir d’une ressource incorporée dans l’exécutable
- À partir de la bibliothèque de photos de l’utilisateur
Il est également possible pour une application SkiaSharp de créer une image bitmap, puis de dessiner dessus ou de définir les bits bitmap de manière algorithmique. Ces techniques sont abordées dans les articles Création et dessin sur les bitmaps SkiaSharp et l’accès aux pixels bitmap SkiaSharp.
Dans les trois exemples de code suivants de chargement d’une bitmap, la classe est supposée contenir un champ de type SKBitmap
:
SKBitmap bitmap;
Comme indiqué dans l’article Bitmap Basics in SkiaSharp, la meilleure façon de charger une bitmap sur Internet est avec la HttpClient
classe. Une seule instance de la classe peut être définie en tant que champ :
HttpClient httpClient = new HttpClient();
Lorsque vous utilisez HttpClient
des applications iOS et Android, vous devez définir les propriétés du projet comme décrit dans les documents sur TLS (Transport Layer Security) 1.2.
Le code qui utilise HttpClient
souvent implique l’opérateur await
. Il doit donc résider dans une async
méthode :
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
{
···
}
Notez que l’objet Stream
obtenu GetStreamAsync
est copié dans un MemoryStream
. Android n’autorise pas le Stream
traitement par HttpClient
le thread principal, sauf dans les méthodes asynchrones.
Le SKBitmap.Decode
fait beaucoup de travail : l’objet Stream
passé à celui-ci fait référence à un bloc de mémoire contenant une image bitmap entière dans l’un des formats de fichier bitmap courants, généralement JPEG, PNG ou GIF. La Decode
méthode doit déterminer le format, puis décoder le fichier bitmap dans le propre format bitmap interne de SkiaSharp.
Une fois que votre code a appelé SKBitmap.Decode
, il invalidera probablement le CanvasView
gestionnaire afin que le PaintSurface
gestionnaire puisse afficher l’image bitmap nouvellement chargée.
La deuxième façon de charger une bitmap consiste à inclure la bitmap en tant que ressource incorporée dans la bibliothèque .NET Standard référencée par les projets de plateforme individuels. Un ID de ressource est passé à la GetManifestResourceStream
méthode. Cet ID de ressource se compose du nom de l’assembly, du nom du dossier et du nom de fichier de la ressource séparés par des points :
string resourceID = "assemblyName.folderName.fileName";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
···
}
Les fichiers bitmap peuvent également être stockés en tant que ressources dans le projet de plateforme individuelle pour iOS, Android et le plateforme Windows universelle (UWP). Toutefois, le chargement de ces bitmaps nécessite du code qui se trouve dans le projet de plateforme.
Une troisième approche pour obtenir une bitmap provient de la bibliothèque d’images de l’utilisateur. Le code suivant utilise un service de dépendance inclus dans l’exemple d’application. La bibliothèque SkiaSharpFormsDemo .NET Standard inclut l’interface IPhotoLibrary
, tandis que chacun des projets de plateforme contient une PhotoLibrary
classe qui implémente cette interface.
IPhotoicturePicker picturePicker = DependencyService.Get<IPhotoLibrary>();
using (Stream stream = await picturePicker.GetImageStreamAsync())
{
if (stream != null)
{
bitmap = SKBitmap.Decode(stream);
···
}
}
En règle générale, ce code invalide également la CanvasView
façon dont le PaintSurface
gestionnaire peut afficher la nouvelle bitmap.
La SKBitmap
classe définit plusieurs propriétés utiles, notamment Width
et Height
, qui révèlent les dimensions de pixels de la bitmap, ainsi que de nombreuses méthodes, y compris les méthodes permettant de créer des bitmaps, de les copier et d’exposer les bits de pixels.
Affichage en dimensions de pixels
La classe SkiaSharp Canvas
définit quatre DrawBitmap
méthodes. Ces méthodes permettent aux bitmaps d’être affichées de deux façons fondamentalement différentes :
- La spécification d’une
SKPoint
valeur (ou de valeurs distinctesx
)y
affiche la bitmap dans ses dimensions de pixels. Les pixels de la bitmap sont mappés directement aux pixels de l’affichage vidéo. - La spécification d’un rectangle entraîne l’étirement de la bitmap à la taille et à la forme du rectangle.
Vous affichez une bitmap dans ses dimensions de pixels à l’aide DrawBitmap
d’un SKPoint
paramètre ou DrawBitmap
avec des paramètres distincts et y
des x
paramètres :
DrawBitmap(SKBitmap bitmap, SKPoint pt, SKPaint paint = null)
DrawBitmap(SKBitmap bitmap, float x, float y, SKPaint paint = null)
Ces deux méthodes sont fonctionnellement identiques. Le point spécifié indique l’emplacement du coin supérieur gauche de la bitmap par rapport au canevas. Étant donné que la résolution de pixels des appareils mobiles est si élevée, les bitmaps plus petites apparaissent généralement assez minuscules sur ces appareils.
Le paramètre facultatif SKPaint
vous permet d’afficher la bitmap à l’aide de la transparence. Pour ce faire, créez un SKPaint
objet et définissez la Color
propriété sur n’importe quelle SKColor
valeur avec un canal alpha inférieur à 1. Par exemple :
paint.Color = new SKColor(0, 0, 0, 0x80);
Le 0x80 passé comme dernier argument indique une transparence de 50 %. Vous pouvez également définir un canal alpha sur l’une des couleurs prédéfinies :
paint.Color = SKColors.Red.WithAlpha(0x80);
Toutefois, la couleur elle-même n’est pas pertinente. Seul le canal alpha est examiné lorsque vous utilisez l’objet SKPaint
dans un DrawBitmap
appel.
L’objet SKPaint
joue également un rôle lors de l’affichage de bitmaps à l’aide de modes de fusion ou d’effets de filtre. Ils sont présentés dans les articles SkiaSharp compositing et blend modes et filtres d’images SkiaSharp.
La page Dimensions de pixels de l’exemple de programme affiche une ressource bitmap de 320 pixels de large de 240 pixels :
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);
}
}
Le PaintSurface
gestionnaire centre la bitmap en calculant x
et y
en fonction des valeurs en fonction des dimensions de pixels de l’aire d’affichage et des dimensions de pixels de la bitmap :
Si l’application souhaite afficher la bitmap dans son coin supérieur gauche, elle passe simplement les coordonnées de (0, 0).
Méthode de chargement des bitmaps de ressources
La plupart des exemples à venir devront charger des ressources bitmap. La classe statique BitmapExtensions
dans l’exemple de solution contient une méthode pour vous aider :
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);
}
}
···
}
Notez le Type
paramètre. Il peut s’agir de l’objet Type
associé à n’importe quel type dans l’assembly qui stocke la ressource bitmap.
Cette LoadBitmapResource
méthode sera utilisée dans tous les exemples suivants qui nécessitent des ressources bitmap.
Étirement pour remplir un rectangle
La SKCanvas
classe définit également une DrawBitmap
méthode qui restitue la bitmap dans un rectangle et une autre DrawBitmap
méthode qui restitue un sous-ensemble rectangulaire de la bitmap dans un rectangle :
DrawBitmap(SKBitmap bitmap, SKRect dest, SKPaint paint = null)
DrawBitmap(SKBitmap bitmap, SKRect source, SKRect dest, SKPaint paint = null)
Dans les deux cas, la bitmap est étirée pour remplir le rectangle nommé dest
. Dans la deuxième méthode, le source
rectangle vous permet de sélectionner un sous-ensemble de la bitmap. Le dest
rectangle est relatif à l’appareil de sortie ; le source
rectangle est relatif à la bitmap.
La page Remplissage rectangle illustre la première de ces deux méthodes en affichant la même bitmap utilisée dans l’exemple précédent dans un rectangle de la même taille que le canevas :
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);
}
}
Notez l’utilisation de la nouvelle BitmapExtensions.LoadBitmapResource
méthode pour définir le SKBitmap
champ. Le rectangle de destination est obtenu à partir de la Rect
propriété de SKImageInfo
, qui déséribe la taille de l’aire d’affichage :
Ce n’est généralement pas ce que vous voulez. L’image est déformée en étant étirée différemment dans les directions horizontales et verticales. Lors de l’affichage d’une bitmap dans une autre taille que sa taille de pixel, vous souhaitez généralement conserver le rapport d’aspect d’origine de la bitmap.
Étirement tout en préservant les proportions
L’étirement d’une bitmap tout en préservant le rapport d’aspect est un processus également appelé mise à l’échelle uniforme. Ce terme suggère une approche algorithmique. Une solution possible s’affiche dans la page Mise à l’échelle uniforme :
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);
}
}
Le PaintSurface
gestionnaire calcule un scale
facteur qui correspond au minimum au ratio de la largeur d’affichage et de la hauteur à la largeur et à la hauteur bitmap. Les x
valeurs y
et les valeurs peuvent ensuite être calculées pour centrer la bitmap mise à l’échelle dans la largeur et la hauteur d’affichage. Le rectangle de destination comporte un angle supérieur gauche et x
y
un coin inférieur droit de ces valeurs, ainsi que la largeur et la hauteur mises à l’échelle de la bitmap :
Tournez le téléphone de côté pour voir la bitmap étirée vers cette zone :
L’avantage de l’utilisation de ce scale
facteur devient évident lorsque vous souhaitez implémenter un algorithme légèrement différent. Supposons que vous souhaitez conserver le rapport d’aspect de la bitmap, mais également remplir le rectangle de destination. La seule façon possible est de rogner une partie de l’image, mais vous pouvez implémenter cet algorithme simplement en passant Math.Min
au Math.Max
code ci-dessus. Voici le résultat :
Le rapport d’aspect de la bitmap est conservé, mais les zones à gauche et à droite de la bitmap sont rognées.
Fonction d’affichage bitmap polyvalente
Les environnements de programmation XAML (tels que UWP et Xamarin.Forms) disposent d’une fonctionnalité permettant d’étendre ou de réduire la taille des bitmaps tout en préservant leurs proportions. Bien que SkiaSharp n’inclut pas cette fonctionnalité, vous pouvez l’implémenter vous-même.
La BitmapExtensions
classe incluse dans l’exemple d’application montre comment procéder. La classe définit deux nouvelles DrawBitmap
méthodes qui effectuent le calcul des proportions. Ces nouvelles méthodes sont des méthodes d’extension de SKCanvas
.
Les nouvelles DrawBitmap
méthodes incluent un paramètre de type BitmapStretch
, une énumération définie dans le fichier BitmapExtensions.cs :
public enum BitmapStretch
{
None,
Fill,
Uniform,
UniformToFill,
AspectFit = Uniform,
AspectFill = UniformToFill
}
Les None
membres , et Uniform
UniformToFill
les membres Fill
sont identiques à ceux de l’énumération UWPStretch
. L’énumération similaire Xamarin.FormsAspect
définit les membres Fill
, AspectFit
et AspectFill
.
La page Mise à l’échelle uniforme affichée ci-dessus centre la bitmap dans le rectangle, mais vous pouvez souhaiter d’autres options, telles que le positionnement de la bitmap à gauche ou à droite du rectangle, ou le haut ou le bas. C’est l’objectif de l’énumération BitmapAlignment
:
public enum BitmapAlignment
{
Start,
Center,
End
}
Les paramètres d’alignement n’ont aucun effet lorsqu’ils sont utilisés avec BitmapStretch.Fill
.
La première DrawBitmap
fonction d’extension contient un rectangle de destination, mais aucun rectangle source. Les valeurs par défaut sont définies de sorte que si vous souhaitez que l’image bitmap soit centrée, vous n’avez besoin que de spécifier un BitmapStretch
membre :
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);
}
}
···
}
L’objectif principal de cette méthode est de calculer un facteur de mise à l’échelle nommé scale
qui est ensuite appliqué à la largeur et à la hauteur bitmap lors de l’appel de la CalculateDisplayRect
méthode. Il s’agit de la méthode qui calcule un rectangle pour afficher la bitmap en fonction de l’alignement horizontal et vertical :
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);
}
}
La BitmapExtensions
classe contient une méthode supplémentaire DrawBitmap
avec un rectangle source pour spécifier un sous-ensemble de la bitmap. Cette méthode est similaire à la première, sauf que le facteur de mise à l’échelle est calculé en fonction du source
rectangle, puis appliqué au source
rectangle dans l’appel à 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);
}
}
···
}
La première de ces deux nouvelles DrawBitmap
méthodes est illustrée dans la page Modes de mise à l’échelle. Le fichier XAML contient trois Picker
éléments qui vous permettent de sélectionner des membres des BitmapStretch
éléments et BitmapAlignment
énumérations :
<?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>
Le fichier code-behind invalide simplement le CanvasView
moment où un Picker
élément a changé. Le PaintSurface
gestionnaire accède aux trois Picker
vues pour appeler la méthode d’extension DrawBitmap
:
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);
}
}
Voici quelques combinaisons d’options :
La page Sous-ensemble de rectangles comporte pratiquement le même fichier XAML que les modes de mise à l’échelle, mais le fichier code-behind définit un sous-ensemble rectangulaire de la bitmap donnée par le SOURCE
champ :
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);
}
}
Cette source de rectangle isole la tête du singe, comme illustré dans ces captures d’écran :