共用方式為


SkiaSharp 中的位圖基本概念

從各種來源載入點陣圖並加以顯示。

SkiaSharp 中位圖的支持相當廣泛。 本文僅涵蓋基本概念 — 如何載入位圖,以及如何顯示點陣圖:

顯示兩個點陣圖

您可以在 SkiaSharp 位圖一節 中找到更深入的點陣圖探索

SkiaSharp 位陣圖是類型的 SKBitmap物件。 有許多方法可以建立位圖,但本文會將本身限制為 SKBitmap.Decode 方法,此方法會從 .NET Stream 物件載入點陣圖。

SkiaSharpFormsDemos 程式中的基本點陣圖頁面示範如何從三個不同的來源載入點陣圖:

  • 從因特網
  • 從內嵌在可執行檔中的資源
  • 從使用者的相片庫

這三個來源的三 SKBitmap 個物件會定義為 類別中的 BasicBitmapsPage 欄位:

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

從 Web 載入點陣圖

若要根據 URL 載入點陣圖,您可以使用 類別 HttpClient 。 您應該只具現化一個 實體 HttpClient 並重複使用它,因此請將它儲存為字段:

HttpClient httpClient = new HttpClient();

搭配 iOS 和 Android 應用程式使用HttpClient時,您會想要設定項目屬性,如傳輸層安全性 (TLS) 1.2 上的檔案所述。

因為搭配 使用 await 運算子 HttpClient最方便,所以無法在建構函式中 BasicBitmapsPage 執行程序代碼。 而是覆寫的 OnAppearing 一部分。 這裡的 URL 會指向具有一些範例位圖的 Xamarin 網站上的區域。 網站上的套件允許將點陣圖大小調整為特定寬度的規格:

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

Android 作業系統在使用 方法中SKBitmap.Decode傳回的 GetStreamAsyncStream,會引發例外狀況,因為它在主線程上執行冗長的作業。 因此,位圖檔案的內容會使用 CopyToAsync複製到 MemoryStream 物件。

靜態 SKBitmap.Decode 方法負責譯碼位圖檔案。 它可與 JPEG、PNG 和 GIF 位圖格式搭配使用,並以內部 SkiaSharp 格式儲存結果。 此時, SKCanvasView 必須失效,才能讓 PaintSurface 處理程式更新顯示。

載入點圖資源

就程式代碼而言,載入位圖最簡單的方法是直接在應用程式中包含位圖資源。 SkiaSharpFormsDemos 程式包含名為 Media 的資料夾,其中包含數位陣陣圖檔案,包括一個名為 monkey.png。 對於儲存為程式資源的點陣圖,您必須使用 [屬性] 對話框,為檔案提供內嵌資源的建置動作

每個內嵌資源都有一個 資源標識符 ,其中包含專案名稱、資料夾和檔名,全都依句點連接: SkiaSharpFormsDemos.Media.monkey.png。 您可以將該資源識別元指定為 類別方法的Assembly自變數GetManifestResourceStream,以取得此資源的存取權:

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

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

這個 Stream 物件可以直接傳遞至 SKBitmap.Decode 方法。

從相片庫載入點陣圖

使用者也可以從裝置的圖片庫載入相片。 這項設施本身並未提供 Xamarin.Forms 。 作業需要相依性服務,例如從圖片庫挑選相片一文中所述的相依性服務。

SkiaSharpFormsDemos 專案中的IPhotoLibrary.cs檔案和平台專案中的三個PhotoLibrary.cs檔案已從該文章改編。 此外,Android MainActivity.cs 檔案已如本文所述進行修改,而且 iOS 專案已獲授與存取相片媒體櫃的許可權,該檔案位於 info.plist 檔案底部的兩行。

BasicBitmapsPage 構函式會將 新增 TapGestureRecognizerSKCanvasView ,以收到點選通知。 在收到點選時, Tapped 處理程式會取得圖片選擇器相依性服務的存取權,並呼叫 PickPhotoAsyncStream如果傳回 物件,則會傳遞至 SKBitmap.Decode 方法:

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

請注意, Tapped 處理程式也會呼叫 InvalidateSurface 物件的方法 SKCanvasView 。 這會產生處理程式 PaintSurface 的新呼叫。

顯示點陣圖

處理程式 PaintSurface 必須顯示三個點陣圖。 處理程式假設手機處於直向模式,並將畫布垂直分割成三個相等部分。

第一個點陣圖會以最簡單的 DrawBitmap 方法顯示。 您只需要指定 X 和 Y 座標,點陣圖左上角的位置就是:

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

SKPaint雖然已定義參數,但它具有的預設值null,而且您可以忽略它。 點陣圖的圖元只會以一對一對應傳送至顯示介面的圖元。 您將在下一節的 SkiaSharp Transparency 中看到此SKPaint自變數的應用程式。

程式可以使用 和 Height 屬性取得位圖Width的像素維度。 這些屬性可讓程式計算座標,將點陣圖放置在畫布上三分之一的中央:

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

其他兩個點陣圖會以 參數SKRect的 版本DrawBitmap來顯示:

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

的第三個版本 DrawBitmap 有兩 SKRect 個自變數,可指定要顯示的位圖矩形子集,但本文並未使用該版本。

以下是顯示從內嵌資源點陣圖載入之點陣圖的程式代碼:

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

位圖會延展到矩形的維度,這就是為什麼猴子在這些螢幕快照中水準伸展的原因:

基本點圖頁面的三重螢幕快照

第三個影像,您只能查看您是否執行程式並從自己的圖片庫載入相片,也會顯示在矩形內,但矩形的位置和大小會調整,以維持點陣圖的外觀比例。 此計算稍微涉及一點,因為它需要根據點陣圖和目的矩形的大小計算縮放比例,並將矩形置中該區域:

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

如果尚未從圖片庫載入點陣圖,則 else 區塊會顯示一些文字,以提示用戶點選畫面。

您可以顯示具有各種透明度的位圖,而SkiaSharp Transparency上的下一篇文章將說明如何。