Режимы наложения Duff ПортерPorter-Duff blend modes

Загрузить образец загрузить примерDownload Sample Download the sample

Режимы наложения Портер Duff названы Томас Портер и Tom Duff, являющейся разработчиком алгебры компоновки, работая в Lucasfilm.The Porter-Duff blend modes are named after Thomas Porter and Tom Duff, who developed an algebra of compositing while working for Lucasfilm. Свой документ цифровых изображений композиции была опубликована в выпуске за июль 1984 компьютерной графике, страницы 253 для 259 знаков.Their paper Compositing Digital Images was published in the July 1984 issue of Computer Graphics, pages 253 to 259. Эти режимы смешения крайне важны для композиции, в которой сборка различных изображений составного сцены:These blend modes are essential for compositing, which is assembling various images into a composite scene:

Пример Портер DuffPorter-Duff Sample

Основные понятия Duff ПортерPorter-Duff concepts

Предположим, что прямоугольник коричневом занимает левом и верхнем две трети поверхность отображения:Suppose a brownish rectangle occupies the left and top two-thirds of your display surface:

Назначение Портер DuffPorter-Duff Destination

Эта область называется назначения или иногда фона или backdrop.This area is called the destination or sometimes the background or backdrop.

Требуется нарисовать следующие прямоугольник, который соответствует размеру массива назначения.You wish to draw the following rectangle, which is the same size of the destination. Прямоугольник является прозрачным за исключением голубовато область, которая занимает вправо и вниз на две трети:The rectangle is transparent except for a bluish area that occupies the right and bottom two-thirds:

Источник Портер DuffPorter-Duff Source

Это называется источника или иногда переднего плана.This is called the source or sometimes the foreground.

При отображении источник на сервере назначения, вот что нужно:When you display the source on the destination, here's what you expect:

Исходный код Портер DuffPorter-Duff Source Over

Прозрачных точек источника разрешить фона видны сквозь, хотя голубовато исходные точки скрывать фона.The transparent pixels of the source allow the background to show through, while the bluish source pixels obscure the background. Это обычный так, и он упоминается в SkiaSharp как SKBlendMode.SrcOver.That's the normal case, and it is referred to in SkiaSharp as SKBlendMode.SrcOver. Значение по умолчанию BlendMode свойство при SKPaint сначала создается экземпляр объекта.That value is the default setting of the BlendMode property when an SKPaint object is first instantiated.

Тем не менее можно указать режим разных наложения для другой эффект.However, it's possible to specify a different blend mode for a different effect. Если указать SKBlendMode.DstOver, а затем в области пересечения исходного и конечного назначения отображается вместо источника:If you specify SKBlendMode.DstOver, then in the area where the source and destination intersect, the destination appears instead of the source:

Назначения Портер Duff надPorter-Duff Destination Over

SKBlendMode.DstIn Blend режиме отображается только область, источника и назначения пересечения с помощью назначения цвета:The SKBlendMode.DstIn blend mode displays only the area where the destination and source intersect using the destination color:

Назначения Портер Duff вPorter-Duff Destination In

Режим наложения SKBlendMode.Xor (исключающее или) вызывает ничего не отображается, перекрытия двух областей:The blend mode of SKBlendMode.Xor (exclusive OR) causes nothing to appear where the two areas overlap:

Портер Duff исключающего илиPorter-Duff Exclusive Or

Цветных прямоугольников источника и назначения эффективно разделить поверхность отображения четыре уникальных областей, которые можно окрасить различными способами, соответствующий наличие прямоугольников источника и назначения:The colored destination and source rectangles effectively divide the display surface into four unique areas that can be colored in various ways corresponding to the presence of the destination and source rectangles:

Портер DuffPorter-Duff

Прямоугольники верхний правый и левый нижний всегда будут пустыми, так как в исходном и целевом прозрачны в этих областях.The upper-right and lower-left rectangles are always blank because both the destination and source are transparent in those areas. Конечный цвет занимает область верхнего левого, таким образом, чтобы область можно окрасить, либо с цветом назначения или вообще не.The destination color occupies the upper-left area, so that area can either be colored with the destination color or not at all. Аналогичным образом исходного цвета занимает область нижний правый, таким образом, чтобы область будут выделены цветом с цветом источника или вообще не.Similarly, the source color occupies the lower-right area, so that area can be colored with the source color or not at all. Пересечение источника в середине и назначения будут выделены цветом с цветом назначения, цвет источника или вообще не.The intersection of the destination and source in the middle can be colored with the destination color, the source color, or not at all.

Общее число комбинаций — 2 (для левом верхнем углу), время 2 (внизу справа) раз 3 (для центра) или 12.The total number of combinations is 2 (for the upper-left) times 2 (for the lower-right) times 3 (for the center), or 12. Ниже приведены 12 основных режима Портер Duff композиции.These are the 12 basic Porter-Duff compositing modes.

Ближе к концу цифровых изображений композиции (страница 256), Портер и Duff Добавление 13-й режима называется , а также (соответствующий SkiaSharp SKBlendMode.Plus член и W3C светлее режим (которого не следует путать с W3C «Замена светлым» режиме.) Это Plus режим добавляет исходного и конечного цветов, процесс, который описывается более подробно чуть ниже.Towards the end of Compositing Digital Images (page 256), Porter and Duff add a 13th mode called plus (corresponding to the SkiaSharp SKBlendMode.Plus member and the W3C Lighter mode (which is not to be confused with the W3C Lighten mode.) This Plus mode adds the destination and source colors, a process that will be described in more detail shortly.

Skia добавляет имеется 14-й режим Modulate это очень похоже на Plus за исключением того, что при умножении исходного и конечного цветов.Skia adds a 14th mode called Modulate that is very similar to Plus except that the destination and source colors are multiplied. Он может рассматриваться как дополнительный режим наложения Duff Портер.It can be treated as an additional Porter-Duff blend mode.

Ниже приведены режимы 14 Duff Портер, как определено в SkiaSharp.Here are the 14 Porter-Duff modes as defined in SkiaSharp. В таблице показано, как они цвет каждого из трех областей непустой на схеме выше:The table shows how they color each of the three non-blank areas in the diagram above:

РежимMode НазначениеDestination ПересечениеIntersection Исходный кодSource
Clear
Src Исходный кодSource XX
Dst XX НазначениеDestination
SrcOver XX Исходный кодSource XX
DstOver XX НазначениеDestination XX
SrcIn Исходный кодSource
DstIn НазначениеDestination
SrcOut XX
DstOut XX
SrcATop XX Исходный кодSource
DstATop НазначениеDestination XX
Xor XX XX
Plus XX SumSum XX
Modulate ПродуктProduct

Эти режимы смешения являются симметричными.These blend modes are symmetrical. Может быть передано источник и назначение и все режимы по-прежнему доступны.The source and destination can be exchanged and all the modes are still available.

Соглашение об именовании из режимов следует за несколько простых правил:The naming convention of the modes follows a few simple rules:

  • Src или перехода на летнее время сама по себе означает, что только пиксели источника или назначения являются видимыми.Src or Dst by itself means that only the source or destination pixels are visible.
  • Через суффикс указывает, что отображается на пересечении.The Over suffix indicates what is visible in the intersection. Исходных или целевых рисуется «по».Either the source or destination is drawn "over" the other.
  • В суффикс означает, что только пересечение окрашивается.The In suffix means that only the intersection is colored. Выходные данные ограничено только часть источнике или назначении «в» другой.The output is restricted to only the part of the source or destination that is "in" the other.
  • Out суффикс означает, что пересечение не окрашивается.The Out suffix means that the intersection is not colored. Выводится только часть источника или назначения, «out» пересечения.The output is only the part of the source or destination that is "out" of the intersection.
  • Поверх суффикс представляет собой объединение в и Out. Он включает в себя область, в котором источник или назначение «поверх» другого.The ATop suffix is the union of In and Out. It includes the area where the source or destination is "atop" of the other.

Обратите внимание на разницу с Plus и Modulate режимы.Notice the difference with the Plus and Modulate modes. Эти режимы выполнении пиксели исходного и целевого другой тип вычисления.These modes are performing a different type of calculation on the source and destination pixels. Они описаны более подробно чуть ниже.They are described in more detail shortly.

Портер Duff сетки странице перечислены все 14 режимы на одном экране в виде сетки.The Porter-Duff Grid page shows all 14 modes on one screen in the form of a grid. В каждом режиме — это отдельный экземпляр SKCanvasView.Each mode is a separate instance of SKCanvasView. По этой причине класс, производный от SKCanvasView с именем PorterDuffCanvasView.For that reason, a class is derived from SKCanvasView named PorterDuffCanvasView. Статический конструктор создает два точечные рисунки такого же размера, один коричневом прямоугольник, в его левом верхнем области, а другой голубовато прямоугольником.The static constructor creates two bitmaps of the same size, one with a brownish rectangle in its upper-left area and another with a bluish rectangle:

class PorterDuffCanvasView : SKCanvasView
{
    static SKBitmap srcBitmap, dstBitmap;

    static PorterDuffCanvasView()
    {
        dstBitmap = new SKBitmap(300, 300);
        srcBitmap = new SKBitmap(300, 300);

        using (SKPaint paint = new SKPaint())
        {
            using (SKCanvas canvas = new SKCanvas(dstBitmap))
            {
                canvas.Clear();
                paint.Color = new SKColor(0xC0, 0x80, 0x00);
                canvas.DrawRect(new SKRect(0, 0, 200, 200), paint);
            }
            using (SKCanvas canvas = new SKCanvas(srcBitmap))
            {
                canvas.Clear();
                paint.Color = new SKColor(0x00, 0x80, 0xC0);
                canvas.DrawRect(new SKRect(100, 100, 300, 300), paint);
            }
        }
    }
    ···
}

Конструктор экземпляра имеет параметр типа SKBlendMode.The instance constructor has a parameter of type SKBlendMode. Она сохраняет этот параметр в поле.It saves this parameter in a field.

class PorterDuffCanvasView : SKCanvasView
{
    ···
    SKBlendMode blendMode;

    public PorterDuffCanvasView(SKBlendMode blendMode)
    {
        this.blendMode = blendMode;
    }

    protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Find largest square that fits
        float rectSize = Math.Min(info.Width, info.Height);
        float x = (info.Width - rectSize) / 2;
        float y = (info.Height - rectSize) / 2;
        SKRect rect = new SKRect(x, y, x + rectSize, y + rectSize);

        // Draw destination bitmap
        canvas.DrawBitmap(dstBitmap, rect);

        // Draw source bitmap
        using (SKPaint paint = new SKPaint())
        {
            paint.BlendMode = blendMode;
            canvas.DrawBitmap(srcBitmap, rect, paint);
        }

        // Draw outline
        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Black;
            paint.StrokeWidth = 2;
            rect.Inflate(-1, -1);
            canvas.DrawRect(rect, paint);
        }
    }
}

OnPaintSurface Переопределение рисует два точечные рисунки.The OnPaintSurface override draws the two bitmaps. Первый рисуется обычно:The first is drawn normally:

canvas.DrawBitmap(dstBitmap, rect);

С помощью которого нарисован второй SKPaint объекта где BlendMode свойство значение аргумента конструктора:The second is drawn with an SKPaint object where the BlendMode property has been set to the constructor argument:

using (SKPaint paint = new SKPaint())
{
    paint.BlendMode = blendMode;
    canvas.DrawBitmap(srcBitmap, rect, paint);
}

В оставшейся части OnPaintSurface переопределение рисует прямоугольник вокруг растровое изображение, чтобы указать их размер.The remainder of the OnPaintSurface override draws a rectangle around the bitmap to indicate their sizes.

PorterDuffGridPage Класс создает экземпляры Четырнадцать PorterDurffCanvasView, один для каждого члена blendModes массива.The PorterDuffGridPage class creates fourteen instances of PorterDurffCanvasView, one for each member of the blendModes array. Порядок SKBlendModes элементов в массиве немного отличается от имени таблицы для расположения аналогичные режимы рядом друг с другом.The order of the SKBlendModes members in the array is a little different than the table in order to position similar modes adjacent to each other. 14 экземпляров PorterDuffCanvasView упорядочены с метками в Grid:The 14 instances of PorterDuffCanvasView are organized along with labels in a Grid:

public class PorterDuffGridPage : ContentPage
{
    public PorterDuffGridPage()
    {
        Title = "Porter-Duff Grid";

        SKBlendMode[] blendModes =
        {
            SKBlendMode.Src, SKBlendMode.Dst, SKBlendMode.SrcOver, SKBlendMode.DstOver,
            SKBlendMode.SrcIn, SKBlendMode.DstIn, SKBlendMode.SrcOut, SKBlendMode.DstOut,
            SKBlendMode.SrcATop, SKBlendMode.DstATop, SKBlendMode.Xor, SKBlendMode.Plus,
            SKBlendMode.Modulate, SKBlendMode.Clear
        };

        Grid grid = new Grid
        {
            Margin = new Thickness(5)
        };

        for (int row = 0; row < 4; row++)
        {
            grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
            grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star });
        }

        for (int col = 0; col < 3; col++)
        {
            grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
        }

        for (int i = 0; i < blendModes.Length; i++)
        {
            SKBlendMode blendMode = blendModes[i];
            int row = 2 * (i / 4);
            int col = i % 4;

            Label label = new Label
            {
                Text = blendMode.ToString(),
                HorizontalTextAlignment = TextAlignment.Center
            };
            Grid.SetRow(label, row);
            Grid.SetColumn(label, col);
            grid.Children.Add(label);

            PorterDuffCanvasView canvasView = new PorterDuffCanvasView(blendMode);

            Grid.SetRow(canvasView, row + 1);
            Grid.SetColumn(canvasView, col);
            grid.Children.Add(canvasView);
        }

        Content = grid;
    }
}

Ниже приведен результат.Here's the result:

Сетка Портер DuffPorter-Duff Grid

Необходимо убедиться, что прозрачность крайне важны для правильной работы режимов смешения Портер Duff.You'll want to convince yourself that transparency is crucial to the proper functioning of the Porter-Duff blend modes. PorterDuffCanvasView Класс содержит всего три вызова Canvas.Clear метод.The PorterDuffCanvasView class contains a total of three calls to the Canvas.Clear method. Все из них используют метод без параметров, который задает все пиксели прозрачным:All of them use the parameterless method, which sets all the pixels to transparent:

canvas.Clear();

Попробуйте изменении любого из этих вызовов, таким образом, пиксели непрозрачный белый.Try changing any of those calls so that the pixels are set to opaque white:

canvas.Clear(SKColors.White);

После этого изменения некоторые из режимов смешения будет казаться, что для работы, а другие нет.Following that change, some of the blend modes will seem to work, but others will not. Если задать фон исходного растрового изображения на белый, а затем SrcOver режиме не работает, так как в исходное растровое изображение, чтобы разрешить назначение видны сквозь нет прозрачных точек.If you set the background of the source bitmap to white, then the SrcOver mode doesn't work because there's no transparent pixels in the source bitmap to let the destination show through. Если задать фон точечный рисунок назначения или холста, чтобы белого, затем DstOver не работает, так как назначение не имеет любой прозрачных точек.If you set the background of the destination bitmap or the canvas to white, then DstOver doesn't work because the destination doesn't have any transparent pixels.

Возможно, есть возможность замены точечных рисунков в Портер Duff сетки страницы с простой DrawRect вызовы.There might be a temptation to replace the bitmaps in the Porter-Duff Grid page with simpler DrawRect calls. Который будет работать для целевого прямоугольника, но не для исходного прямоугольника.That will work for the destination rectangle but not for the source rectangle. Исходный прямоугольник должен охватывать не только области сине цветные.The source rectangle must encompass more than just the bluish-colored area. Исходный прямоугольник должен включать прозрачной области, соответствующий цветная область назначения.The source rectangle must include a transparent area that corresponds to the colored area of the destination. Только после этого они будут blend режимы работы.Only then will these blend modes work.

Использование при задании с Duff ПортерUsing mattes with Porter-Duff

На странице « композиция» для развертывания на основе кирпича показан пример классической задачи компоновки: Необходимо собрать изображение из нескольких частей, включая точечный рисунок с фоновым рисунком, который необходимо устранить.The Brick-Wall Compositing page shows an example of a classic compositing task: A picture needs to be assembled from several pieces, including a bitmap with a background that needs to be eliminated. Вот SeatedMonkey.jpg растровое изображение со проблемных фоном:Here's the SeatedMonkey.jpg bitmap with the problematic background:

Сидели MonkeySeated Monkey

В процессе подготовки к композиции, соответствующий матовой был создан, это другой точечного рисунка, который является черной, где требуется для изображения и прозрачно, в противном случае.In preparation for compositing, a corresponding matte was created, which is another bitmap that is black where you want the image to appear and transparent otherwise. Этот файл называется SeatedMonkeyMatte.png и в том числе ресурсы в мультимедиа папку в SkiaSharpFormsDemos образца :This file is named SeatedMonkeyMatte.png and is among the resources in the Media folder in the SkiaSharpFormsDemos sample:

Сидели матовой MonkeySeated Monkey Matte

Это не продукте созданный подложки.This is not an expertly created matte. Лучше всего подложки должна содержать частично прозрачных точек вокруг области черных пикселей, и этот матовой — нет.Optimally, the matte should include partially transparent pixels around the edge of the black pixels, and this matte does not.

Файл XAML для Упираетесь в стену композиции создает страницу SKCanvasView и Button , проводит пользователя через процесс создания окончательного образа:The XAML file for the Brick-Wall Compositing page instantiates an SKCanvasView and a Button that guides the user through the process of composing the final image:

<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.BrickWallCompositingPage"
             Title="Brick-Wall Compositing">

    <StackLayout>
        <skia:SKCanvasView x:Name="canvasView"
                           VerticalOptions="FillAndExpand"
                           PaintSurface="OnCanvasViewPaintSurface" />

        <Button Text="Show sitting monkey"
                HorizontalOptions="Center"
                Margin="0, 10"
                Clicked="OnButtonClicked" />

    </StackLayout>
</ContentPage>

Файл с выделенным кодом загружает два точечные рисунки, которые требуются и обрабатывает Clicked событие Button.The code-behind file loads the two bitmaps that it needs and handles the Clicked event of the Button. Для каждого Button нажмите кнопку, step поле увеличивается и запускается новый Text задано для Button.For every Button click, the step field is incremented and a new Text property is set for the Button. Когда step достигает 5, он снова установить значение 0:When step reaches 5, it is set back to 0:

public partial class BrickWallCompositingPage : ContentPage
{
    SKBitmap monkeyBitmap = BitmapExtensions.LoadBitmapResource(
        typeof(BrickWallCompositingPage), 
        "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");

    SKBitmap matteBitmap = BitmapExtensions.LoadBitmapResource(
        typeof(BrickWallCompositingPage), 
        "SkiaSharpFormsDemos.Media.SeatedMonkeyMatte.png");

    int step = 0;

    public BrickWallCompositingPage ()
    {
        InitializeComponent ();
    }

    void OnButtonClicked(object sender, EventArgs args)
    {
        Button btn = (Button)sender;
        step = (step + 1) % 5;

        switch (step)
        {
            case 0: btn.Text = "Show sitting monkey"; break;
            case 1: btn.Text = "Draw matte with DstIn"; break;
            case 2: btn.Text = "Draw sidewalk with DstOver"; break;
            case 3: btn.Text = "Draw brick wall with DstOver"; break;
            case 4: btn.Text = "Reset"; break;
        }

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

        canvas.Clear();
        ···
    }
}

При первом запуске программы, ничто не является видимым, за исключением Button:When the program first runs, nothing is visible except the Button:

Упираетесь в стену независимую 0Brick-Wall Compositing Step 0

Нажав клавишу Button раза возникает step увеличивается на 1 и PaintSurface обработчик теперь отображает SeatedMonkey.jpg:Pressing the Button once causes step to increment to 1, and the PaintSurface handler now displays SeatedMonkey.jpg:

public partial class BrickWallCompositingPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        ···
        float x = (info.Width - monkeyBitmap.Width) / 2;
        float y = info.Height - monkeyBitmap.Height;

        // Draw monkey bitmap
        if (step >= 1)
        {
            canvas.DrawBitmap(monkeyBitmap, x, y);
        }
        ···
    }
}

Существует не SKPaint объекта и, следовательно режим без наложения.There's no SKPaint object and hence no blend mode. Точечный рисунок отображается в нижней части экрана:The bitmap appears at the bottom of the screen:

Упираетесь в стену независимую 1Brick-Wall Compositing Step 1

Нажмите клавишу Button еще раз и step с шагом 2.Press the Button again and step increments to 2. Это наиболее важную операцию отображения SeatedMonkeyMatte.png файла:This is the crucial step of displaying the SeatedMonkeyMatte.png file:

public partial class BrickWallCompositingPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        ···
        // Draw matte to exclude monkey's surroundings
        if (step >= 2)
        {
            using (SKPaint paint = new SKPaint())
            {
                paint.BlendMode = SKBlendMode.DstIn;
                canvas.DrawBitmap(matteBitmap, x, y, paint);
            }
        }
        ···
    }
}

Режим blend — SKBlendMode.DstIn, что означает, что назначение будет сохранен в области, соответствующие непрозрачные области источника.The blend mode is SKBlendMode.DstIn, which means that the destination will be preserved in areas corresponding to non-transparent areas of the source. В оставшейся части прямоугольник назначения, соответствующего исходного растрового изображения становится прозрачной:The remainder of the destination rectangle corresponding to the original bitmap becomes transparent:

Упираетесь в стену независимую 2Brick-Wall Compositing Step 2

Фон был удален.The background has been removed.

Следующим шагом является рисование прямоугольника, похожий на тротуара, на тебя monkey.The next step is to draw a rectangle that resembles a sidewalk that the monkey is sitting on. Внешний вид этого тротуара основан на сочетание двух шейдеры: шейдера сплошным цветом и шейдера шума Перлина:The appearance of this sidewalk is based on a composition of two shaders: a solid color shader and a Perlin noise shader:

public partial class BrickWallCompositingPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        ···
        const float sidewalkHeight = 80;
        SKRect rect = new SKRect(info.Rect.Left, info.Rect.Bottom - sidewalkHeight,
                                 info.Rect.Right, info.Rect.Bottom);

        // Draw gravel sidewalk for monkey to sit on
        if (step >= 3)
        {
            using (SKPaint paint = new SKPaint())
            {
                paint.Shader = SKShader.CreateCompose(
                                    SKShader.CreateColor(SKColors.SandyBrown),
                                    SKShader.CreatePerlinNoiseTurbulence(0.1f, 0.3f, 1, 9));

                paint.BlendMode = SKBlendMode.DstOver;
                canvas.DrawRect(rect, paint);
            }
        }
        ···
    }
}

Так как этот тротуара должны проходить за monkey, режим blend — DstOver.Because this sidewalk must go behind the monkey, the blend mode is DstOver. Назначение появляется, только когда фон будет прозрачным:The destination appears only where the background is transparent:

Упираетесь в стену независимую 3Brick-Wall Compositing Step 3

Последним шагом является добавление упираетесь в стену.The final step is adding a brick wall. Программа использует доступные плитку точечного рисунка упираетесь в стену как статическое свойство BrickWallTile в AlgorithmicBrickWallPage класса.The program uses the brick-wall bitmap tile available as the static property BrickWallTile in the AlgorithmicBrickWallPage class. Добавляется преобразованию SKShader.CreateBitmap вызова необходимо сдвинуть плитки, таким образом, а нижняя строка — это полный Плитка:A translation transform is added to the SKShader.CreateBitmap call to shift the tiles so that the bottom row is a full tile:

public partial class BrickWallCompositingPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        ···
        // Draw bitmap tiled brick wall behind monkey
        if (step >= 4)
        {
            using (SKPaint paint = new SKPaint())
            {
                SKBitmap bitmap = AlgorithmicBrickWallPage.BrickWallTile;
                float yAdjust = (info.Height - sidewalkHeight) % bitmap.Height;

                paint.Shader = SKShader.CreateBitmap(bitmap,
                                                     SKShaderTileMode.Repeat,
                                                     SKShaderTileMode.Repeat,
                                                     SKMatrix.MakeTranslation(0, yAdjust));
                paint.BlendMode = SKBlendMode.DstOver;
                canvas.DrawRect(info.Rect, paint);
            }
        }
    }
}

Для удобства DrawRect вызовов будет отображен этот шейдер весь холст, но DstOver режим ограничивает выходные данные только в области холста, по-прежнему прозрачное:For convenience, the DrawRect call displays this shader over the entire canvas, but the DstOver mode limits the output to only the area of the canvas that is still transparent:

Упираетесь в стену независимую 4Brick-Wall Compositing Step 4

Очевидно, что существуют другие способы создания этой сценой.Obviously there are other ways to compose this scene. Его можно построить и запуск в фоновом режиме и выполняется на переднем плане.It could be built up starting at the background and progressing to the foreground. Но использование режимов blend обеспечивает большую гибкость.But using the blend modes gives you more flexibility. В частности использование подложки позволяет фона растрового изображения должны быть исключены из составных сцены.In particular, the use of the matte allows the background of a bitmap to be excluded from the composed scene.

Как было указано в статье отсеченные области с помощью путей, SKCanvas класс определяет три вида обрезки, соответствующий ClipRect , ClipPath , и ClipRegion методы.As you learned in the article Clipping with Paths and Regions, the SKCanvas class defines three types of clipping, corresponding to the ClipRect, ClipPath, and ClipRegion methods. Режимы наложения Портер Duff добавьте еще один тип обрезки, что позволяет ограничить изображения для все, что можно рисовать, включая точечные рисунки.The Porter-Duff blend modes add another type of clipping, which allows restricting an image to anything that you can draw, including bitmaps. Матовый, используемых в Упираетесь в стену композиции фактически определяет области отсечения.The matte used in Brick-Wall Compositing essentially defines a clipping area.

Градиента прозрачности и переходыGradient transparency and transitions

Примеры Портер-Duff blend режимы, показанный ранее в этой статье все использовали образы, которые состоял из непрозрачными и прозрачных точек, но не частично прозрачных точек.The examples of the Porter-Duff blend modes shown earlier in this article have all involved images that consisted of opaque pixels and transparent pixels, but not partially transparent pixels. Для этих пикселей, а также определения функций режим наложения.The blend-mode functions are defined for those pixels as well. В следующей таблице приведен более формальное определение режимов смешения Duff Портер, представление, в Skia ссылку SkBlendMode.The following table is a more formal definition of the Porter-Duff blend modes that uses notation found in the Skia SkBlendMode Reference. (Поскольку SkBlendMode ссылка является ссылкой на Skia, используется синтаксис C++.)(Because SkBlendMode Reference is a Skia reference, C++ syntax is used.)

По существу красного, зеленого, синего и альфа-компоненты каждого пикселя преобразуются из байтов в числа с плавающей запятой в диапазоне от 0 до 1.Conceptually, the red, green, blue, and alpha components of each pixel are converted from bytes to floating-point numbers in the range of 0 to 1. Для альфа-канала 0 — полностью прозрачное, а 1 — полностью непрозрачныйFor the alpha channel, 0 is fully transparent and 1 is fully opaque

В следующей таблице используются следующие сокращения:The notation in the table below uses the following abbreviations:

  • DA альфа-канал назначенияDa is the destination alpha channel
  • Контроллер домена является местом назначения цвета RGBDc is the destination RGB color
  • Sa является исходный альфа-каналSa is the source alpha channel
  • SC является источником цвета RGBSc is the source RGB color

Цвета RGB предварительно умноженное альфа-значение.The RGB colors are pre-multiplied by the alpha value. Например если Sc представляет чистые red, но Sa равно 0x80, является цвета RGB (0x80, 0, 0) .For example, if Sc represents pure red but Sa is 0x80, then the RGB color is (0x80, 0, 0). Если Sa равно 0, то все компоненты RGB также равны нулю.If Sa is 0, then all the RGB components are also zero.

Результат отображается в квадратных скобках с альфа-канала и содержать запятую цвета RGB: [альфа-канал, цвет] .The result is shown in brackets with the alpha channel and the RGB color separated by a comma: [alpha, color]. Цвета Расчет выполняется отдельно для красного, зеленого и синего компонентов:For the color, the calculation is performed separately for the red, green, and blue components:

РежимMode ОперацияOperation
Clear [0, 0][0, 0]
Src [Sa, Sc][Sa, Sc]
Dst [Da, контроллер домена][Da, Dc]
SrcOver [Sa + Da· (1 — Sa), Sc + Dc· (1 — Sa)[Sa + Da·(1 – Sa), Sc + Dc·(1 – Sa)
DstOver [Da + Sa· (1 — Да), Dc + Sc· (1 — Da)[Da + Sa·(1 – Da), Dc + Sc·(1 – Da)
SrcIn [Sa· DA Sc· DA][Sa·Da, Sc·Da]
DstIn [Da· SA, Dc· SA][Da·Sa, Dc·Sa]
SrcOut [Sa· (1 — Да), Sc· (1 — Da)][Sa·(1 – Da), Sc·(1 – Da)]
DstOut [Da· (1 — Sa), Dc· (1 — Sa)][Da·(1 – Sa), Dc·(1 – Sa)]
SrcATop [Da, Sc· DA + Dc· (1 — Sa)][Da, Sc·Da + Dc·(1 – Sa)]
DstATop [Sa, Dc· SA + Sc· (1 — Da)][Sa, Dc·Sa + Sc·(1 – Da)]
Xor [Sa + Da — 2· SA· DA Sc· (1 — Da) + Dc· (1 — Sa)][Sa + Da – 2·Sa·Da, Sc·(1 – Da) + Dc·(1 – Sa)]
Plus [Sa + Da, Sc + Dc][Sa + Da, Sc + Dc]
Modulate [Sa· DA Sc· Контроллер домена][Sa·Da, Sc·Dc]

Эти операции удобны для анализа, когда Da и Sa являются 0 или 1.These operations are easier to analyze when Da and Sa are either 0 or 1. Например, значение по умолчанию SrcOver режим, если Sa равна 0, то Sc является также 0, а результат — [Da, контроллер домена] , альфа-канал назначения и цвет.For example, for the default SrcOver mode, if Sa is 0, then Sc is also 0, and the result is [Da, Dc], the destination alpha and color. Если Sa имеет значение 1, то результат тоже [Sa, Sc] , цвет и альфа-версия источника или [1, Sc] .If Sa is 1, then the result is [Sa, Sc], the source alpha and color, or [1, Sc].

Plus И Modulate режимы немного отличаются от других тем, что новые цвета может быть результатом сочетания источника и назначения.The Plus and Modulate modes are a little different from the others in that new colors can result from the combination of the source and the destination. Plus Режим может интерпретироваться с помощью байтов компоненты или компоненты с плавающей запятой.The Plus mode can be interpreted either with byte components or floating-point components. В сетки Портер Duff страницы, приведенной выше, является цветом назначения (0xC0, 0x80, 0x00) и цвет источника (0x00, 0x80, 0xC0) .In the Porter-Duff Grid page shown earlier, the destination color is (0xC0, 0x80, 0x00) and the source color is (0x00, 0x80, 0xC0). Каждая пара компонентов добавляется, но сумма присваивается в 0xFF.Each pair of components is added but the sum is clamped at 0xFF. Результатом является цвет (0xC0, 0xFF, 0xC0) .The result is the color (0xC0, 0xFF, 0xC0). Это показано на пересечении цвет.That's the color shown in the intersection.

Для Modulate режиме, необходимо преобразовать к с плавающей запятой значения RGB.For the Modulate mode, the RGB values must be converted to floating-point. Конечный цвет (0,75, 0,5, 0) , а источник (0, 0,5, 0,75) .The destination color is (0.75, 0.5, 0) and the source is (0, 0.5, 0.75). RGB компонентами являются каждого умножением и в результате (0, 0,25, 0) .The RGB components are each multiplied together, and the result is (0, 0.25, 0). Это показано на пересечении цвет Портер Duff сетки страницы для этого режима.That's the color shown in the intersection in the Porter-Duff Grid page for this mode.

Портер Duff прозрачности страница позволяет изучить принципы работы режимов смешения Портер Duff на графические объекты, которые частично прозрачных точек.The Porter-Duff Transparency page allows you to examine how the Porter-Duff blend modes operate on graphical objects that are partially transparent. Файл XAML включает Picker с режимами Портер Duff:The XAML file includes a Picker with the Porter-Duff modes:

<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:skiaviews="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Effects.PorterDuffTransparencyPage"
             Title="Porter-Duff Transparency">

    <StackLayout>
        <skiaviews:SKCanvasView x:Name="canvasView"
                                VerticalOptions="FillAndExpand"
                                PaintSurface="OnCanvasViewPaintSurface" />

        <Picker x:Name="blendModePicker"
                Title="Blend Mode"
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKBlendMode}">
                    <x:Static Member="skia:SKBlendMode.Clear" />
                    <x:Static Member="skia:SKBlendMode.Src" />
                    <x:Static Member="skia:SKBlendMode.Dst" />
                    <x:Static Member="skia:SKBlendMode.SrcOver" />
                    <x:Static Member="skia:SKBlendMode.DstOver" />
                    <x:Static Member="skia:SKBlendMode.SrcIn" />
                    <x:Static Member="skia:SKBlendMode.DstIn" />
                    <x:Static Member="skia:SKBlendMode.SrcOut" />
                    <x:Static Member="skia:SKBlendMode.DstOut" />
                    <x:Static Member="skia:SKBlendMode.SrcATop" />
                    <x:Static Member="skia:SKBlendMode.DstATop" />
                    <x:Static Member="skia:SKBlendMode.Xor" />
                    <x:Static Member="skia:SKBlendMode.Plus" />
                    <x:Static Member="skia:SKBlendMode.Modulate" />
                </x:Array>
            </Picker.ItemsSource>

            <Picker.SelectedIndex>
                3
            </Picker.SelectedIndex>
        </Picker>
    </StackLayout>
</ContentPage>

Файл с выделенным кодом заполняет два прямоугольника одного размера с помощью линейного градиента.The code-behind file fills two rectangles of the same size using a linear gradient. Градиент назначения представляет собой из верхней прямо в нижнем левом углу.The destination gradient is from the upper right to the lower left. Коричневом в правом верхнем углу, но затем к центру начинается постепенное исчезновение прозрачным и прозрачно в левом нижнем углу.It is brownish in the upper-right corner but then towards the center begins fading to transparent, and is transparent in the lower-left corner.

Исходного прямоугольника имеет градиент от левого верхнего угла до правого нижнего угла.The source rectangle has a gradient from the upper left to the lower right. Верхнего левого угла голубовато, но снова выцветает до прозрачным и прозрачно в правом нижнем углу.The upper-left corner is bluish but again fades to transparent, and is transparent in the lower-right corner.

public partial class PorterDuffTransparencyPage : ContentPage
{
    public PorterDuffTransparencyPage()
    {
        InitializeComponent();
    }

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

        // Make square display rectangle smaller than canvas
        float size = 0.9f * Math.Min(info.Width, info.Height);
        float x = (info.Width - size) / 2;
        float y = (info.Height - size) / 2;
        SKRect rect = new SKRect(x, y, x + size, y + size);

        using (SKPaint paint = new SKPaint())
        {
            // Draw destination
            paint.Shader = SKShader.CreateLinearGradient(
                                new SKPoint(rect.Right, rect.Top),
                                new SKPoint(rect.Left, rect.Bottom),
                                new SKColor[] { new SKColor(0xC0, 0x80, 0x00),
                                                new SKColor(0xC0, 0x80, 0x00, 0) },
                                new float[] { 0.4f, 0.6f },
                                SKShaderTileMode.Clamp);

            canvas.DrawRect(rect, paint);

            // Draw source
            paint.Shader = SKShader.CreateLinearGradient(
                                new SKPoint(rect.Left, rect.Top),
                                new SKPoint(rect.Right, rect.Bottom),
                                new SKColor[] { new SKColor(0x00, 0x80, 0xC0), 
                                                new SKColor(0x00, 0x80, 0xC0, 0) },
                                new float[] { 0.4f, 0.6f },
                                SKShaderTileMode.Clamp);

            // Get the blend mode from the picker
            paint.BlendMode = blendModePicker.SelectedIndex == -1 ? 0 :
                                    (SKBlendMode)blendModePicker.SelectedItem;

            canvas.DrawRect(rect, paint);

            // Stroke surrounding rectangle
            paint.Shader = null;
            paint.BlendMode = SKBlendMode.SrcOver;
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Black;
            paint.StrokeWidth = 3;
            canvas.DrawRect(rect, paint);
        }
    }
}

В этой программе демонстрируется использование режимов смешения Портер Duff со графических объектов, отличных от растровых изображений.This program demonstrates that the Porter-Duff blend modes can be used with graphic objects other than bitmaps. Тем не менее источник должен включать прозрачной области.However, the source must include a transparent area. Это обусловлено тем, в данном случае градиентные заливки прямоугольника, но часть градиента является прозрачным.This is the case here because the gradient fills the rectangle, but part of the gradient is transparent.

Ниже приведены три примера:Here are three examples:

Прозрачность Портер DuffPorter-Duff Transparency

Конфигурация источника и назначения является очень похожа на схемы, показанный на странице 255 исходного Портер-Duff цифровых изображений композиции бумаги, но эта страница показывает, что режимы наложения хорошо работающие для областей частичную прозрачность.The configuration of the destination and source is very similar to the diagrams shown in page 255 of the original Porter-Duff Compositing Digital Images paper, but this page demonstrates that the blend modes are well-behaved for areas of partial transparency.

Для некоторых различные эффекты можно использовать прозрачный градиентов.You can use transparent gradients for some different effects. Один из вариантов использование масок, аналогичный метод, описанный в Радиальный градиент для маскирования раздел SkiaSharp циклическая градиенты страницы.One possibility is masking, which is similar to the technique shown in the Radial gradients for masking section of the SkiaSharp circular gradients page. Значительная часть маска композиции страница аналогична этой более ранней программы.Much of the Compositing Mask page is similar to that earlier program. Он загружает ресурса точечного рисунка и определяет прямоугольник, в котором для его отображения.It loads a bitmap resource and determines a rectangle in which to display it. Радиальный градиент будет создан на основе предварительно определенный центра и радиус:A radial gradient is created based on a pre-determined center and radius:

public class CompositingMaskPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
        typeof(CompositingMaskPage),
        "SkiaSharpFormsDemos.Media.MountainClimbers.jpg");

    static readonly SKPoint CENTER = new SKPoint(180, 300);
    static readonly float RADIUS = 120;

    public CompositingMaskPage ()
    {
        Title = "Compositing Mask";

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

        // Find rectangle to display bitmap
        float scale = Math.Min((float)info.Width / bitmap.Width,
                               (float)info.Height / bitmap.Height);

        SKRect rect = SKRect.Create(scale * bitmap.Width, scale * bitmap.Height);

        float x = (info.Width - rect.Width) / 2;
        float y = (info.Height - rect.Height) / 2;
        rect.Offset(x, y);

        // Display bitmap in rectangle
        canvas.DrawBitmap(bitmap, rect);

        // Adjust center and radius for scaled and offset bitmap
        SKPoint center = new SKPoint(scale * CENTER.X + x,
                                        scale * CENTER.Y + y);
        float radius = scale * RADIUS;

        using (SKPaint paint = new SKPaint())
        {
            paint.Shader = SKShader.CreateRadialGradient(
                                center,
                                radius,
                                new SKColor[] { SKColors.Black,
                                                SKColors.Transparent },
                                new float[] { 0.6f, 1 },
                                SKShaderTileMode.Clamp);

            paint.BlendMode = SKBlendMode.DstIn;

            // Display rectangle using that gradient and blend mode
            canvas.DrawRect(rect, paint);
        }

        canvas.DrawColor(SKColors.Pink, SKBlendMode.DstOver);
    }
}

С этой программой разница в том что начинается с черный цвет в центре градиента и заканчивается прозрачности.The difference with this program is that the gradient begins with black in the center and ends with transparency. Он отображается в точечный рисунок с режимом blend DstIn, который показывает назначение только в областях источника, которые не являются прозрачными.It is displayed on the bitmap with a blend mode of DstIn, which shows the destination only in the areas of the source that are not transparent.

После DrawRect вызова, всю поверхность элемента canvas является прозрачным за исключением круга, определенного радиального градиента.After the DrawRect call, the entire surface of the canvas is transparent except for the circle defined by the radial gradient. Последний вызов:A final call is made:

canvas.DrawColor(SKColors.Pink, SKBlendMode.DstOver);

Прозрачные области холста розовым:All the transparent areas of the canvas are colored pink:

Маска композицииCompositing Mask

Также можно Портер Duff режимы и частично прозрачный градиентов для переходов из одного образа на другой.You can also use Porter-Duff modes and partially transparent gradients for transitions from one image to another. Градиента переходы страница содержит Slider чтобы указать уровень ход выполнения при переходе от 0 до 1 и Picker Выбор типа перехода:The Gradient Transitions page includes a Slider to indicate a progress level in the transition from 0 to 1, and a Picker to choose the type of transition you want:

<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.GradientTransitionsPage"
             Title="Gradient Transitions">
    
    <StackLayout>
        <skia:SKCanvasView x:Name="canvasView"
                           VerticalOptions="FillAndExpand"
                           PaintSurface="OnCanvasViewPaintSurface" />

        <Slider x:Name="progressSlider"
                Margin="10, 0"
                ValueChanged="OnSliderValueChanged" />

        <Label Text="{Binding Source={x:Reference progressSlider},
                              Path=Value,
                              StringFormat='Progress = {0:F2}'}"
               HorizontalTextAlignment="Center" />

        <Picker x:Name="transitionPicker" 
                Title="Transition" 
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged" />
        
    </StackLayout>
</ContentPage>

Файл с выделенным кодом загружает два ресурса точечного рисунка для демонстрации перехода.The code-behind file loads two bitmap resources to demonstrate the transition. Это же двух изображений, используемых в исчезают точечного рисунка ранее в этой статье.These are the same two images used in the Bitmap Dissolve page earlier in this article. Код также определяет перечисление с тремя элементами, соответствующие трем типам градиенты — линейной, радиальной и очистки.The code also defines an enumeration with three members corresponding to three types of gradients — linear, radial, and sweep. Эти значения будут загружены в Picker:These values are loaded into the Picker:

public partial class GradientTransitionsPage : ContentPage
{
    SKBitmap bitmap1 = BitmapExtensions.LoadBitmapResource(
        typeof(GradientTransitionsPage),
        "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");

    SKBitmap bitmap2 = BitmapExtensions.LoadBitmapResource(
        typeof(GradientTransitionsPage),
        "SkiaSharpFormsDemos.Media.FacePalm.jpg");

    enum TransitionMode
    {
        Linear,
        Radial,
        Sweep
    };

    public GradientTransitionsPage ()
    {
        InitializeComponent ();

        foreach (TransitionMode mode in Enum.GetValues(typeof(TransitionMode)))
        {
            transitionPicker.Items.Add(mode.ToString());
        }

        transitionPicker.SelectedIndex = 0;
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        canvasView.InvalidateSurface();
    }

    void OnPickerSelectedIndexChanged(object sender, EventArgs args)
    {
        canvasView.InvalidateSurface();
    }
    ···
}

Создает файл с выделенным кодом трех SKPaint объектов.The code-behind file creates three SKPaint objects. paint0 Объекта не использует режим наложения.The paint0 object doesn't use a blend mode. Этот объект paint используется для рисования прямоугольника с градиент, идущий от черного к прозрачным, как указано в colors массива.This paint object is used to draw a rectangle with a gradient that goes from black to transparent as indicated in the colors array. positions Массива основан на положение Slider, но немного изменены.The positions array is based on the position of the Slider, but adjusted somewhat. Если Slider в его минимума и максимума, progress значениями являются 0 или 1, и один из двух растровые изображения должен быть полностью отображены.If the Slider is at its minimum or maximum, the progress values are 0 or 1, and one of the two bitmaps should be fully visible. positions Массива должны быть настроены с учетом этих значений.The positions array must be set accordingly for those values.

Если progress значение равно 0, то positions — значения -0.1, а значение 0.If the progress value is 0, then the positions array contains the values -0.1 and 0. Первое значение равно 0, это означает, что градиент представляет собой черный только с 0 и прозрачный настроит SkiaSharp в противном случае.SkiaSharp will adjust that first value to be equal to 0, which means that the gradient is black only at 0 and transparent otherwise. Когда progress равен 0,5, то массив содержит значения 0,45 и 0,55.When progress is 0.5, then the array contains the values 0.45 and 0.55. Градиента черный от 0 к 0,45, а затем переходит к прозрачности, а полностью прозрачный 0,55 1.The gradient is black from 0 to 0.45, then transitions to transparent, and is fully transparent from 0.55 to 1. Когда progress -1, positions массив — 1 и 1.1, которое означает, что градиент представляет собой черный от 0 до 1.When progress is 1, the positions array is 1 and 1.1, which means the gradient is black from 0 to 1.

colors И position массивы используются в трех методов SKShader , Создание градиента.The colors and position arrays are both used in the three methods of SKShader that create a gradient. Только один из этих шейдеры создается на основе Picker выбора:Only one of these shaders is created based on the Picker selection:

public partial class GradientTransitionsPage : ContentPage
{
    ···
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Assume both bitmaps are square for display rectangle
        float size = Math.Min(info.Width, info.Height);
        SKRect rect = SKRect.Create(size, size);
        float x = (info.Width - size) / 2;
        float y = (info.Height - size) / 2;
        rect.Offset(x, y);

        using (SKPaint paint0 = new SKPaint())
        using (SKPaint paint1 = new SKPaint())
        using (SKPaint paint2 = new SKPaint())
        {
            SKColor[] colors = new SKColor[] { SKColors.Black,
                                               SKColors.Transparent };

            float progress = (float)progressSlider.Value;

            float[] positions = new float[]{ 1.1f * progress - 0.1f,
                                             1.1f * progress };

            switch ((TransitionMode)transitionPicker.SelectedIndex)
            {
                case TransitionMode.Linear:
                    paint0.Shader = SKShader.CreateLinearGradient(
                                        new SKPoint(rect.Left, 0),
                                        new SKPoint(rect.Right, 0),
                                        colors,
                                        positions,
                                        SKShaderTileMode.Clamp);
                    break;

                case TransitionMode.Radial:
                    paint0.Shader = SKShader.CreateRadialGradient(
                                        new SKPoint(rect.MidX, rect.MidY),
                                        (float)Math.Sqrt(Math.Pow(rect.Width / 2, 2) +
                                                         Math.Pow(rect.Height / 2, 2)),
                                        colors,
                                        positions,
                                        SKShaderTileMode.Clamp);
                    break;

                case TransitionMode.Sweep:
                    paint0.Shader = SKShader.CreateSweepGradient(
                                        new SKPoint(rect.MidX, rect.MidY),
                                        colors,
                                        positions);
                    break;
            }

            canvas.DrawRect(rect, paint0);

            paint1.BlendMode = SKBlendMode.SrcOut;
            canvas.DrawBitmap(bitmap1, rect, paint1);

            paint2.BlendMode = SKBlendMode.DstOver;
            canvas.DrawBitmap(bitmap2, rect, paint2);
        }
    }
}

Этот градиент отображается в прямоугольнике без режима наложения.That gradient is displayed in the rectangle without a blend mode. После этого DrawRect вызов, холста просто содержит градиент от черного к прозрачности.After that DrawRect call, the canvas simply contains a gradient from black to transparent. Выше возрастает объем черный Slider значения.The amount of black increases with higher Slider values.

В окончательной четыре операторы PaintSurface обработчик, отображаются два точечные рисунки.In the final four statements of the PaintSurface handler, the two bitmaps are displayed. SrcOut Blend режим означает, что первый точечный рисунок отображается только в прозрачные области фона.The SrcOut blend mode means that the first bitmap is displayed only in the transparent areas of the background. DstOver Режим для второго растрового изображения означает, что второй точечный рисунок отображается только в этих областях, где первый растровое изображение не отображается.The DstOver mode for the second bitmap means that the second bitmap is displayed only in those areas where the first bitmap is not displayed.

На следующих снимках экрана показано три типа различных переходов, каждый на отметке 50%:The following screenshots show the three different transitions types, each at the 50% mark:

Переходы градиентаGradient Transitions