Share via


Bitmapgrundlagen in SkiaSharp

Laden Sie Bitmaps aus verschiedenen Quellen, und zeigen Sie sie an.

Die Unterstützung von Bitmaps in SkiaSharp ist ziemlich umfangreich. In diesem Artikel werden nur die Grundlagen behandelt– wie Bitmaps geladen werden und wie sie angezeigt werden:

Anzeige von zwei Bitmaps

Eine viel tiefere Erkundung von Bitmaps finden Sie im Abschnitt SkiaSharp Bitmaps.

Eine SkiaSharp-Bitmap ist ein Objekt vom Typ SKBitmap. Es gibt viele Möglichkeiten zum Erstellen einer Bitmap, aber dieser Artikel beschränkt sich auf die SKBitmap.Decode Methode, die die Bitmap aus einem .NET-Objekt Stream lädt.

Die Seite "Grundlegende Bitmaps " im Programm "SkiaSharpFormsDemos " veranschaulicht, wie Bitmaps aus drei verschiedenen Quellen geladen werden:

  • Von über das Internet
  • Aus einer in die ausführbare Datei eingebetteten Ressource
  • Aus der Fotobibliothek des Benutzers

Drei SKBitmap Objekte für diese drei Quellen werden als Felder in der BasicBitmapsPage Klasse definiert:

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

Laden einer Bitmap aus dem Web

Um eine Bitmap basierend auf einer URL zu laden, können Sie die HttpClient Klasse verwenden. Sie sollten nur eine Instanz instanziieren HttpClient und wiederverwenden, damit sie als Feld gespeichert wird:

HttpClient httpClient = new HttpClient();

Bei Verwendung HttpClient mit iOS- und Android-Anwendungen sollten Sie Projekteigenschaften festlegen, wie in den Dokumenten für Transport Layer Security (TLS) 1.2 beschrieben.

Da die Verwendung des Operators mit dem await Operator HttpClientam bequemsten ist, kann der Code nicht im BasicBitmapsPage Konstruktor ausgeführt werden. Stattdessen ist er Teil der OnAppearing Außerkraftsetzung. Die URL verweist hier auf einen Bereich auf der Xamarin-Website mit einigen Beispielbitmaps. Ein Paket auf der Website ermöglicht das Anfügen einer Spezifikation zum Ändern der Größe der Bitmap an eine bestimmte Breite:

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

Das Android-Betriebssystem löst eine Ausnahme aus, wenn sie die in GetStreamAsync der StreamSKBitmap.Decode Methode zurückgegebene Verwendung verwendet, da sie einen langwierigen Vorgang in einem Standard Thread ausführt. Aus diesem Grund werden die Inhalte der Bitmapdatei mit CopyToAsynceinem MemoryStream Objekt kopiert.

Die statische SKBitmap.Decode Methode ist für die Decodierung von Bitmapdateien verantwortlich. Es funktioniert mit JPEG-, PNG- und GIF-Bitmapformaten und speichert die Ergebnisse in einem internen SkiaSharp-Format. An diesem Punkt muss der SKCanvasView Handler ungültig sein, damit der PaintSurface Handler die Anzeige aktualisieren kann.

Laden einer Bitmapressource

Im Hinblick auf Code ist der einfachste Ansatz zum Laden von Bitmaps eine Bitmapressource direkt in Ihrer Anwendung enthalten. Das SkiaSharpFormsDemos-Programm enthält einen Ordner namens "Medien" , der mehrere Bitmapdateien enthält, einschließlich eines namens monkey.png. Für Bitmaps, die als Programmressourcen gespeichert sind, müssen Sie das Dialogfeld "Eigenschaften " verwenden, um der Datei eine Buildaktion der eingebetteten Ressource zuzuweisen!

Jede eingebettete Ressource verfügt über eine Ressourcen-ID , die aus dem Projektnamen, dem Ordner und dem Dateinamen besteht, die alle nach Zeiträumen verbunden sind: SkiaSharpFormsDemos.Media.monkey.png. Sie können zugriff auf diese Ressource erhalten, indem Sie diese Ressourcen-ID als Argument für die GetManifestResourceStream Methode der Assembly Klasse angeben:

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

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

Dieses Stream Objekt kann direkt an die SKBitmap.Decode Methode übergeben werden.

Laden einer Bitmap aus der Fotobibliothek

Es ist auch möglich, dass der Benutzer ein Foto aus der Bildbibliothek des Geräts lädt. Diese Einrichtung wird nicht selbst Xamarin.Forms bereitgestellt. Der Auftrag erfordert einen Abhängigkeitsdienst, z. B. den im Artikel "Auswählen eines Fotos aus der Bildbibliothek" beschriebenen Dienst.

Die IPhotoLibrary.cs Datei im Projekt SkiaSharpFormsDemos und die drei PhotoLibrary.cs Dateien in den Plattformprojekten wurden aus diesem Artikel angepasst. Darüber hinaus wurde die Android-MainActivity.cs-Datei wie im Artikel beschrieben geändert, und dem iOS-Projekt wurde die Berechtigung erteilt, auf die Fotobibliothek mit zwei Zeilen am Ende der Info.plist-Datei zuzugreifen.

Der BasicBitmapsPage Konstruktor fügt dem SKCanvasView Tipper eine TapGestureRecognizer Benachrichtigung hinzu. Beim Empfang eines Tippens erhält der Tapped Handler Zugriff auf den Abhängigkeitsdienst für die Bildauswahl und Aufrufe PickPhotoAsync. Wenn ein Stream Objekt zurückgegeben wird, wird es an die SKBitmap.Decode Methode übergeben:

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

Beachten Sie, dass der Tapped Handler auch die InvalidateSurface Methode des SKCanvasView Objekts aufruft. Dadurch wird ein neuer Aufruf des PaintSurface Handlers generiert.

Anzeigen der Bitmaps

Der PaintSurface Handler muss drei Bitmaps anzeigen. Der Handler geht davon aus, dass sich das Telefon im Hochformat befindet und den Zeichenbereich vertikal in drei gleiche Teile unterteilt.

Die erste Bitmap wird mit der einfachsten DrawBitmap Methode angezeigt. Sie müssen lediglich die X- und Y-Koordinaten angeben, wobei die obere linke Ecke der Bitmap positioniert werden soll:

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

Obwohl ein SKPaint Parameter definiert ist, weist er einen Standardwert null auf und Sie können ihn ignorieren. Die Pixel der Bitmap werden einfach mit einer 1:1-Zuordnung auf die Pixel der Anzeigeoberfläche übertragen. Im nächsten Abschnitt zu SkiaSharp Transparency wird eine Anwendung für dieses SKPaint Argument angezeigt.

Ein Programm kann die Pixelabmessungen einer Bitmap mit den Width Eigenschaften Height abrufen. Mit diesen Eigenschaften kann das Programm Koordinaten berechnen, um die Bitmap in der Mitte des oberen Drittels des Zeichenbereichs zu positionieren:

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

Die anderen beiden Bitmaps werden mit einer Version von DrawBitmap einem SKRect Parameter angezeigt:

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

Eine dritte Version von DrawBitmap zwei SKRect Argumenten zum Angeben einer rechteckigen Teilmenge der anzuzeigenden Bitmap, aber diese Version wird in diesem Artikel nicht verwendet.

Hier sehen Sie den Code zum Anzeigen der Bitmap, die aus einer eingebetteten Ressourcenbitmap geladen wurde:

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

Die Bitmap wird auf die Abmessungen des Rechtecks gestreckt, weshalb der Affen in diesen Screenshots horizontal gestreckt wird:

Ein dreifacher Screenshot der Seite

Das dritte Bild , das Sie nur sehen können, wenn Sie das Programm ausführen und ein Foto aus Ihrer eigenen Bildbibliothek laden, wird auch innerhalb eines Rechtecks angezeigt, aber die Position und Größe des Rechtecks werden an Standard seitenverhältnis der Bitmap angepasst. Diese Berechnung ist etwas mehr beteiligt, da es eine Berechnung eines Skalierungsfaktors erfordert, der auf der Größe der Bitmap und des Zielrechtecks basiert und das Rechteck in diesem Bereich zentriert wird:

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

Wenn noch keine Bitmap aus der Bildbibliothek geladen wurde, zeigt der else Block Text an, um den Benutzer auf den Bildschirm zu tippen.

Sie können Bitmaps mit verschiedenen Transparenzgraden anzeigen, und im nächsten Artikel zu SkiaSharp Transparency wird beschrieben, wie das geht.