Die nicht separierbaren Mischmodi
Wie Sie im Artikel SkiaSharp separierbare Mischungsmodi gesehen haben, führen die separierbaren Mischmodi vorgänge auf den roten, grünen und blauen Kanälen separat aus. Die nicht trennbaren Mischmodi sind nicht zulässig. Durch die Nutzung der Farbton-, Sättigungs- und Luminositätsstufen können die nicht trennbaren Mischungsmodi Farben auf interessante Weise ändern:
Das Hue-Saturation-Luminosity-Modell
Um die nicht trennbaren Mischmodi zu verstehen, ist es notwendig, die Ziel- und Quellpixel als Farben im Hue-Saturation-Luminosity-Modell zu behandeln. (Leuchtdichte wird auch als Helligkeit bezeichnet.)
Das HSL-Farbmodell wurde im Artikel Integration mit Xamarin.Formsund ein Beispielprogramm in diesem Artikel behandelt, um das Experimentieren mit HSL-Farben zu ermöglichen. Sie können einen SKColor
Wert mithilfe von Hue-, Sättigungs- und Luminosity-Werten mit der statischen SKColor.FromHsl
Methode erstellen.
Der Farbton stellt die dominante Wellenlänge der Farbe dar. Farbtonwerte reichen von 0 bis 360 und durchlaufen den Additiven und subtrahtiven Primaren: Rot ist der Wert 0, Gelb ist 60, Grün ist 120, Cyan ist 180, Blau ist 240, Magenta ist 300, und der Zyklus geht bei 360 zurück zu Rot.
Wenn keine dominante Farbe vorhanden ist, z. B. weiß oder schwarz oder grau ist, ist der Farbton nicht definiert und in der Regel auf 0 festgelegt.
Die Sättigungswerte können zwischen 0 und 100 liegen und die Reinheit der Farbe angeben. Ein Sättigungswert von 100 ist die reinste Farbe, während die Werte unter 100 die Farbe grauer werden lassen. Ein Sättigungswert von 0 führt zu einer Grauschattierung.
Der Leuchtdichtewert (oder Helligkeit) gibt an, wie hell die Farbe ist. Ein Leuchtdichtewert von 0 ist unabhängig von den anderen Einstellungen schwarz. Ebenso ist ein Leuchtdichtewert von 100 weiß.
Der HSL-Wert (0, 100, 50) ist der RGB-Wert (FF, 00, 00), der rein rot ist. Der HSL-Wert (180, 100, 50) ist der RGB-Wert (00, FF, FF), reines Cyan. Da die Sättigung verringert wird, wird die dominante Farbkomponente verringert, und die anderen Komponenten werden erhöht. Auf einer Sättigungsebene von 0 sind alle Komponenten gleich, und die Farbe ist eine graue Schattierung. Verringern Sie die Leuchtdichte, um zu schwarz zu wechseln; erhöhen Sie die Leuchtdichte, um zu weiß zu wechseln.
Die Blendmodi im Detail
Wie bei den anderen Blendmodi umfassen die vier nicht trennbaren Blendmodi ein Ziel (häufig ein Bitmapbild) und eine Quelle, die oft eine einzelne Farbe oder einen Farbverlauf ist. Die Blendmodi kombinieren Farbton-, Sättigungs- und Luminositätswerte aus dem Ziel und der Quelle:
Blendmodus | Komponenten aus Der Quelle | Komponenten vom Ziel |
---|---|---|
Hue |
Farbton | Sättigung und Leuchtdichte |
Saturation |
Sättigung | Farbton und Leuchtdichte |
Color |
Farbton und Sättigung | Leuchtdichte |
Luminosity |
Leuchtdichte | Farbton und Sättigung |
Die Spezifikationen für W3C Compositing und Blending Level 1 finden Sie in den Algorithmen.
Die Seite "Nicht separierbare Blendmodi" enthält einen Picker
der folgenden Blendmodi und drei Slider
Ansichten, um eine HSL-Farbe auszuwählen:
<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.NonSeparableBlendModesPage"
Title="Non-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.Hue" />
<x:Static Member="skia:SKBlendMode.Saturation" />
<x:Static Member="skia:SKBlendMode.Color" />
<x:Static Member="skia:SKBlendMode.Luminosity" />
</x:Array>
</Picker.ItemsSource>
<Picker.SelectedIndex>
0
</Picker.SelectedIndex>
</Picker>
<Slider x:Name="hueSlider"
Maximum="360"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="satSlider"
Maximum="100"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="lumSlider"
Maximum="100"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<StackLayout Orientation="Horizontal">
<Label x:Name="hslLabel"
HorizontalOptions="CenterAndExpand" />
<Label x:Name="rgbLabel"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</ContentPage>
Um Platz zu sparen, werden die drei Slider
Ansichten in der Benutzeroberfläche des Programms nicht identifiziert. Sie müssen sich daran erinnern, dass die Reihenfolge "Hue", "Sättigung" und "Leuchtdichte" lautet. Zwei Label
Ansichten unten auf der Seite zeigen die HSL- und RGB-Farbwerte an.
Die CodeBehind-Datei lädt eine der Bitmapressourcen, zeigt diese so groß wie möglich auf der Canvas an und deckt dann den Zeichenbereich mit einem Rechteck ab. Die Rechteckfarbe basiert auf den drei Slider
Ansichten, und der Blend-Modus ist die in der Picker
:
public partial class NonSeparableBlendModesPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(NonSeparableBlendModesPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
SKColor color;
public NonSeparableBlendModesPage()
{
InitializeComponent();
}
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs e)
{
// Calculate new color based on sliders
color = SKColor.FromHsl((float)hueSlider.Value,
(float)satSlider.Value,
(float)lumSlider.Value);
// Use labels to display HSL and RGB color values
color.ToHsl(out float hue, out float sat, out float lum);
hslLabel.Text = String.Format("HSL = {0:F0} {1:F0} {2:F0}",
hue, sat, lum);
rgbLabel.Text = String.Format("RGB = {0:X2} {1:X2} {2:X2}",
color.Red, color.Green, color.Blue);
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform);
// Get blend mode from Picker
SKBlendMode blendMode =
(SKBlendMode)(blendModePicker.SelectedIndex == -1 ?
0 : blendModePicker.SelectedItem);
using (SKPaint paint = new SKPaint())
{
paint.Color = color;
paint.BlendMode = blendMode;
canvas.DrawRect(info.Rect, paint);
}
}
}
Beachten Sie, dass das Programm den HSL-Farbwert nicht wie von den drei Schiebereglern ausgewählt anzeigt. Stattdessen erstellt es einen Farbwert aus diesen Schiebereglern und verwendet dann die ToHsl
Methode, um die Werte Hue, Sättigung und Luminosity abzurufen. Dies liegt daran, dass die FromHsl
Methode eine HSL-Farbe in eine RGB-Farbe konvertiert, die intern in der SKColor
Struktur gespeichert wird. Die ToHsl
Methode konvertiert von RGB in HSL, aber das Ergebnis ist nicht immer der ursprüngliche Wert.
Wandelt z FromHsl
. B. den HSL-Wert (180, 50, 0) in die RGB-Farbe (0, 0, 0) um, da die Luminosity
Null ist. Die ToHsl
Methode konvertiert die RGB-Farbe (0, 0, 0) in die HSL-Farbe (0, 0, 0, 0), da die Farbton- und Sättigungswerte irrelevant sind. Wenn Sie dieses Programm verwenden, ist es besser, dass Sie die Darstellung der HSL-Farbe sehen, die das Programm verwendet, anstatt das, das Sie mit den Schiebereglern angegeben haben.
Der SKBlendModes.Hue
Blendmodus verwendet die Farbtonebene der Quelle, während die Sättigungs- und Leuchtdichtestufen des Ziels beibehalten werden. Wenn Sie diesen Mischungsmodus testen, müssen die Sättigungs- und Leuchtdichteregler auf einen anderen Wert als 0 oder 100 festgelegt werden, da in diesen Fällen der Farbton nicht eindeutig definiert ist.
Wenn Sie den Schieberegler auf 0 festlegen (wie bei dem iOS-Screenshot links), wird alles rot. Das bedeutet aber nicht, dass das Bild ganz von Grün und Blau abwesend ist. Offensichtlich gibt es immer noch graue Schattierungen, die im Ergebnis vorhanden sind. Beispielsweise entspricht die RGB-Farbe (40, 40, C0) der HSL-Farbe (240, 50, 50). Der Farbton ist blau, aber der Sättigungswert von 50 gibt an, dass es auch rote und grüne Komponenten gibt. Wenn der Farbton auf SKBlendModes.Hue
0 festgelegt ist, lautet die HSL-Farbe (0, 50, 50), die RGB-Farbe (C0, 40, 40, 40). Es gibt immer noch blaue und grüne Komponenten, aber jetzt ist die dominante Komponente rot.
Der SKBlendModes.Saturation
Blendmodus kombiniert die Sättigungsebene der Quelle mit dem Farbton und der Leuchtdichte des Ziels. Wie der Farbton ist die Sättigung nicht gut definiert, wenn die Leuchtdichte 0 oder 100 ist. Theoretisch sollte jede Luminositätseinstellung zwischen diesen beiden Extremen funktionieren. Die Einstellung "Luminosity" wirkt sich jedoch eher auf das Ergebnis aus, als es sollte. Legen Sie die Leuchtdichte auf 50 fest, und Sie können sehen, wie Sie den Sättigungsgrad des Bilds festlegen können:
Sie können diesen Blendmodus verwenden, um die Farbsättigung eines dullen Bilds zu erhöhen, oder Sie können die Sättigung auf Null (wie im iOS-Screenshot links) für ein resultierendes Bild verringern, das nur aus grauen Schattierungen besteht.
Der SKBlendModes.Color
Blendmodus behält die Leuchtdichte des Ziels bei, verwendet jedoch den Farbton und die Sättigung der Quelle. Das bedeutet auch, dass alle Einstellungen des Luminosity-Schiebereglers irgendwo zwischen den Extremen funktionieren sollten.
In Kürze wird eine Anwendung dieses Blendmodus angezeigt.
Schließlich ist der SKBlendModes.Luminosity
Blendmodus das Gegenteil von SKBlendModes.Color
. Er behält den Farbton und die Sättigung des Ziels bei, verwendet jedoch die Leuchtdichte der Quelle. Der Luminosity
Blend-Modus ist das geheimnisvollste des Batches: Die Farbton- und Sättigungsschieberegler wirken sich auf das Bild aus, aber auch bei mittlerer Leuchtdichte ist das Bild nicht eindeutig:
Theoretisch sollte das Erhöhen oder Verringern der Leuchtdichte eines Bilds es heller oder dunkler machen. Dieses Luminosity-Eigenschaftsbeispiel oder diese SKBlendMode Enum-Definition kann von Interesse sein.
Es ist im Allgemeinen nicht der Fall, dass Sie einen der nicht trennbaren Blendmodi mit einer Quelle verwenden möchten, die aus einer einzelnen Farbe besteht, die auf das gesamte Zielbild angewendet wird. Der Effekt ist einfach zu groß. Sie möchten den Effekt auf einen Teil des Bilds beschränken. In diesem Fall wird die Quelle wahrscheinlich die Transparenz enthalten, oder die Quelle wird auf eine kleinere Grafik beschränkt.
Ein Matte für einen separierbaren Modus
Dies ist eine der Bitmaps, die als Ressource im Beispiel enthalten sind. Der Dateiname ist Banana.jpg:
Es ist möglich, eine Matte zu erstellen, die nur die Banane umfasst. Dies ist auch eine Ressource im Beispiel. Der Dateiname ist BananaMatte.png:
Neben der schwarzen Bananenform ist der Rest der Bitmap transparent.
Die Blaue Bananenseite verwendet diese Matte, um den Farbton und die Sättigung der Banane zu ändern, die der Affen hält, aber nichts anderes im Bild zu ändern.
In der folgenden BlueBananaPage
Klasse wird die Banana.jpg Bitmap als Feld geladen. Der Konstruktor lädt die BananaMatte.png Bitmap als matteBitmap
Objekt, behält dieses Objekt jedoch nicht über den Konstruktor hinaus. Stattdessen wird eine dritte Bitmap mit dem Namen blueBananaBitmap
erstellt. Die matteBitmap
Gezeichnet wird auf gefolgt blueBananaBitmap
von einem SKPaint
mit seinem Color
Set auf Blau und dessen BlendMode
Set auf SKBlendMode.SrcIn
. Die blueBananaBitmap
Re Standard s meist transparent, aber mit einem vollblauen Bild der Banane:
public class BlueBananaPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(BlueBananaPage),
"SkiaSharpFormsDemos.Media.Banana.jpg");
SKBitmap blueBananaBitmap;
public BlueBananaPage()
{
Title = "Blue Banana";
// Load banana matte bitmap (black on transparent)
SKBitmap matteBitmap = BitmapExtensions.LoadBitmapResource(
typeof(BlueBananaPage),
"SkiaSharpFormsDemos.Media.BananaMatte.png");
// Create a bitmap with a solid blue banana and transparent otherwise
blueBananaBitmap = new SKBitmap(matteBitmap.Width, matteBitmap.Height);
using (SKCanvas canvas = new SKCanvas(blueBananaBitmap))
{
canvas.Clear();
canvas.DrawBitmap(matteBitmap, new SKPoint(0, 0));
using (SKPaint paint = new SKPaint())
{
paint.Color = SKColors.Blue;
paint.BlendMode = SKBlendMode.SrcIn;
canvas.DrawPaint(paint);
}
}
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();
canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform);
using (SKPaint paint = new SKPaint())
{
paint.BlendMode = SKBlendMode.Color;
canvas.DrawBitmap(blueBananaBitmap,
info.Rect,
BitmapStretch.Uniform,
paint: paint);
}
}
}
Der PaintSurface
Handler zeichnet die Bitmap mit dem Affen, der die Banane hält. Auf diesen Code folgt die Anzeige mit blueBananaBitmap
SKBlendMode.Color
. Über der Oberfläche der Banane wird der Farbton und die Sättigung jedes Pixels durch das einfarbige Blau ersetzt, das einem Farbtonwert von 240 und einem Sättigungswert von 100 entspricht. Die Luminosität ist jedoch wieder Standard gleich, was bedeutet, dass die Banane trotz ihrer neuen Farbe weiterhin eine realistische Textur hat:
Versuchen Sie, den Mischmodus in SKBlendMode.Saturation
. Die Banane ist gelb Standard aber es ist ein intensiveres Gelb. In einer echten Anwendung kann dies ein wünschenswerterer Effekt sein, als das Bananenblau zu drehen.