Freigeben über


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:

Nicht separierbares Beispiel

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.

Nicht separierbare Blendmodi - Hue

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.Hue0 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:

Nicht separierbare Mischmodi - Sättigung

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.

Nicht separierbare Mischmodi - Farbe

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:

Nicht separierbare Blendmodi - Leuchtdichte

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:

Bananenaffe

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:

Bananenmatte Matte

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:

Blaue Banane

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.