Partager via


Notions de base de bitmap dans SkiaSharp

Chargez des bitmaps à partir de différentes sources et affichez-les.

La prise en charge des bitmaps dans SkiaSharp est très étendue. Cet article couvre uniquement les concepts de base : comment charger des bitmaps et comment les afficher :

Affichage de deux bitmaps

Vous trouverez une exploration beaucoup plus approfondie des bitmaps dans la section SkiaSharp Bitmaps.

Une bitmap SkiaSharp est un objet de type SKBitmap. Il existe de nombreuses façons de créer une bitmap, mais cet article se limite à la SKBitmap.Decode méthode, qui charge la bitmap à partir d’un objet .NET Stream .

La page Bitmaps de base du programme SkiaSharpFormsDemos montre comment charger des bitmaps à partir de 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

Trois SKBitmap objets pour ces trois sources sont définis en tant que champs dans la 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;
        ...
    }
    ...
}

Chargement d’une bitmap à partir du web

Pour charger une bitmap basée sur une URL, vous pouvez utiliser la HttpClient classe. Vous ne devez instancier qu’une seule instance et HttpClient la réutiliser. Stockez-la 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.

Étant donné qu’il est plus pratique d’utiliser l’opérateur await avec HttpClient, le code ne peut pas être exécuté dans le BasicBitmapsPage constructeur. Au lieu de cela, il fait partie du OnAppearing remplacement. L’URL ici pointe vers une zone sur le site web Xamarin avec des exemples de bitmaps. Un package sur le site web permet d’ajouter une spécification pour redimensionner la bitmap à une largeur particulière :

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
    {
    }
}

Le système d’exploitation Android génère une exception lors de l’utilisation du Stream retour de GetStreamAsync la SKBitmap.Decode méthode, car il effectue une longue opération sur un thread principal. Pour cette raison, le contenu du fichier bitmap est copié dans un MemoryStream objet à l’aide CopyToAsyncde .

La méthode statique SKBitmap.Decode est responsable du décodage des fichiers bitmap. Il fonctionne avec les formats bitmap JPEG, PNG et GIF, et stocke les résultats dans un format SkiaSharp interne. À ce stade, il SKCanvasView doit être invalidé pour permettre PaintSurface au gestionnaire de mettre à jour l’affichage.

Chargement d’une ressource bitmap

En termes de code, l’approche la plus simple pour charger des bitmaps consiste à inclure une ressource bitmap directement dans votre application. Le programme SkiaSharpFormsDemos inclut un dossier nommé Media contenant plusieurs fichiers bitmap, dont un nommé monkey.png. Pour les bitmaps stockées en tant que ressources de programme, vous devez utiliser la boîte de dialogue Propriétés pour donner au fichier une action de génération de ressource incorporée !

Chaque ressource incorporée a un ID de ressource qui se compose du nom du projet, du dossier et du nom de fichier, tous connectés par points : SkiaSharpFormsDemos.Media.monkey.png. Vous pouvez accéder à cette ressource en spécifiant cet ID de ressource comme argument de la GetManifestResourceStream méthode de la Assembly classe :

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

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

Cet Stream objet peut être transmis directement à la SKBitmap.Decode méthode.

Chargement d’une bitmap à partir de la bibliothèque de photos

Il est également possible pour l’utilisateur de charger une photo à partir de la bibliothèque d’images de l’appareil. Cette installation n’est pas fournie par Xamarin.Forms elle-même. Le travail nécessite un service de dépendance, tel que celui décrit dans l’article Sélection d’une photo à partir de la bibliothèque d’images.

Le fichier IPhotoLibrary.cs dans le projet SkiaSharpFormsDemos et les trois fichiers PhotoLibrary.cs dans les projets de plateforme ont été adaptés à partir de cet article. En outre, le fichier android MainActivity.cs a été modifié comme décrit dans l’article, et le projet iOS a été autorisé à accéder à la bibliothèque de photos avec deux lignes vers le bas du fichier info.plist .

Le BasicBitmapsPage constructeur ajoute un TapGestureRecognizer à la SKCanvasView notification des appuis. À la réception d’un appui, le Tapped gestionnaire obtient l’accès au service de dépendance du sélecteur d’images et aux appels PickPhotoAsync. Si un Stream objet est retourné, il est passé à la SKBitmap.Decode méthode :

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

Notez que le Tapped gestionnaire appelle également la InvalidateSurface méthode de l’objet SKCanvasView . Cela génère un nouvel appel au PaintSurface gestionnaire.

Affichage des bitmaps

Le PaintSurface gestionnaire doit afficher trois bitmaps. Le gestionnaire suppose que le téléphone est en mode portrait et divise verticalement le canevas en trois parties égales.

La première bitmap s’affiche avec la méthode la plus simple DrawBitmap . Il vous suffit de spécifier les coordonnées X et Y dans lesquelles le coin supérieur gauche de la bitmap doit être positionné :

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

Bien qu’un SKPaint paramètre soit défini, il a une valeur par défaut et null vous pouvez l’ignorer. Les pixels de la bitmap sont simplement transférés aux pixels de l’aire d’affichage avec un mappage un-à-un. Vous verrez une application pour cet SKPaint argument dans la section suivante sur SkiaSharp Transparency.

Un programme peut obtenir les dimensions de pixels d’une bitmap avec les propriétés et Height les Width propriétés. Ces propriétés permettent au programme de calculer les coordonnées pour positionner la bitmap au centre du tiers supérieur du canevas :

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

Les deux autres bitmaps sont affichées avec une version d’un DrawBitmapSKRect paramètre :

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

Une troisième version comporte DrawBitmap deux SKRect arguments pour spécifier un sous-ensemble rectangulaire de l’image bitmap à afficher, mais cette version n’est pas utilisée dans cet article.

Voici le code permettant d’afficher la bitmap chargée à partir d’une bitmap de ressource incorporée :

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 est étirée aux dimensions du rectangle, c’est pourquoi le singe est étiré horizontalement dans ces captures d’écran :

Capture d’écran triple de la page Bitmaps de base

La troisième image , que vous pouvez voir uniquement si vous exécutez le programme et charger une photo à partir de votre propre bibliothèque d’images, est également affichée dans un rectangle, mais la position et la taille du rectangle sont ajustées pour maintenir le rapport d’aspect de la bitmap. Ce calcul est un peu plus impliqué, car il nécessite le calcul d’un facteur de mise à l’échelle en fonction de la taille de la bitmap et du rectangle de destination, et le centre du rectangle dans cette zone :

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

Si aucune bitmap n’a encore été chargée à partir de la bibliothèque d’images, le else bloc affiche du texte pour inviter l’utilisateur à appuyer sur l’écran.

Vous pouvez afficher des bitmaps avec différents degrés de transparence, et l’article suivant sur SkiaSharp Transparency décrit comment procéder.