SkiaSharp マスク フィルター
マスク フィルターは、グラフィカル オブジェクトのジオメトリとアルファ チャネルを操作する効果です。 マスク フィルターを使用するには、SKMaskFilter
静的メソッドのいずれかを呼び出して作成した、種類が SKMaskFilter
のオブジェクトに SKPaint
の MaskFilter
プロパティを設定します。
マスク フィルターについてよく理解するための最善の方法は、これらの静的メソッドを試すことです。 最も便利なマスク フィルターは、ぼかしを作成するものです。
この記事で説明するマスク フィルター機能はそれだけです。 SkiaSharp 画像フィルターに関する次の記事では、この効果よりも好ましい場合があるぼかし効果についても説明します。
静的メソッド SKMaskFilter.CreateBlur
の構文は次のとおりです。
public static SKMaskFilter CreateBlur (SKBlurStyle blurStyle, float sigma);
オーバーロードを使用すると、ぼかしの作成に使用するアルゴリズムのフラグと、他のグラフィカル オブジェクトで覆われる領域のぼかしを回避する四角形を指定できます。
SKBlurStyle
は、次のメンバーを持つ列挙体です。
Normal
Solid
Outer
Inner
これらのスタイルの効果を次の例に示します。 sigma
パラメーターは、ぼかしの範囲を指定します。 以前のバージョンの Skia では、ぼかしの範囲は半径の値で示されていました。 アプリケーションに半径の値が適している場合は、静的メソッド SKMaskFilter.ConvertRadiusToSigma
を使用して、あるものを他のものに変換できます。 このメソッドは、半径に 0.57735 を乗算し、0.5 を加算します。
サンプルの [Mask Blur Experiment] ページでは、ぼかしスタイルとシグマ値を試すことができます。 XAML ファイルは、4 つの Picker
列挙メンバーと、シグマ値を指定するための SKBlurStyle
を使用して、Slider
をインスタンス化します。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Effects.MaskBlurExperimentPage"
Title="Mask Blur Experiment">
<StackLayout>
<skiaforms:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Picker x:Name="blurStylePicker"
Title="Filter Blur Style"
Margin="10, 0"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type skia:SKBlurStyle}">
<x:Static Member="skia:SKBlurStyle.Normal" />
<x:Static Member="skia:SKBlurStyle.Solid" />
<x:Static Member="skia:SKBlurStyle.Outer" />
<x:Static Member="skia:SKBlurStyle.Inner" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Slider x:Name="sigmaSlider"
Maximum="10"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference sigmaSlider},
Path=Value,
StringFormat='Sigma = {0:F1}'}"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
分離コード ファイルでは、それらの値を使用して SKMaskFilter
オブジェクトを作成し、それを SKPaint
オブジェクトの MaskFilter
プロパティに設定します。 この SKPaint
オブジェクトは、テキスト文字列とビットマップの両方を描画するために使用されます。
public partial class MaskBlurExperimentPage : ContentPage
{
const string TEXT = "Blur My Text";
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(MaskBlurExperimentPage),
"SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");
public MaskBlurExperimentPage ()
{
InitializeComponent ();
}
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear(SKColors.Pink);
// Get values from XAML controls
SKBlurStyle blurStyle =
(SKBlurStyle)(blurStylePicker.SelectedIndex == -1 ?
0 : blurStylePicker.SelectedItem);
float sigma = (float)sigmaSlider.Value;
using (SKPaint paint = new SKPaint())
{
// Set SKPaint properties
paint.TextSize = (info.Width - 100) / (TEXT.Length / 2);
paint.MaskFilter = SKMaskFilter.CreateBlur(blurStyle, sigma);
// Get text bounds and calculate display rectangle
SKRect textBounds = new SKRect();
paint.MeasureText(TEXT, ref textBounds);
SKRect textRect = new SKRect(0, 0, info.Width, textBounds.Height + 50);
// Center the text in the display rectangle
float xText = textRect.Width / 2 - textBounds.MidX;
float yText = textRect.Height / 2 - textBounds.MidY;
canvas.DrawText(TEXT, xText, yText, paint);
// Calculate rectangle for bitmap
SKRect bitmapRect = new SKRect(0, textRect.Bottom, info.Width, info.Height);
bitmapRect.Inflate(-50, -50);
canvas.DrawBitmap(bitmap, bitmapRect, BitmapStretch.Uniform, paint: paint);
}
}
}
ぼかしのスタイル Normal
と増加する sigma
レベルを使用した、iOS、Android、ユニバーサル Windows プラットフォーム (UWP) で実行されているプログラムを次に示します。
ビットマップの端のみがぼかしの影響を受けることがわかります。 SKMaskFilter
クラスは、ビットマップ イメージ全体をぼかす場合に使用する正しい効果ではありません。 そのため、SkiaSharp 画像フィルターに関する次の記事で説明するように、SKImageFilter
クラスを使用します。
sigma
引数の値を増やすと、テキストのぼかしが増えます。 このプログラムを使用した実験では、特定の sigma
値について、Windows 10 デスクトップでは、ぼかしがより極端であることがわかります。 この違いは、デスクトップ モニターではモバイル デバイスよりもピクセル密度が低いため、テキストの高さがピクセル単位で低くなるために発生します。 sigma
値はピクセル単位のぼかし範囲に比例するため、特定の sigma
値について、解像度の低いディスプレイでは効果がより極端になります。 実稼働アプリケーションでは、グラフィックのサイズに比例する sigma
値を計算することが必要になる場合があります。
アプリケーションに最適なぼかしレベルを決定する前に、いくつかの値を試してください。 たとえば、[Mask Blur Experiment] ページで、sigma
を次のように設定してみてください。
sigma = paint.TextSize / 18;
paint.MaskFilter = SKMaskFilter.CreateBlur(blurStyle, sigma);
現在は Slider
の効果はありませんが、ぼかしの程度はプラットフォーム間で一貫しています。
ここまでのすべてのスクリーンショットでは、SKBlurStyle.Normal
列挙メンバーで作成されたぼかしが示されています。 次のスクリーンショットは、Solid
、Outer
、Inner
のぼかしスタイルの効果を示しています。
iOS のスクリーンショットは Solid
スタイルを示しています。テキスト文字は黒の実線ストロークのままであり、ぼかしはこれらのテキスト文字の外側に追加されます。
中央の Android のスクリーンショットは、Outer
スタイルを示しています。文字ストローク自体は (ビットマップと同様に) 削除され、ぼかしはテキスト文字が表示されていた空のスペースを囲んでいます。
右側の UWP のスクリーンショットは、Inner
スタイルを示しています。 ぼかしは、テキスト文字によって通常占有される領域に制限されます。
SkiaSharp 線形グラデーションに関する記事では、線形グラデーションと変換を使用してテキスト文字列のリフレクションを模倣するリフレクション グラデーション プログラムについて説明しています。
[Blurry Reflection] ページでは、そのコードに 1 つのステートメントを追加されます。
public class BlurryReflectionPage : ContentPage
{
const string TEXT = "Reflection";
public BlurryReflectionPage()
{
Title = "Blurry Reflection";
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();
using (SKPaint paint = new SKPaint())
{
// Set text color to blue
paint.Color = SKColors.Blue;
// Set text size to fill 90% of width
paint.TextSize = 100;
float width = paint.MeasureText(TEXT);
float scale = 0.9f * info.Width / width;
paint.TextSize *= scale;
// Get text bounds
SKRect textBounds = new SKRect();
paint.MeasureText(TEXT, ref textBounds);
// Calculate offsets to position text above center
float xText = info.Width / 2 - textBounds.MidX;
float yText = info.Height / 2;
// Draw unreflected text
canvas.DrawText(TEXT, xText, yText, paint);
// Shift textBounds to match displayed text
textBounds.Offset(xText, yText);
// Use those offsets to create a gradient for the reflected text
paint.Shader = SKShader.CreateLinearGradient(
new SKPoint(0, textBounds.Top),
new SKPoint(0, textBounds.Bottom),
new SKColor[] { paint.Color.WithAlpha(0),
paint.Color.WithAlpha(0x80) },
null,
SKShaderTileMode.Clamp);
// Create a blur mask filter
paint.MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, paint.TextSize / 36);
// Scale the canvas to flip upside-down around the vertical center
canvas.Scale(1, -1, 0, yText);
// Draw reflected text
canvas.DrawText(TEXT, xText, yText, paint);
}
}
}
新しいステートメントは、テキスト サイズに基づいて、反射したテキストのぼかしフィルターを追加します。
paint.MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, paint.TextSize / 36);
このぼかしフィルターを使用すると、反射がより現実的に見えます。