Die separierbaren Mischmodi
Wie Sie im Artikel SkiaSharp Porter-Duff Blend Modi gesehen haben, führen die Porter-Duff Blend Modi in der Regel Clipping-Vorgänge aus. Die separierbaren Mischmodi unterscheiden sich. Die separierbaren Modi ändern die einzelnen Rot-, Grün- und Blaufarbenkomponenten eines Bilds. Separierbare Mischungsmodi können Farben mischen, um zu zeigen, dass die Kombination aus Rot, Grün und Blau tatsächlich weiß ist:
Aufhellen und Abdunkelt auf zwei Arten
Es ist üblich, eine Bitmap zu verwenden, die etwas zu dunkel oder zu hell ist. Sie können separierbare Blendmodi verwenden, um das Bild zu erhellen oder abzudunkelt. Tatsächlich werden zwei der separierbaren Mischmodi in der SKBlendMode
Enumeration benannt Lighten
und Darken
.
Diese beiden Modi werden auf der Seite "Aufhellen" und "Dunkler" veranschaulicht. Die XAML-Datei instanziiert zwei SKCanvasView
Objekte und zwei Slider
Ansichten:
<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>
Das erste SKCanvasView
und vorführen SKBlendMode.Lighten
und Slider
das zweite Paar veranschaulicht SKBlendMode.Darken
. Die beiden Slider
Ansichten verwenden denselben ValueChanged
Handler, und die beiden SKCanvasView
teilen denselben PaintSurface
Handler. Beide Ereignishandler überprüfen, welches Objekt das Ereignis auslöst:
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);
}
}
}
Der PaintSurface
Handler berechnet ein Rechteck, das für die Bitmap geeignet ist. Der Handler zeigt diese Bitmap an und zeigt dann ein Rechteck über die Bitmap mithilfe eines SKPaint
Objekts an, dessen BlendMode
Eigenschaft auf SKBlendMode.Lighten
oder SKBlendMode.Darken
. Die Color
Eigenschaft ist eine graue Schattierung basierend auf der Slider
. Für den Lighten
Modus reicht die Farbe von Schwarz bis Weiß, aber für den Darken
Modus reicht sie von Weiß bis Schwarz.
Die Screenshots von links nach rechts zeigen immer größere Slider
Werte an, da das obere Bild heller wird und das untere Bild dunkler wird:
Dieses Programm veranschaulicht die normale Art und Weise, in der die separierbaren Mischmodi verwendet werden: Das Ziel ist ein Bild einer Art, sehr oft eine Bitmap. Die Quelle ist ein Rechteck, das mit einem SKPaint
Objekt angezeigt wird, dessen BlendMode
Eigenschaft auf einen separierbaren Mischmodus festgelegt ist. Das Rechteck kann eine Volltonfarbe (wie hier) oder ein Farbverlauf sein. Transparenz wird in der Regel nicht mit den trennbaren Mischmodi verwendet.
Während Sie mit diesem Programm experimentieren, werden Sie feststellen, dass diese beiden Blendmodi das Bild nicht gleichmäßig aufhellen und abdunkelt. Stattdessen scheint dies Slider
einen Schwellenwert für eine Art von Sortierung festzulegen. Wenn Sie beispielsweise den Slider
Lighten
Modus erhöhen, werden die dunkleren Bereiche des Bilds zuerst hell, während die helleren Bereiche wieder Standard identisch sind.
Wenn für den Lighten
Modus das Zielpixel der RGB-Farbwert (Dr, Dg, Db) ist und das Quellpixel die Farbe (Sr, Sg, Sb) ist, wird die Ausgabe (Or, Og, Ob) wie folgt berechnet:
Or = max(Dr, Sr)
Og = max(Dg, Sg)
Ob = max(Db, Sb)
Bei Rot, Grün und Blau ist das Ergebnis der Ziel- und Quelle größer. Dies bewirkt, dass die dunklen Bereiche des Ziels zuerst aufhellt werden.
Der Darken
Modus ist ähnlich, mit der Ausnahme, dass das Ergebnis der geringere des Ziels und der Quelle ist:
Or = min(Dr, Sr)
Og = min(Dg, Sg)
Ob = min(Db, Sb)
Die roten, grünen und blauen Komponenten werden jeweils separat behandelt, weshalb diese Mischmodi als trennbare Mischungsmodi bezeichnet werden. Aus diesem Grund können die Abkürzungen Dc und Sc für die Ziel- und Quellfarben verwendet werden, und es wird verstanden, dass Berechnungen für jede der roten, grünen und blauen Komponenten separat gelten.
In der folgenden Tabelle sind alle separierbaren Mischmodi mit kurzen Erläuterungen zu ihrer Funktionsweise aufgeführt. In der zweiten Spalte wird die Quellfarbe angezeigt, die keine Änderung erzeugt:
Blendmodus | Keine Änderung | Vorgang |
---|---|---|
Plus |
Schwarz | Hellt durch Hinzufügen von Farben: Sc + Dc |
Modulate |
White | Verdunkelt durch Multiplizieren von Farben: Sc· Dc |
Screen |
Schwarz | Ergänzt Produkt von Ergänzungen: Sc + Dc – Sc· Dc |
Overlay |
Grau | Umkehrung von HardLight |
Darken |
White | Mindestfarben: min(Sc, Dc) |
Lighten |
Schwarz | Maximale Anzahl von Farben: max(Sc, Dc) |
ColorDodge |
Schwarz | Aufhellen des Ziels basierend auf der Quelle |
ColorBurn |
White | Dunkles Ziel basierend auf der Quelle |
HardLight |
Grau | Ähnlich wie die Wirkung von rauen Blickpunkt |
SoftLight |
Grau | Ähnlich wie bei weichem Blickpunkt |
Difference |
Schwarz | Subtrahiert den dunkleren vom Helleren: Abs(Dc – Sc) |
Exclusion |
Schwarz | Ähnlich wie Difference , aber der Kontrast ist niedriger. |
Multiply |
White | Verdunkelt durch Multiplizieren von Farben: Sc· Dc |
Detailliertere Algorithmen finden Sie in der W3C Compositing- und Blending Level 1-Spezifikation und der Skia SkBlendMode Reference, obwohl die Notation in diesen beiden Quellen nicht identisch ist. Denken Sie daran, dass Plus
es sich häufig um einen Porter-Duff-Blend-Modus handelt und Modulate
nicht Teil der W3C-Spezifikation ist.
Wenn die Quelle transparent ist, hat der Blendmodus für alle trennbaren Mischmodi Modulate
keine Auswirkung. Wie Sie bereits gesehen haben, enthält der Modulate
Blendmodus den Alphakanal in die Multiplikation. Modulate
Andernfalls hat die gleiche Wirkung wie Multiply
.
Beachten Sie die beiden benannten ColorDodge
und ColorBurn
. Die Worte verdüsteten und verbrennen aus fotografischen Dunklen Raumpraktiken. Ein Vergrößerungselement macht einen fotografischen Druck durch ein negatives Licht. Ohne Licht ist der Druck weiß. Der Druck wird dunkler, da mehr Licht für einen längeren Zeitraum auf den Druck fällt. Print-Maker verwendeten häufig ein Hand- oder kleines Objekt, um zu verhindern, dass ein teil des Drucks auf ein bestimmtes Teil des Drucks fällt, wodurch dieser Bereich heller wird. Dies wird als Verdrückung bezeichnet. Umgekehrt könnte undurchsichtiges Material mit einem Loch darin (oder händen, die den größten Teil des Lichts blockieren) verwendet werden, um das Licht an einem bestimmten Punkt zu verdunkelt, der als Brennen bezeichnet wird.
Das Dodge and Burn-Programm ist sehr ähnlich wie "Aufhellen" und "Dunkler". Die XAML-Datei ist identisch, aber mit unterschiedlichen Elementnamen, und die CodeBehind-Datei ist ebenfalls ziemlich ähnlich, aber der Effekt dieser beiden Blendmodi unterscheidet sich ziemlich:
Bei kleinen Slider
Werten hellt der Lighten
Modus zuerst dunkle Bereiche auf, während ColorDodge
er gleichmäßiger aufhellt.
Anwendungsprogramme zur Bildverarbeitung ermöglichen häufig das Ausweichen und Brennen auf bestimmte Bereiche, genau wie in einem Dunklen Raum. Dies kann durch Farbverläufe oder durch eine Bitmap mit unterschiedlichen Graustufen erreicht werden.
Erkunden der separierbaren Mischmodi
Auf der Seite "Separable Blend Modes " können Sie alle separierbaren Mischmodi untersuchen. Es zeigt ein Bitmapziel und eine farbige Rechteckquelle mit einem der Blendmodi an.
Die XAML-Datei definiert einen Picker
(zum Auswählen des Mischmodus) und vier Schieberegler. Mit den ersten drei Schiebereglern können Sie die roten, grünen und blauen Komponenten der Quelle festlegen. Der vierte Schieberegler soll diese Werte überschreiben, indem ein grauer Schatten festgelegt wird. Die einzelnen Schieberegler werden nicht identifiziert, aber Farben geben ihre Funktion an:
<?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>
Die CodeBehind-Datei lädt eine der Bitmapressourcen und zeichnet sie zweimal, einmal in der oberen Hälfte des Zeichenbereichs und wieder in der unteren Hälfte des Zeichenbereichs:
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);
}
}
}
Am unteren Rand des PaintSurface
Handlers wird ein Rechteck über die zweite Bitmap mit dem ausgewählten Blendmodus und der ausgewählten Farbe gezeichnet. Sie können die geänderte Bitmap unten mit der ursprünglichen Bitmap oben vergleichen:
Additive und subtrahierende Primärfarben
Auf der Seite " Primärfarben " werden drei überlappende Kreise von Rot, Grün und Blau gezeichnet:
Dies sind die additiven Primärfarben. Kombinationen von zwei beliebigen erzeugen Zyan, Magenta und Gelb, und eine Kombination aller drei ist weiß.
Diese drei Kreise werden mit dem SKBlendMode.Plus
Modus gezeichnet, sie können aber auch für denselben Effekt verwendet Screen
Lighten
werdenDifference
. Hier ist das Programm:
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);
}
}
}
}
Das Programm enthält ein TabGestureRecognizer
. Wenn Sie auf den Bildschirm tippen oder klicken, zeigt SKBlendMode.Multiply
das Programm die drei subtrahativen Primarvorlagen an:
Der Darken
Modus funktioniert auch für diesen Effekt.