Modalità di fusione non separabili
Come si è visto nell'articolo Le modalità di fusione separabili SkiaSharp, le modalità di fusione separabili eseguono operazioni sui canali rosso, verde e blu separatamente. Le modalità di fusione non separabili non sono disponibili. Operando sui livelli hue, saturazione e luminosità del colore, le modalità di fusione non separabili possono modificare i colori in modi interessanti:
Modello Hue-Saturation-Luminosity
Per comprendere le modalità di fusione non separabili, è necessario considerare la destinazione e i pixel di origine come colori nel modello Hue-Saturation-Luminosity. (La luminosità è nota anche come Leggerezza.
Il modello di colore HSL è stato illustrato nell'articolo Integrazione con Xamarin.Forms e un programma di esempio in tale articolo consente la sperimentazione con i colori HSL. È possibile creare un SKColor
valore usando i valori Hue, Saturation e Luminosità con il metodo statico SKColor.FromHsl
.
La tonalità rappresenta la lunghezza d'onda dominante del colore. I valori delle tonalità vanno da 0 a 360 e scorrere i primari additivi e sottrazione: il rosso è il valore 0, il giallo è 60, il verde è 120, il ciano è 180, il blu è 240, magenta è 300 e il ciclo torna al rosso a 360.
Se non esiste un colore dominante, ad esempio il colore è bianco o nero o grigio, allora hue non è definito e in genere impostato su 0.
I valori di saturazione possono variare da 0 a 100 e indicare la purezza del colore. Un valore di saturazione pari a 100 è il colore più puro, mentre i valori inferiori a 100 causano un colore più grigio. Un valore di saturazione pari a 0 restituisce un'ombreggiatura di grigio.
Il valore luminosità (o leggerezza) indica la luminosità del colore. Un valore di luminosità pari a 0 è nero indipendentemente dalle altre impostazioni. Analogamente, un valore di luminosità pari a 100 è bianco.
Il valore HSL (0, 100, 50) è il valore RGB (FF, 00, 00), che è rosso puro. Il valore HSL (180, 100, 50) è il valore RGB (00, FF, FF), ciano puro. Man mano che la saturazione è diminuita, il componente del colore dominante viene ridotto e gli altri componenti vengono aumentati. A un livello di saturazione pari a 0, tutti i componenti sono uguali e il colore è una sfumatura grigia. Diminuire la luminosità per andare al nero; aumentare la luminosità per andare a bianco.
Modalità blend in dettaglio
Come le altre modalità di fusione, le quattro modalità di fusione non separabili comportano una destinazione (che spesso è un'immagine bitmap) e un'origine, che spesso è un singolo colore o una sfumatura. Le modalità di fusione combinano i valori Hue, Saturation e Luminosità dalla destinazione e dall'origine:
Modalità blend | Componenti dall'origine | Componenti dalla destinazione |
---|---|---|
Hue |
Hue | Saturazione e luminosità |
Saturation |
Saturazione | Tonalità e luminosità |
Color |
Tonalità e saturazione | Luminosità |
Luminosity |
Luminosità | Tonalità e saturazione |
Vedere la specifica W3C Compositing and Blending Level 1 (Composizione W3C e Blending Level 1 ) per gli algoritmi.
La pagina Modalità blend non separabili contiene un oggetto Picker
per selezionare una di queste modalità di fusione e tre Slider
visualizzazioni per selezionare un colore HSL:
<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>
Per risparmiare spazio, le tre Slider
visualizzazioni non vengono identificate nell'interfaccia utente del programma. È necessario ricordare che l'ordine è Hue, Saturation e Luminosità. Due Label
visualizzazioni nella parte inferiore della pagina mostrano i valori di colore HSL e RGB.
Il file code-behind carica una delle risorse bitmap, visualizza il più grande possibile nell'area di disegno e quindi copre l'area di disegno con un rettangolo. Il colore del rettangolo si basa sulle tre Slider
visualizzazioni e la modalità di fusione è quella selezionata in 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);
}
}
}
Si noti che il programma non visualizza il valore del colore HSL come selezionato dai tre dispositivi di scorrimento. Crea invece un valore di colore da tali dispositivi di scorrimento e quindi usa il ToHsl
metodo per ottenere i valori Hue, Saturation e Luminosità. Questo perché il FromHsl
metodo converte un colore HSL in un colore RGB, archiviato internamente nella SKColor
struttura. Il ToHsl
metodo converte da RGB a HSL, ma il risultato non sarà sempre il valore originale.
Ad esempio, FromHsl
converte il valore HSL (180, 50, 0) nel colore RGB (0, 0, 0) perché è Luminosity
zero. Il ToHsl
metodo converte il colore RGB (0, 0, 0) nel colore HSL (0, 0, 0) perché i valori Hue e Saturation sono irrilevanti. Quando si usa questo programma, è preferibile visualizzare la rappresentazione del colore HSL usato dal programma anziché quello specificato con i dispositivi di scorrimento.
La SKBlendModes.Hue
modalità blend usa il livello Hue dell'origine mantenendo i livelli di saturazione e luminosità della destinazione. Quando si testa questa modalità di fusione, i dispositivi di scorrimento della saturazione e della luminosità devono essere impostati su un valore diverso da 0 o 100 perché in questi casi la tonalità non è definita in modo univoco.
Quando si usa impostare il dispositivo di scorrimento su 0 (come con lo screenshot iOS a sinistra), tutto diventa rossastro. Ma questo non significa che l'immagine è completamente assente di verde e blu. Ovviamente ci sono ancora sfumature grigie presenti nel risultato. Ad esempio, il colore RGB (40, 40, C0) equivale al colore HSL (240, 50, 50). Hue è blu, ma il valore di saturazione pari a 50 indica che sono presenti anche componenti rossi e verdi. Se Hue è impostato su 0 con SKBlendModes.Hue
, il colore HSL è (0, 50, 50), ovvero il colore RGB (C0, 40, 40). Ci sono ancora componenti blu e verde, ma ora il componente dominante è rosso.
La SKBlendModes.Saturation
modalità blend combina il livello di saturazione dell'origine con hue e luminosità della destinazione. Come la Tonalità, la saturazione non è ben definita se la luminosità è 0 o 100. In teoria, qualsiasi impostazione di luminosità tra questi due estremi dovrebbe funzionare. Tuttavia, l'impostazione Luminosità sembra influire sul risultato più che dovrebbe. Impostare la luminosità su 50 ed è possibile vedere come impostare il livello di saturazione dell'immagine:
È possibile usare questa modalità di fusione per aumentare la saturazione del colore di un'immagine opaca oppure ridurre la saturazione fino a zero (come nello screenshot iOS a sinistra) per un'immagine risultante composta solo da sfumature grigie.
La SKBlendModes.Color
modalità blend mantiene la luminosità della destinazione, ma usa hue e saturazione dell'origine. Anche in questo caso, ciò implica che qualsiasi impostazione del dispositivo di scorrimento Luminosità da qualche parte tra gli estremi dovrebbe funzionare.
A breve verrà visualizzata un'applicazione di questa modalità di fusione.
Infine, la SKBlendModes.Luminosity
modalità blend è l'opposto di SKBlendModes.Color
. Mantiene la tonalità e la saturazione della destinazione, ma usa la luminosità dell'origine. La Luminosity
modalità di fusione è la più misteriosa del batch: i dispositivi di scorrimento Hue e Saturazione influiscono sull'immagine, ma anche a luminosità media, l'immagine non è distinta:
In teoria, aumentare o diminuire la luminosità di un'immagine dovrebbe renderla più chiara o scura. Questo esempio di proprietà Luminosità o questa definizione di Enumerazione SKBlendMode può essere di interesse.
In genere non è consigliabile usare una delle modalità di fusione non separabili con un'origine costituita da un singolo colore applicato all'intera immagine di destinazione. L'effetto è troppo grande. Si vuole limitare l'effetto a una parte dell'immagine. In tal caso, l'origine incorporerà probabilmente la transparanza, o forse l'origine sarà limitata a un elemento grafico più piccolo.
Matte per una modalità separabile
Ecco una delle bitmap incluse come risorsa nell'esempio. Il nome file è Banana.jpg:
È possibile creare un opaco che comprende solo la banana. Si tratta anche di una risorsa nell'esempio. Il nome file è BananaMatte.png:
A parte la forma di banana nera, il resto della bitmap è trasparente.
La pagina Blue Banana usa tale matto per modificare la tonalità e la saturazione della banana che la scimmia sta tenendo, ma per cambiare nient'altro nell'immagine.
Nella classe seguente BlueBananaPage
la bitmap Banana.jpg viene caricata come campo. Il costruttore carica il BananaMatte.png bitmap come matteBitmap
oggetto, ma non mantiene tale oggetto oltre il costruttore. Viene invece creata una terza bitmap denominata blueBananaBitmap
. L'oggetto matteBitmap
viene disegnato su seguito da un SKPaint
oggetto con il relativo Color
valore impostato su blueBananaBitmap
blu e il relativo BlendMode
valore impostato su SKBlendMode.SrcIn
. Il blueBananaBitmap
rimane per lo più trasparente ma con un'immagine blu pura solida della banana:
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);
}
}
}
Il PaintSurface
gestore disegna la bitmap con la scimmia che tiene la banana. Questo codice è seguito dalla visualizzazione di blueBananaBitmap
con SKBlendMode.Color
. Sulla superficie della banana, la tonalità e la saturazione di ogni pixel vengono sostituite dal blu solido, che corrisponde a un valore di tonalità 240 e un valore di saturazione pari a 100. La Luminosità, tuttavia, rimane invariata, il che significa che la banana continua ad avere una trama realistica nonostante il suo nuovo colore:
Provare a modificare la modalità blend in SKBlendMode.Saturation
. La banana rimane gialla, ma è un giallo più intenso. In un'applicazione reale, questo potrebbe essere un effetto più auspicabile che trasformare il blu della banana.