Режимы смешения с разделителями
Как вы видели в статье SkiaSharp Porter-Duff blend режимы, режимы смешения Porter-Duff обычно выполняют операции вырезки. Режимы смешения с разделителями отличаются. Режимы сепарабельного изменения отдельных красных, зеленых и синих цветов изображения. Сепарируемые режимы смешивания могут смешивать цвет, чтобы продемонстрировать, что сочетание красного, зеленого и синего действительно белое:
Светить и темнеть два способа
Обычно имеется растровое изображение, которое несколько слишком темно или слишком светло. Вы можете использовать режимы смешения с разделителями, чтобы осветить или темнеть изображение. Действительно, два режима сепарируемых смешения в SKBlendMode
перечислении именуются Lighten
и Darken
.
Эти два режима демонстрируются на странице Lighten и Darken . XAML-файл создает экземпляры двух объектов и двух SKCanvasView
Slider
представлений:
<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.LightenAndDarkenPage"
Title="Lighten and Darken">
<StackLayout>
<skia:SKCanvasView x:Name="lightenCanvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Slider x:Name="lightenSlider"
Margin="10"
ValueChanged="OnSliderValueChanged" />
<skia:SKCanvasView x:Name="darkenCanvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Slider x:Name="darkenSlider"
Margin="10"
ValueChanged="OnSliderValueChanged" />
</StackLayout>
</ContentPage>
SKCanvasView
Первая и демонстрацияSKBlendMode.Lighten
, а Slider
вторая пара демонстрируетSKBlendMode.Darken
. Два Slider
представления совместно используют один и тот же ValueChanged
обработчик, и они SKCanvasView
совместно используют один и тот же PaintSurface
обработчик. Оба обработчика событий проверка, какой объект запускает событие:
public partial class LightenAndDarkenPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(SeparableBlendModesPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
public LightenAndDarkenPage ()
{
InitializeComponent ();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
if ((Slider)sender == lightenSlider)
{
lightenCanvasView.InvalidateSurface();
}
else
{
darkenCanvasView.InvalidateSurface();
}
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Find largest size rectangle in canvas
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
canvas.DrawBitmap(bitmap, rect);
// Display gray rectangle with blend mode
using (SKPaint paint = new SKPaint())
{
if ((SKCanvasView)sender == lightenCanvasView)
{
byte value = (byte)(255 * lightenSlider.Value);
paint.Color = new SKColor(value, value, value);
paint.BlendMode = SKBlendMode.Lighten;
}
else
{
byte value = (byte)(255 * (1 - darkenSlider.Value));
paint.Color = new SKColor(value, value, value);
paint.BlendMode = SKBlendMode.Darken;
}
canvas.DrawRect(rect, paint);
}
}
}
Обработчик PaintSurface
вычисляет прямоугольник, подходящий для растрового изображения. Обработчик отображает это растровое изображение, а затем отображает прямоугольник по растровой карте, используя объект со своим BlendMode
свойствомSKPaint
, заданным SKBlendMode.Lighten
или SKBlendMode.Darken
. Свойство Color
является серым оттенком на Slider
основе . Lighten
Для режима цветовые диапазоны от черного до белого, но для Darken
режима он варьируется от белого до черного.
Снимок экрана слева направо показывает все Slider
больше значений, так как верхний образ становится легче, а нижний рисунок становится темнее:
Эта программа демонстрирует обычный способ использования режимов сепарабельного смешения: назначение — это изображение определенного рода, очень часто растровое изображение. Источник — это прямоугольник, отображаемый с помощью SKPaint
объекта со своим BlendMode
свойством, заданным в режиме сепарабельного смешения. Прямоугольник может быть сплошным цветом (как здесь) или градиентом. Прозрачность обычно не используется с режимами разбиения.
Поэкспериментируя с этой программой, вы обнаружите, что эти два режима смешивания не светятся и не темнеют изображение равномерно. Вместо этого, кажется, Slider
установить порог определенного рода. Например, при увеличении Slider
Lighten
режима темные области изображения сначала получают свет, а более светлые области остаются прежними.
В режиме Lighten
, если целевой пиксель является значением цвета RGB (dr, Dg, Db), а исходный пиксель — цветом (Sr, Sg, Sb), то выходные данные вычисляются следующим образом:
Or = max(Dr, Sr)
Og = max(Dg, Sg)
Ob = max(Db, Sb)
Для красного, зеленого и синего по отдельности результат — это больше места назначения и источника. Это создает эффект осветления темных областей назначения первым.
Режим Darken
аналогичен, за исключением того, что результат меньше назначения и источника:
Or = min(Dr, Sr)
Og = min(Dg, Sg)
Ob = min(Db, Sb)
Красные, зеленые и синие компоненты обрабатываются отдельно, поэтому эти режимы смешивания называются режимами сепарабельной смеси. По этой причине аббревиаций Dc и Sc можно использовать для цветов назначения и источника, и понятно, что вычисления применяются к каждому из красных, зеленых и синих компонентов отдельно.
В следующей таблице показаны все режимы сепарируемых смешений с краткими объяснениями того, что они делают. Второй столбец показывает исходный цвет, который не приводит к изменению:
Режим смешивания | Без изменений | Операция |
---|---|---|
Plus |
Черный | Светит путем добавления цветов: Sc + Dc |
Modulate |
Белый | Темнеет путем умножения цветов: Sc· Dc |
Screen |
Черный | Дополняет продукт дополнений: Sc + Dc – Sc · Dc |
Overlay |
Серый | Обратное HardLight |
Darken |
Белый | Минимум цветов: min(Sc, Dc) |
Lighten |
Черный | Максимальное количество цветов: max(Sc, Dc) |
ColorDodge |
Черный | Назначение Brightens на основе источника |
ColorBurn |
Белый | Темная цель на основе источника |
HardLight |
Серый | Похоже на эффект жесткого внимания |
SoftLight |
Серый | Аналогично эффекту мягкого внимания |
Difference |
Черный | Вычитает темнее из более светлого: Abs(Dc – Sc) |
Exclusion |
Черный | Difference Аналогично, но более низкая контрастность |
Multiply |
Белый | Темнеет путем умножения цветов: Sc· Dc |
Более подробные алгоритмы можно найти в спецификации W3C Compositing и Blending Level 1 и в справочнике skia SkBlendMode, хотя нотация в этих двух источниках не совпадает. Помните, что Plus
обычно считается режимом смешивания Porter-Duff и Modulate
не является частью спецификации W3C.
Если источник прозрачный, то для всех режимов сепарируемых смешения, кроме Modulate
того, режим смешивания не действует. Как вы видели ранее, Modulate
режим смешения включает альфа-канал в умножение. В противном случае имеет тот же эффект, Modulate
что Multiply
и .
Обратите внимание на два режима с именем ColorDodge
и ColorBurn
. Слова уклоняются и горят в фотографических темных комнатах практики. Увеличение делает фотопечать, сияя светом через отрицательный. Без света печать белая. Печать становится темнее, так как больше света падает на печать в течение более длительного периода времени. Печатники часто использовали руку или небольшой объект, чтобы заблокировать некоторые из света от падения на определенную часть печати, что делает эту область светлее. Это называется dodging. И наоборот, непрозрачный материал с отверстием в нем (или руки блокируют большую часть света) можно использовать для направления большего света в определенном месте, чтобы темнеть его, называется сжиганием.
Программа Dodge и Burn очень похожа на Lighten и Darken. XAML-файл структурирован так же, но с различными именами элементов, и файл кода программной части также аналогичен, но эффект этих двух режимов смешения совершенно отличается:
Для небольших Slider
значений Lighten
режим сначала светит темные области, а ColorDodge
светит более равномерно.
Программы приложений для обработки изображений часто позволяют выполнять отработку и сжигание в определенных областях, как и в темном помещении. Это можно сделать с помощью градиентов или растрового изображения с различными оттенками серого.
Изучение режимов сепарируемых смешения
Страница "Режимы смешивания с разделителями" позволяет изучить все режимы сепарабельного смешения. В нем отображается назначение растрового изображения и цветной прямоугольник с помощью одного из режимов смешения.
XAML-файл определяет 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:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
xmlns:skiaviews="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Effects.SeparableBlendModesPage"
Title="Separable Blend Modes">
<StackLayout>
<skiaviews:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Picker x:Name="blendModePicker"
Title="Blend Mode"
Margin="10, 0"
SelectedIndexChanged="OnPickerSelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type skia:SKBlendMode}">
<x:Static Member="skia:SKBlendMode.Plus" />
<x:Static Member="skia:SKBlendMode.Modulate" />
<x:Static Member="skia:SKBlendMode.Screen" />
<x:Static Member="skia:SKBlendMode.Overlay" />
<x:Static Member="skia:SKBlendMode.Darken" />
<x:Static Member="skia:SKBlendMode.Lighten" />
<x:Static Member="skia:SKBlendMode.ColorDodge" />
<x:Static Member="skia:SKBlendMode.ColorBurn" />
<x:Static Member="skia:SKBlendMode.HardLight" />
<x:Static Member="skia:SKBlendMode.SoftLight" />
<x:Static Member="skia:SKBlendMode.Difference" />
<x:Static Member="skia:SKBlendMode.Exclusion" />
<x:Static Member="skia:SKBlendMode.Multiply" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Slider x:Name="redSlider"
MinimumTrackColor="Red"
MaximumTrackColor="Red"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="greenSlider"
MinimumTrackColor="Green"
MaximumTrackColor="Green"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="blueSlider"
MinimumTrackColor="Blue"
MaximumTrackColor="Blue"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="graySlider"
MinimumTrackColor="Gray"
MaximumTrackColor="Gray"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="colorLabel"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
Файл программной части загружает один из ресурсов растрового изображения и рисует его дважды, один раз в верхней половине холста и снова в нижней половине холста:
public partial class SeparableBlendModesPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(SeparableBlendModesPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
public SeparableBlendModesPage()
{
InitializeComponent();
}
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs e)
{
if (sender == graySlider)
{
redSlider.Value = greenSlider.Value = blueSlider.Value = graySlider.Value;
}
colorLabel.Text = String.Format("Color = {0:X2} {1:X2} {2:X2}",
(byte)(255 * redSlider.Value),
(byte)(255 * greenSlider.Value),
(byte)(255 * blueSlider.Value));
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Draw bitmap in top half
SKRect rect = new SKRect(0, 0, info.Width, info.Height / 2);
canvas.DrawBitmap(bitmap, rect, BitmapStretch.Uniform);
// Draw bitmap in bottom halr
rect = new SKRect(0, info.Height / 2, info.Width, info.Height);
canvas.DrawBitmap(bitmap, rect, BitmapStretch.Uniform);
// Get values from XAML controls
SKBlendMode blendMode =
(SKBlendMode)(blendModePicker.SelectedIndex == -1 ?
0 : blendModePicker.SelectedItem);
SKColor color = new SKColor((byte)(255 * redSlider.Value),
(byte)(255 * greenSlider.Value),
(byte)(255 * blueSlider.Value));
// Draw rectangle with blend mode in bottom half
using (SKPaint paint = new SKPaint())
{
paint.Color = color;
paint.BlendMode = blendMode;
canvas.DrawRect(rect, paint);
}
}
}
В нижней части PaintSurface
обработчика прямоугольник рисуется по второй растровой карте с выбранным режимом смешения и выбранным цветом. Измененное растровое изображение в нижней части можно сравнить с исходной растровой картой в верхней части:
Аддитивные и субтрактивные первичные цвета
Страница "Основные цвета" рисует три перекрывающихся круга красного, зеленого и синего:
Это аддитивные первичные цвета. Сочетания любых двух видов производства цина, пургенты и желтого цвета, а сочетание всех трех является белым.
Эти три круга рисуются с режимомSKBlendMode.Plus
, но вы также можете использовать Screen
или Lighten
Difference
для того же эффекта. Вот программа:
public class PrimaryColorsPage : ContentPage
{
bool isSubtractive;
public PrimaryColorsPage ()
{
Title = "Primary Colors";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
// Switch between additive and subtractive primaries at tap
TapGestureRecognizer tap = new TapGestureRecognizer();
tap.Tapped += (sender, args) =>
{
isSubtractive ^= true;
canvasView.InvalidateSurface();
};
canvasView.GestureRecognizers.Add(tap);
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY);
float radius = Math.Min(info.Width, info.Height) / 4;
float distance = 0.8f * radius; // from canvas center to circle center
SKPoint center1 = center +
new SKPoint(distance * (float)Math.Cos(9 * Math.PI / 6),
distance * (float)Math.Sin(9 * Math.PI / 6));
SKPoint center2 = center +
new SKPoint(distance * (float)Math.Cos(1 * Math.PI / 6),
distance * (float)Math.Sin(1 * Math.PI / 6));
SKPoint center3 = center +
new SKPoint(distance * (float)Math.Cos(5 * Math.PI / 6),
distance * (float)Math.Sin(5 * Math.PI / 6));
using (SKPaint paint = new SKPaint())
{
if (!isSubtractive)
{
paint.BlendMode = SKBlendMode.Plus;
System.Diagnostics.Debug.WriteLine(paint.BlendMode);
paint.Color = SKColors.Red;
canvas.DrawCircle(center1, radius, paint);
paint.Color = SKColors.Lime; // == (00, FF, 00)
canvas.DrawCircle(center2, radius, paint);
paint.Color = SKColors.Blue;
canvas.DrawCircle(center3, radius, paint);
}
else
{
paint.BlendMode = SKBlendMode.Multiply
System.Diagnostics.Debug.WriteLine(paint.BlendMode);
paint.Color = SKColors.Cyan;
canvas.DrawCircle(center1, radius, paint);
paint.Color = SKColors.Magenta;
canvas.DrawCircle(center2, radius, paint);
paint.Color = SKColors.Yellow;
canvas.DrawCircle(center3, radius, paint);
}
}
}
}
Программа включает в TabGestureRecognizer
себя . При нажатии или щелчке экрана программа используется SKBlendMode.Multiply
для отображения трех субтрактивных первичных элементов:
Режим Darken
также работает для этого же эффекта.