Bitmap Basics in SkiaSharp
Načtěte rastrové obrázky z různých zdrojů a zobrazte je.
Podpora rastrových obrázků ve SkiaSharpu je poměrně rozsáhlá. Tento článek se zabývá pouze základy – jak načíst rastrové obrázky a jak je zobrazit:
Mnohem hlubší zkoumání rastrových obrázků najdete v části SkiaSharp Bitmaps.
Bitmapa SkiaSharp je objekt typu SKBitmap
. Existuje mnoho způsobů, jak vytvořit rastrový obrázek, ale tento článek omezuje sám na metodu SKBitmap.Decode
, která načte rastrový obrázek z objektu .NET Stream
.
Stránka Základní rastrové obrázky v programu SkiaSharpFormsDemos ukazuje, jak načíst rastrové obrázky ze tří různých zdrojů:
- Z internetu
- Z prostředku vloženého do spustitelného souboru
- Z knihovny fotek uživatele
Tři SKBitmap
objekty pro tyto tři zdroje jsou definovány jako pole ve BasicBitmapsPage
třídě:
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;
...
}
...
}
Načtení rastrového obrázku z webu
K načtení rastrového obrázku na základě adresy URL můžete použít HttpClient
třídu. Měli byste vytvořit instanci pouze jedné instance HttpClient
a znovu ji použít, takže ji uložte jako pole:
HttpClient httpClient = new HttpClient();
Při použití HttpClient
s aplikacemi pro iOS a Android budete chtít nastavit vlastnosti projektu, jak je popsáno v dokumentech tls (Transport Layer Security) 1.2.
Vzhledem k tomu, že je nejvhodnější použít await
operátor s HttpClient
, nelze kód spustit v konstruktoru BasicBitmapsPage
. Místo toho je součástí přepsání OnAppearing
. Adresa URL zde odkazuje na oblast na webu Xamarin s některými ukázkovými rastrovými obrázky. Balíček na webu umožňuje připojit specifikaci pro změnu velikosti rastrového obrázku na určitou šířku:
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
{
}
}
Operační systém Android vyvolá výjimku při použití vráceného Stream
z GetStreamAsync
metody SKBitmap.Decode
, protože provádí zdlouhavou operaci v hlavním vlákně. Z tohoto důvodu se obsah rastrového souboru zkopíruje do objektu MemoryStream
pomocí CopyToAsync
.
Statická SKBitmap.Decode
metoda zodpovídá za dekódování rastrových souborů. Funguje s rastrovými formáty JPEG, PNG a GIF a výsledky ukládá do interního formátu SkiaSharp. V tomto okamžiku SKCanvasView
je potřeba zneplatnit, aby obslužná rutina PaintSurface
mohla aktualizovat zobrazení.
Načtení bitmapového prostředku
Z hlediska kódu je nejjednodušším způsobem načítání rastrových obrázků zahrnout rastrový prostředek přímo ve vaší aplikaci. Program SkiaSharpFormsDemos obsahuje složku s názvem Media obsahující několik rastrových souborů, včetně jedné pojmenované monkey.png. U rastrových obrázků uložených jako prostředky programu je nutné použít dialogové okno Vlastnosti k poskytnutí souboru akce sestavení vloženého prostředku!
Každý vložený prostředek má ID zdroje, které se skládá z názvu projektu, složky a názvu souboru, všechny spojené tečkami: SkiaSharpFormsDemos.Media.monkey.png. Přístup k tomuto prostředku získáte zadáním ID prostředku jako argumentu GetManifestResourceStream
pro metodu Assembly
třídy:
string resourceID = "SkiaSharpFormsDemos.Media.monkey.png";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
resourceBitmap = SKBitmap.Decode(stream);
}
Tento Stream
objekt lze předat přímo metodě SKBitmap.Decode
.
Načtení rastrového obrázku z knihovny fotografií
Je také možné, aby uživatel načetl fotku z knihovny obrázků zařízení. Toto zařízení není poskytováno Xamarin.Forms samostatně. Úloha vyžaduje službu závislostí, například službu popsanou v článku Výběr fotky z knihovny obrázků.
Soubor IPhotoLibrary.cs v projektu SkiaSharpFormsDemos a tři PhotoLibrary.cs soubory v projektech platformy byly upraveny z daného článku. Kromě toho byl soubor MainActivity.cs androidu upraven tak, jak je popsáno v článku, a projekt iOS má oprávnění pro přístup ke knihovně fotografií se dvěma řádky v dolní části souboru info.plist.
Konstruktor BasicBitmapsPage
přidá TapGestureRecognizer
do upozornění SKCanvasView
na klepnutí. Po přijetí klepnutí Tapped
získá obslužná rutina přístup ke službě závislostí pro výběr obrázku a volání PickPhotoAsync
. Stream
Pokud se vrátí objekt, předá SKBitmap.Decode
se metodě:
// 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);
Všimněte si, že obslužná rutina Tapped
také volá InvalidateSurface
metodu objektu SKCanvasView
. Tím se vygeneruje nové volání obslužné rutiny PaintSurface
.
Zobrazení rastrových obrázků
Obslužná rutina PaintSurface
musí zobrazit tři rastrové obrázky. Obslužná rutina předpokládá, že telefon je v režimu na výšku a rozdělí plátno svisle na tři stejné části.
První rastrový obrázek se zobrazí nejjednodušší DrawBitmap
metodou. Stačí zadat souřadnice X a Y, kde má být umístěn levý horní roh rastrového obrázku:
public void DrawBitmap (SKBitmap bitmap, Single x, Single y, SKPaint paint = null)
SKPaint
Přestože je parametr definovaný, má výchozí hodnotu a můžete ho null
ignorovat. Pixely rastrového obrázku se jednoduše přenesou na pixely povrchu zobrazení s mapováním 1:1. Aplikaci pro tento SKPaint
argument uvidíte v další části o průhlednosti SkiaSharpu.
Program může získat rozměry pixelu rastrového obrázku Width
s vlastnostmi a Height
vlastnostmi. Tyto vlastnosti umožňují programu vypočítat souřadnice pro umístění rastrového obrázku do středu horní třetiny plátna:
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);
}
...
}
Další dva rastrové obrázky se zobrazí s verzí DrawBitmap
s parametrem SKRect
:
public void DrawBitmap (SKBitmap bitmap, SKRect dest, SKPaint paint = null)
Třetí verze DrawBitmap
má dva SKRect
argumenty pro zadání obdélníkové podmnožina rastrového obrázku k zobrazení, ale tato verze se v tomto článku nepoužívá.
Tady je kód pro zobrazení rastrového obrázku načteného z vloženého rastrového obrázku prostředku:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
...
if (resourceBitmap != null)
{
canvas.DrawBitmap(resourceBitmap,
new SKRect(0, info.Height / 3, info.Width, 2 * info.Height / 3));
}
...
}
Rastrový obrázek je roztažen na rozměry obdélníku, což je důvod, proč je opice vodorovně roztažena na těchto snímcích obrazovky:
Třetí obrázek – který můžete vidět pouze v případě, že program spustíte a načtete fotku z vlastní knihovny obrázků – se také zobrazí v obdélníku, ale umístění a velikost obdélníku se upraví tak, aby zachoval poměr stran rastrového obrázku. Tento výpočet je trochu složitější, protože vyžaduje výpočet měřítka na základě velikosti rastrového obrázku a cílového obdélníku a na střed obdélníku v této oblasti:
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);
}
}
}
Pokud se z knihovny obrázků ještě nenačetl žádný rastrový obrázek, zobrazí blok nějaký text, else
který uživatele vyzve k klepnutí na obrazovku.
Rastrové obrázky můžete zobrazit s různými stupni průhlednosti a další článek o Průhlednosti SkiaSharp popisuje, jak na to.