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
傳回的 GetStreamAsync
時Stream
,會引發例外狀況,因為它在主線程上執行冗長的作業。 因此,位圖檔案的內容會使用 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
構函式會將 新增 TapGestureRecognizer
至 SKCanvasView
,以收到點選通知。 在收到點選時, Tapped
處理程式會取得圖片選擇器相依性服務的存取權,並呼叫 PickPhotoAsync
。 Stream
如果傳回 物件,則會傳遞至 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上的下一篇文章將說明如何。