SkiaSharp の透明度

Download Sampleサンプルのダウンロード

これまでに説明したように、SKPaint クラスには SKColor 型の Color プロパティが含まれています。 SKColor にはアルファ チャネルが含まれているため、SKColor 値で色分けするものは部分的に透明にすることができます。

一部の透明度は、SkiaSharp の基本アニメーションに関する記事で説明されています。 この記事では、1 つのシーンで複数のオブジェクトを結合する透明度について詳しく説明します。これは、ブレンドとも呼ばれる手法です。 より高度なブレンド手法については、「SkiaSharp シェーダー」セクションの記事で説明します。

透明度レベルは、最初に 4 つのパラメーター SKColor コンストラクターを使用して色を作成するときに設定できます。

SKColor (byte red, byte green, byte blue, byte alpha);

アルファ値 0 は完全に透明で、アルファ値 0xFF は完全に不透明です。 これら 2 つの両極端な値の間では、部分的に透明な色が作成されます。

さらに、SKColor は既存の色から新しい色を作成するのに便利な WithAlpha メソッドを定義しますが、アルファ レベルは指定されています。

SKColor halfTransparentBlue = SKColors.Blue.WithAlpha(0x80);

部分的に透明なテキストの使用については、SkiaSharpFormsDemos サンプルの [詳細なコード] ページで説明しています。 このページでは、SKColor 値に透明度を組み込むことで、2 つのテキスト文字列をフェード イン/アウトします。

public class CodeMoreCodePage : ContentPage
{
    SKCanvasView canvasView;
    bool isAnimating;
    Stopwatch stopwatch = new Stopwatch();
    double transparency;

    public CodeMoreCodePage ()
    {
        Title = "Code More Code";

        canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();

        isAnimating = true;
        stopwatch.Start();
        Device.StartTimer(TimeSpan.FromMilliseconds(16), OnTimerTick);
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        stopwatch.Stop();
        isAnimating = false;
    }

    bool OnTimerTick()
    {
        const int duration = 5;     // seconds
        double progress = stopwatch.Elapsed.TotalSeconds % duration / duration;
        transparency = 0.5 * (1 + Math.Sin(progress * 2 * Math.PI));
        canvasView.InvalidateSurface();

        return isAnimating;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        const string TEXT1 = "CODE";
        const string TEXT2 = "MORE";

        using (SKPaint paint = new SKPaint())
        {
            // Set text width to fit in width of canvas
            paint.TextSize = 100;
            float textWidth = paint.MeasureText(TEXT1);
            paint.TextSize *= 0.9f * info.Width / textWidth;

            // Center first text string
            SKRect textBounds = new SKRect();
            paint.MeasureText(TEXT1, ref textBounds);

            float xText = info.Width / 2 - textBounds.MidX;
            float yText = info.Height / 2 - textBounds.MidY;

            paint.Color = SKColors.Blue.WithAlpha((byte)(0xFF * (1 - transparency)));
            canvas.DrawText(TEXT1, xText, yText, paint);

            // Center second text string
            textBounds = new SKRect();
            paint.MeasureText(TEXT2, ref textBounds);

            xText = info.Width / 2 - textBounds.MidX;
            yText = info.Height / 2 - textBounds.MidY;

            paint.Color = SKColors.Blue.WithAlpha((byte)(0xFF * transparency));
            canvas.DrawText(TEXT2, xText, yText, paint);
        }
    }
}

transparency フィールドは 0 から 1 まで変化するようにアニメーション化され、正弦波のリズムでもう一度元に戻ります。 最初のテキスト文字列は、transparency 値を 1 から減算して計算されたアルファ値で表示されます。

paint.Color = SKColors.Blue.WithAlpha((byte)(0xFF * (1 - transparency)));

WithAlpha メソッドは、既存の色 (こちらでは SKColors.Blue) にアルファ コンポーネントを設定します。 2 番目のテキスト文字列は、transparency の値自体から計算されたアルファ値を使用します。

paint.Color = SKColors.Blue.WithAlpha((byte)(0xFF * transparency));

アニメーションは 2 つの単語を交互に使用し、ユーザーに "code more" (または "more code") を要求するよう促します。

Code More Code

前の記事の「SkiaSharp のビットマップの基本」では、SKCanvasDrawBitmap メソッドの 1 つを使用してビットマップを表示する方法を確認しました。 すべての DrawBitmap メソッドには、最後のパラメーターとして SKPaint オブジェクトが含まれます。 既定では、このパラメーターは null に設定され、無視できます。

または、この SKPaint オブジェクトの Color プロパティを設定して、ある程度の透明度を持つビットマップを表示することもできます。 SKPaintColor プロパティに透明度のレベルを設定すると、ビットマップをフェードイン/アウトしたり、ビットマップを別のビットマップにディゾルブしたりできます。

ビットマップの透明度は、[ビットマップのディゾルブ] ページで説明されています。 XAML ファイルは、次の SKCanvasViewSlider をインスタンス化します。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.BitmapDissolvePage"
             Title="Bitmap Dissolve">
    <StackLayout>
        <skia:SKCanvasView x:Name="canvasView"
                           VerticalOptions="FillAndExpand"
                           PaintSurface="OnCanvasViewPaintSurface" />

        <Slider x:Name="progressSlider"
                Margin="10"
                ValueChanged="OnSliderValueChanged" />
    </StackLayout>
</ContentPage>

分離コード ファイルは、2 つのビットマップ リソースを読み込みます。 これらのビットマップは同じサイズではありませんが、縦横比は同じです。

public partial class BitmapDissolvePage : ContentPage
{
    SKBitmap bitmap1;
    SKBitmap bitmap2;

    public BitmapDissolvePage()
    {
        InitializeComponent();

        // Load two bitmaps
        Assembly assembly = GetType().GetTypeInfo().Assembly;

        using (Stream stream = assembly.GetManifestResourceStream(
                                "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg"))
        {
            bitmap1 = SKBitmap.Decode(stream);
        }
        using (Stream stream = assembly.GetManifestResourceStream(
                                "SkiaSharpFormsDemos.Media.FacePalm.jpg"))
        {
            bitmap2 = SKBitmap.Decode(stream);
        }
    }

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

        // Find rectangle to fit bitmap
        float scale = Math.Min((float)info.Width / bitmap1.Width,
                                (float)info.Height / bitmap1.Height);
        SKRect rect = SKRect.Create(scale * bitmap1.Width,
                                    scale * bitmap1.Height);
        float x = (info.Width - rect.Width) / 2;
        float y = (info.Height - rect.Height) / 2;
        rect.Offset(x, y);

        // Get progress value from Slider
        float progress = (float)progressSlider.Value;

        // Display two bitmaps with transparency
        using (SKPaint paint = new SKPaint())
        {
            paint.Color = paint.Color.WithAlpha((byte)(0xFF * (1 - progress)));
            canvas.DrawBitmap(bitmap1, rect, paint);

            paint.Color = paint.Color.WithAlpha((byte)(0xFF * progress));
            canvas.DrawBitmap(bitmap2, rect, paint);
        }
    }
}

SKPaint オブジェクトの Color プロパティは、2 つのビットマップの 2 つの補完的なアルファ レベルに設定されます。 ビットマップを含む SKPaint を使用する場合、Color 値の残りの部分は関係ありません。 重要なのはアルファ チャネルです。 ここでのコードは、Color プロパティの既定値で WithAlpha メソッドを呼び出すだけです。

Slider を移動させると、1 つのビットマップともう一方のビットマップの間でディゾルブします。

Bitmap Dissolve

過去のいくつかの記事では、SkiaSharp を使用してテキスト、円、楕円、角丸四角形、ビットマップを描画する方法について説明しました。 次の手順は SkiaSharp の線とパスで、グラフィックス パスに接続された線を描画する方法を学習します。