SkiaSharp ビットマップの表示
SkiaSharp ビットマップに関する主題は、SkiaSharp のビットマップの基本に関する記事で紹介しました。 その記事では、ビットマップを読み込む 3 つの方法とビットマップを表示する 3 つの方法を示しました。 この記事では、ビットマップを読み込む手法を確認し、SKCanvas
の DrawBitmap
メソッドの使用について深く掘り下げます。
DrawBitmapLattice
および DrawBitmapNinePatch
メソッドについては、SkiaSharp ビットマップのセグメント化された表示に関する記事で説明します。
このページのサンプルは、サンプル アプリケーションからのものです。 そのアプリケーションのホーム ページで、[SkiaSharp ビットマップ] を選択し、[ビットマップの表示] セクションに移動します。
ビットマップの読み込み
SkiaSharp アプリケーションで使用されるビットマップは通常、次の 3 つの異なるソースのいずれかから取得されます。
- インターネットから
- 実行可能ファイルに埋め込まれているリソースから
- ユーザーの写真ライブラリから
SkiaSharp アプリケーションで新しいビットマップを作成し、その上に描画したり、ビットマップ ビットをアルゴリズムで設定したりすることもできます。 これらの手法については、SkiaSharp ビットマップの作成と描画と SkiaSharp ビットマップ ピクセルへのアクセスに関する記事で説明されています。
ビットマップを読み込む次の 3 つのコード例では、クラスにタイプ SKBitmap
のフィールドが含まれていることを前提としています。
SKBitmap bitmap;
SkiaSharp のビットマップの基本に関する記事で説明したように、インターネット経由でビットマップを読み込む最善の方法は HttpClient
クラスを使用する方法です。 クラスの 1 つのインスタンスをフィールドとして定義できます。
HttpClient httpClient = new HttpClient();
iOS および Android アプリケーションで HttpClient
を使用する場合は、トランスポート層セキュリティ (TLS) 1.2 のドキュメントの説明に従って、プロジェクトのプロパティを設定する必要があります。
多くの場合、HttpClient
を使用するコードには await
演算子が含まれるため、このコードは async
メソッド内に存在する必要があります。
try
{
using (Stream stream = await httpClient.GetStreamAsync("https:// ··· "))
using (MemoryStream memStream = new MemoryStream())
{
await stream.CopyToAsync(memStream);
memStream.Seek(0, SeekOrigin.Begin);
bitmap = SKBitmap.Decode(memStream);
···
};
}
catch
{
···
}
GetStreamAsync
から取得した Stream
オブジェクトが MemoryStream
にコピーされることに注意してください。 Android では、非同期メソッドでの場合を除き、メイン スレッドによって HttpClient
の Stream
が処理されることは許可されません。
SKBitmap.Decode
は多くの処理を行います。これに渡された Stream
オブジェクトは、ビットマップ全体が一般的なビットマップ ファイル形式 (通常は JPEG、PNG、GIF) のいずれかで含まれるメモリ ブロックを参照します。 Decode
メソッドは、形式を確認してから、ビットマップ ファイルを SkiaSharp 独自の内部ビットマップ形式にデコードする必要があります。
コードは、SKBitmap.Decode
を呼び出した後、たいていは CanvasView
を無効にし、PaintSurface
ハンドラーが新しく読み込まれたビットマップを表示できるようにします。
ビットマップを読み込む 2 番目の方法は、個々のプラットフォーム プロジェクトによって参照される .NET Standard ライブラリにビットマップを埋め込みリソースとして含める方法です。 GetManifestResourceStream
メソッドにはリソース ID が渡されます。 このリソース ID は、ピリオドで区切られたリソースのアセンブリ名、フォルダー名、ファイル名で構成されます。
string resourceID = "assemblyName.folderName.fileName";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
···
}
ビットマップ ファイルは、iOS、Android、ユニバーサル Windows プラットフォーム (UWP) の個々のプラットフォーム プロジェクトにリソースとして格納することもできます。 ただし、これらのビットマップを読み込むには、プラットフォーム プロジェクトにあるコードが必要です。
ビットマップを取得する 3 番目の方法は、ユーザーの画像ライブラリから取得する方法です。 次のコードでは、サンプル アプリケーションに含まれている依存関係サービスを使用します。 SkiaSharpFormsDemo .NET Standard ライブラリには IPhotoLibrary
インターフェイスが含まれていますが、各プラットフォーム プロジェクトには、そのインターフェイスを実装する PhotoLibrary
クラスが含まれています。
IPhotoicturePicker picturePicker = DependencyService.Get<IPhotoLibrary>();
using (Stream stream = await picturePicker.GetImageStreamAsync())
{
if (stream != null)
{
bitmap = SKBitmap.Decode(stream);
···
}
}
一般に、このようなコードは、CanvasView
を無効にし、PaintSurface
ハンドラーが新しいビットマップを表示できるようにします。
SKBitmap
クラスは、ビットマップのピクセルの寸法を明らかにする Width
や Height
を含む複数の便利なプロパティや、ビットマップの作成、ビットマップのコピー、ピクセル ビットの公開などを行うメソッドを含む多くのメソッドを定義します。
ピクセルの寸法での表示
SkiaSharp の Canvas
クラスは、4 つの DrawBitmap
メソッドを定義します。 これらのメソッドを使用すると、基本的に異なる 2 つの方法でビットマップを表示できます。
SKPoint
値 (または個別のx
およびy
値) を指定すると、ビットマップがピクセルの寸法で表示されます。 ビットマップのピクセルは、ビデオ ディスプレイのピクセルに直接マップされます。- 四角形を指定すると、ビットマップは四角形のサイズと形状に引き伸ばされます。
ビットマップをピクセルの寸法ンションで表示するには、DrawBitmap
を SKPoint
パラメータと共に使用するか、DrawBitmap
を別個の x
および y
パラメーターと共に使用します。
DrawBitmap(SKBitmap bitmap, SKPoint pt, SKPaint paint = null)
DrawBitmap(SKBitmap bitmap, float x, float y, SKPaint paint = null)
これら 2 つのメソッドは機能的に同じです。 指定した点は、キャンバスを基準としたビットマップの左上の角の位置を示します。 モバイル デバイスのピクセル解像度は非常に高いため、通常、これらのデバイスでは小さいビットマップが非常に小さく表示されます。
省略可能な SKPaint
パラメータを使用すると、透明度を使用してビットマップを表示できます。 これを行うには、SKPaint
オブジェクトを作成し、Color
プロパティを、アルファ チャネルが 1 未満である任意 SKColor
の値に設定します。 次に例を示します。
paint.Color = new SKColor(0, 0, 0, 0x80);
最後の引数として渡された 0x80 は、50% の透明度を示します。 また、定義済みの色のいずれかにアルファ チャネルを設定することもできます。
paint.Color = SKColors.Red.WithAlpha(0x80);
ただし、色自体は関係ありません。 DrawBitmap
呼び出しで SKPaint
オブジェクトを使用すると、アルファ チャネルのみが調べられます。
また、ブレンド モードまたはフィルター効果を使用してビットマップを表示する場合、SKPaint
オブジェクトも役割を果たします。 これらは、SkiaSharp の合成モードとブレンド モードおよび SkiaSharp 画像フィルターに関する記事で説明されています。
サンプル プログラムの Pixel Dimensions ページには、幅 320 ピクセル x 高さ 240 ピクセルのビットマップ リソースが表示されます。
public class PixelDimensionsPage : ContentPage
{
SKBitmap bitmap;
public PixelDimensionsPage()
{
Title = "Pixel Dimensions";
// Load the bitmap from a resource
string resourceID = "SkiaSharpFormsDemos.Media.Banana.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
bitmap = SKBitmap.Decode(stream);
}
// Create the SKCanvasView and set the PaintSurface handler
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float x = (info.Width - bitmap.Width) / 2;
float y = (info.Height - bitmap.Height) / 2;
canvas.DrawBitmap(bitmap, x, y);
}
}
PaintSurface
ハンドラーは、ディスプレイ面のピクセルの寸法とビットマップのピクセルの寸法に基づいて x
および y
値を計算して、ビットマップを中央に配置します。
アプリケーションは、左上の角にビットマップを表示する必要がある場合、単に (0, 0) の座標を渡します。
リソース ビットマップを読み込むためのメソッド
後続のサンプルの多くでは、ビットマップ リソースを読み込む必要があります。 サンプル ソリューションの静的 BitmapExtensions
クラスには、次の役立つ方法が含まれています。
static class BitmapExtensions
{
public static SKBitmap LoadBitmapResource(Type type, string resourceID)
{
Assembly assembly = type.GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
return SKBitmap.Decode(stream);
}
}
···
}
Type
パラメータに注目してください。 これは、ビットマップ リソースを格納する Type
アセンブリ内の任意の型に関連付けられたオブジェクトである場合があります。
この LoadBitmapResource
メソッドは、ビットマップ リソースを必要とする後続のすべてのサンプルで使用されます。
四角形を塗りつぶすために引き伸ばす
SKCanvas
クラスは、ビットマップを四角形にレンダリングする DrawBitmap
メソッドと、ビットマップの四角形のサブセットを四角形にレンダリングする別の DrawBitmap
メソッドも定義します。
DrawBitmap(SKBitmap bitmap, SKRect dest, SKPaint paint = null)
DrawBitmap(SKBitmap bitmap, SKRect source, SKRect dest, SKPaint paint = null)
どちらの場合も、ビットマップは、dest
という名前の四角形を塗りつぶすために引き伸ばされます。 2 番目のメソッドでは、source
四角形を使用してビットマップのサブセットを選択できます。 dest
四角形は出力デバイスを基準としており、source
四角形はビットマップを基準としています。
Fill Rectangle ページは、キャンバスと同じサイズの四角形の前の例で使用したものと同じビットマップを表示することで、これら 2 つのメソッドの最初のメソッドを示します。
public class FillRectanglePage : ContentPage
{
SKBitmap bitmap =
BitmapExtensions.LoadBitmapResource(typeof(FillRectanglePage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
public FillRectanglePage ()
{
Title = "Fill Rectangle";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(bitmap, info.Rect);
}
}
新しい BitmapExtensions.LoadBitmapResource
メソッドを使用して SKBitmap
フィールドを設定していることに注意してください。 変換先の四角形は、ディスプレイ面のサイズを説明する SKImageInfo
の Rect
プロパティから取得されます。
これは通常、望ましくありません。 この画像は、水平方向と垂直方向に異なる方法で引き伸ばされて歪んでいます。 ビットマップをピクセル サイズ以外の方法で表示する場合は通常、ビットマップの元の縦横比を維持する必要があります。
縦横比を維持しながら引き伸ばす
縦横比を維持しながらビットマップを引き伸ばすことは、均一スケーリングとも呼ばれるプロセスです。 この用語は、アルゴリズム アプローチを示唆しています。 考えられる解決策の 1 つは、Uniform Scaling ページに示されています。
public class UniformScalingPage : ContentPage
{
SKBitmap bitmap =
BitmapExtensions.LoadBitmapResource(typeof(UniformScalingPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
public UniformScalingPage()
{
Title = "Uniform Scaling";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float scale = Math.Min((float)info.Width / bitmap.Width,
(float)info.Height / bitmap.Height);
float x = (info.Width - scale * bitmap.Width) / 2;
float y = (info.Height - scale * bitmap.Height) / 2;
SKRect destRect = new SKRect(x, y, x + scale * bitmap.Width,
y + scale * bitmap.Height);
canvas.DrawBitmap(bitmap, destRect);
}
}
PaintSurface
ハンドラーは、ビットマップの幅と高さに対するディスプレイの幅と高さの比率の最小値である scale
係数を計算します。 その後、スケーリングされたビットマップをディスプレイの幅と高さの範囲内に中央揃えするために、x
および y
値を計算できます。 変換先の四角形には、x
および y
の左上の角と、これらの値の右下の角に加えて、スケーリングされたビットマップの幅と高さがあります。
スマートフォンを横向きにして、ビットマップがその領域まで引き伸ばされていることを確認します。
この scale
係数を使用する利点は、若干異なるアルゴリズムを実装するときに明らかになります。 ビットマップの縦横比を維持するが、変換先の四角形も塗りつぶしたいとします。 これが可能な唯一の方法は、画像の一部をトリミングすることですが、上記のコードで Math.Min
を Math.Max
に変更するだけでこのアルゴリズムを実装できます。 結果は次のとおりです。
ビットマップの縦横比は保持されますが、ビットマップの左右の領域はトリミングされます。
汎用性の高いビットマップ表示関数
XAML ベースのプログラミング環境 (UWP や Xamarin.Forms など) には、ビットマップのサイズを拡大または縮小しながら縦横比を維持するための機能があります。 SkiaSharp にはこの機能は含まれませんが、自分で実装できます。
サンプル アプリケーションに含まれる BitmapExtensions
クラスは、その方法を示しています。 このクラスは、縦横比の計算を実行する 2 つの新しい DrawBitmap
メソッドを定義します。 これらの新しいメソッドは、SKCanvas
の拡張メソッドです。
この新しい DrawBitmap
メソッドには、BitmapExtensions.cs ファイルに定義されている列挙型である、タイプ BitmapStretch
のパラメータが含まれます。
public enum BitmapStretch
{
None,
Fill,
Uniform,
UniformToFill,
AspectFit = Uniform,
AspectFill = UniformToFill
}
None
、Fill
、Uniform
、UniformToFill
メンバーは、UWP の Stretch
列挙型のメンバーと同じです。 同様の Xamarin.FormsAspect
列挙型は、メンバー Fill
、AspectFit
、AspectFill
を定義します。
上記の Uniform Scaling ページではビットマップは四角形内に中央揃えされます。しかし、ビットマップを四角形の左側または右側、上側または下側に配置するなど、その他のオプションが必要な場合があります。 これが BitmapAlignment
メソッドの目的です。
public enum BitmapAlignment
{
Start,
Center,
End
}
配置設定は、BitmapStretch.Fill
と一緒に使用すると、効果がありません。
最初の DrawBitmap
拡張関数には、変換先の四角形が含まれますが、変換元の四角形は含まれません。 既定では、ビットマップを中央揃えにする必要があるときに、BitmapStretch
メンバーのみを指定する必要があるよう定義されています。
static class BitmapExtensions
{
···
public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect dest,
BitmapStretch stretch,
BitmapAlignment horizontal = BitmapAlignment.Center,
BitmapAlignment vertical = BitmapAlignment.Center,
SKPaint paint = null)
{
if (stretch == BitmapStretch.Fill)
{
canvas.DrawBitmap(bitmap, dest, paint);
}
else
{
float scale = 1;
switch (stretch)
{
case BitmapStretch.None:
break;
case BitmapStretch.Uniform:
scale = Math.Min(dest.Width / bitmap.Width, dest.Height / bitmap.Height);
break;
case BitmapStretch.UniformToFill:
scale = Math.Max(dest.Width / bitmap.Width, dest.Height / bitmap.Height);
break;
}
SKRect display = CalculateDisplayRect(dest, scale * bitmap.Width, scale * bitmap.Height,
horizontal, vertical);
canvas.DrawBitmap(bitmap, display, paint);
}
}
···
}
このメソッドの主な目的は、scale
という名前のスケーリング係数を計算することです。この係数はその後、CalculateDisplayRect
メソッドを呼び出すときにビットマップの幅と高さに適用されます。 これは、水平方向と垂直方向の配置に基づいてビットマップを表示するための四角形を計算するメソッドです。
static class BitmapExtensions
{
···
static SKRect CalculateDisplayRect(SKRect dest, float bmpWidth, float bmpHeight,
BitmapAlignment horizontal, BitmapAlignment vertical)
{
float x = 0;
float y = 0;
switch (horizontal)
{
case BitmapAlignment.Center:
x = (dest.Width - bmpWidth) / 2;
break;
case BitmapAlignment.Start:
break;
case BitmapAlignment.End:
x = dest.Width - bmpWidth;
break;
}
switch (vertical)
{
case BitmapAlignment.Center:
y = (dest.Height - bmpHeight) / 2;
break;
case BitmapAlignment.Start:
break;
case BitmapAlignment.End:
y = dest.Height - bmpHeight;
break;
}
x += dest.Left;
y += dest.Top;
return new SKRect(x, y, x + bmpWidth, y + bmpHeight);
}
}
この BitmapExtensions
クラスには、追加の DrawBitmap
メソッドと共に、ビットマップのサブセットを指定するための変換元の四角形が含まれています。 このメソッドは最初のメソッドと似ていますが、スケーリング係数が source
四角形に基づいて計算された後、CalculateDisplayRect
に対する呼び出し内の source
四角形に適用される点が異なります。
static class BitmapExtensions
{
···
public static void DrawBitmap(this SKCanvas canvas, SKBitmap bitmap, SKRect source, SKRect dest,
BitmapStretch stretch,
BitmapAlignment horizontal = BitmapAlignment.Center,
BitmapAlignment vertical = BitmapAlignment.Center,
SKPaint paint = null)
{
if (stretch == BitmapStretch.Fill)
{
canvas.DrawBitmap(bitmap, source, dest, paint);
}
else
{
float scale = 1;
switch (stretch)
{
case BitmapStretch.None:
break;
case BitmapStretch.Uniform:
scale = Math.Min(dest.Width / source.Width, dest.Height / source.Height);
break;
case BitmapStretch.UniformToFill:
scale = Math.Max(dest.Width / source.Width, dest.Height / source.Height);
break;
}
SKRect display = CalculateDisplayRect(dest, scale * source.Width, scale * source.Height,
horizontal, vertical);
canvas.DrawBitmap(bitmap, source, display, paint);
}
}
···
}
これら 2 つの新しい DrawBitmap
メソッドの 1 つ目は、Scaling Modes ページで説明されています。 XAML ファイルには、BitmapStretch
および BitmapAlignment
列挙型のメンバーを選択できる 3 つの Picker
要素が含まれています。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SkiaSharpFormsDemos"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Bitmaps.ScalingModesPage"
Title="Scaling Modes">
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<skia:SKCanvasView x:Name="canvasView"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
PaintSurface="OnCanvasViewPaintSurface" />
<Label Text="Stretch:"
Grid.Row="1" Grid.Column="0"
VerticalOptions="Center" />
<Picker x:Name="stretchPicker"
Grid.Row="1" Grid.Column="1"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type local:BitmapStretch}">
<x:Static Member="local:BitmapStretch.None" />
<x:Static Member="local:BitmapStretch.Fill" />
<x:Static Member="local:BitmapStretch.Uniform" />
<x:Static Member="local:BitmapStretch.UniformToFill" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Label Text="Horizontal Alignment:"
Grid.Row="2" Grid.Column="0"
VerticalOptions="Center" />
<Picker x:Name="horizontalPicker"
Grid.Row="2" Grid.Column="1"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type local:BitmapAlignment}">
<x:Static Member="local:BitmapAlignment.Start" />
<x:Static Member="local:BitmapAlignment.Center" />
<x:Static Member="local:BitmapAlignment.End" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Label Text="Vertical Alignment:"
Grid.Row="3" Grid.Column="0"
VerticalOptions="Center" />
<Picker x:Name="verticalPicker"
Grid.Row="3" Grid.Column="1"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type local:BitmapAlignment}">
<x:Static Member="local:BitmapAlignment.Start" />
<x:Static Member="local:BitmapAlignment.Center" />
<x:Static Member="local:BitmapAlignment.End" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
</Grid>
</ContentPage>
分離コード ファイルは、Picker
項目が変更されたときに単に CanvasView
を無効にします。 PaintSurface
ハンドラーは、DrawBitmap
拡張メソッドを呼び出すための 3 つの Picker
ビューにアクセスします。
public partial class ScalingModesPage : ContentPage
{
SKBitmap bitmap =
BitmapExtensions.LoadBitmapResource(typeof(ScalingModesPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
public ScalingModesPage()
{
InitializeComponent();
}
private void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKRect dest = new SKRect(0, 0, info.Width, info.Height);
BitmapStretch stretch = (BitmapStretch)stretchPicker.SelectedItem;
BitmapAlignment horizontal = (BitmapAlignment)horizontalPicker.SelectedItem;
BitmapAlignment vertical = (BitmapAlignment)verticalPicker.SelectedItem;
canvas.DrawBitmap(bitmap, dest, stretch, horizontal, vertical);
}
}
オプションの組み合わせをいくつか次に示します。
Rectangle Subset ページには、Scaling Modes と実質的に同じ XAML ファイルがありますが、分離コード ファイルでは、SOURCE
フィールドによって指定されたビットマップの四角形のサブセットが定義されます。
public partial class ScalingModesPage : ContentPage
{
SKBitmap bitmap =
BitmapExtensions.LoadBitmapResource(typeof(ScalingModesPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
static readonly SKRect SOURCE = new SKRect(94, 12, 212, 118);
public RectangleSubsetPage()
{
InitializeComponent();
}
private void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKRect dest = new SKRect(0, 0, info.Width, info.Height);
BitmapStretch stretch = (BitmapStretch)stretchPicker.SelectedItem;
BitmapAlignment horizontal = (BitmapAlignment)horizontalPicker.SelectedItem;
BitmapAlignment vertical = (BitmapAlignment)verticalPicker.SelectedItem;
canvas.DrawBitmap(bitmap, SOURCE, dest, stretch, horizontal, vertical);
}
}
次のスクリーンショットに示すように、この四角形の変換元はサルの頭を分離します。