Modes de fusion séparables
Comme vous l’avez vu dans l’article SkiaSharp Porter-Duff modes de fusion, les modes de fusion Porter-Duff effectuent généralement des opérations de découpage. Les modes de fusion séparables sont différents. Les modes séparables modifient les composants de couleur rouge, vert et bleu d’une image. Les modes de mélange séparables peuvent mélanger la couleur pour démontrer que la combinaison rouge, verte et bleue est en effet blanche :
Éclaircir et assombrir deux façons
Il est courant d’avoir une bitmap qui est un peu trop sombre ou trop clair. Vous pouvez utiliser des modes de fusion séparables pour éclaircir ou assombrir l’image. En effet, deux des modes de fusion séparables dans l’énumération SKBlendMode
sont nommés Lighten
et Darken
.
Ces deux modes sont illustrés dans la page Lighten et Darken . Le fichier XAML instancie deux SKCanvasView
objets et deux Slider
vues :
<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>
La première SKCanvasView
et Slider
la SKBlendMode.Lighten
deuxième paire illustrent SKBlendMode.Darken
. Les deux Slider
vues partagent le même ValueChanged
gestionnaire et les deux SKCanvasView
partagent le même PaintSurface
gestionnaire. Les deux gestionnaires d’événements case activée quel objet déclenche l’événement :
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);
}
}
}
Le PaintSurface
gestionnaire calcule un rectangle adapté à la bitmap. Le gestionnaire affiche cette bitmap, puis affiche un rectangle sur la bitmap à l’aide d’un SKPaint
objet avec sa BlendMode
propriété définie SKBlendMode.Lighten
sur ou SKBlendMode.Darken
. La Color
propriété est une nuance grise basée sur le Slider
. Pour le Lighten
mode, la couleur est comprise entre le noir et le blanc, mais pour le Darken
mode, il varie de blanc à noir.
Les captures d’écran de gauche à droite affichent des valeurs de plus en plus grandes lorsque l’image supérieure est plus claire Slider
et que l’image inférieure est plus sombre :
Ce programme illustre la façon normale dont les modes de fusion séparables sont utilisés : la destination est une image d’une sorte, très souvent une bitmap. La source est un rectangle affiché à l’aide d’un SKPaint
objet dont la BlendMode
propriété est définie sur un mode de fusion séparable. Le rectangle peut être une couleur unie (tel qu’il est ici) ou un dégradé. La transparence n’est généralement pas utilisée avec les modes de fusion séparables.
Au fur et à mesure que vous expérimentez ce programme, vous découvrirez que ces deux modes de fusion ne s’éclaircient pas et assombrir l’image uniformément. Au lieu de cela, il Slider
semble définir un seuil de quelque sorte. Par exemple, à mesure que vous augmentez le Slider
Lighten
mode, les zones plus sombres de l’image obtiennent d’abord la lumière tandis que les zones plus claires restent les mêmes.
Pour le Lighten
mode, si le pixel de destination est la valeur de couleur RVB (Dr, Dg, Db) et que le pixel source est la couleur (Sr, Sg, Sb), la sortie est calculée comme suit :
Or = max(Dr, Sr)
Og = max(Dg, Sg)
Ob = max(Db, Sb)
Pour le rouge, le vert et le bleu séparément, le résultat est supérieur à la destination et à la source. Cela produit l’effet d’éclaircir les zones sombres de la destination en premier.
Le Darken
mode est similaire, sauf que le résultat est le plus faible de la destination et de la source :
Or = min(Dr, Sr)
Og = min(Dg, Sg)
Ob = min(Db, Sb)
Les composants bleus, rouges, verts et bleus sont gérés séparément, c’est pourquoi ces modes de fusion sont appelés modes de fusion séparables . Pour cette raison, les abréviations Dc et Sc peuvent être utilisées pour les couleurs de destination et de source, et il est compris que les calculs s’appliquent à chacun des composants rouges, verts et bleus séparément.
Le tableau suivant présente tous les modes de fusion séparables avec de brèves explications sur ce qu’ils font. La deuxième colonne affiche la couleur source qui ne produit aucune modification :
Blend Mode | Aucun changement | Opération |
---|---|---|
Plus |
Noir | Éclaircit en ajoutant des couleurs : Sc + Dc |
Modulate |
White | Sombre en multipliant les couleurs : Sc· Dc |
Screen |
Noir | Compléments produits de compléments : Sc + Dc – Sc· Dc |
Overlay |
Gris | Inverse de HardLight |
Darken |
White | Minimum des couleurs : min(Sc, Dc) |
Lighten |
Noir | Nombre maximal de couleurs : max(Sc, Dc) |
ColorDodge |
Noir | Destination brightens basée sur la source |
ColorBurn |
White | Destination Darkens basée sur la source |
HardLight |
Gris | Similaire à l’effet d’une mise à l’honneur dure |
SoftLight |
Gris | Similaire à l’effet de la mise à jour réversible |
Difference |
Noir | Soustrait le plus sombre de l’clair : Abs(Dc – Sc) |
Exclusion |
Noir | Similaire à un Difference contraste inférieur |
Multiply |
White | Sombre en multipliant les couleurs : Sc· Dc |
Vous trouverez des algorithmes plus détaillés dans la spécification W3C Compositing et Blending Level 1 et la référence Skia SkBlendMode, bien que la notation de ces deux sources ne soit pas la même. Gardez à l’esprit qu’il Plus
est généralement considéré comme un mode de fusion Porter-Duff et Modulate
ne fait pas partie de la spécification W3C.
Si la source est transparente, pour tous les modes de fusion séparables à l’exception Modulate
du mode de fusion, le mode blend n’a aucun effet. Comme vous l’avez vu précédemment, le Modulate
mode blend incorpore le canal alpha dans la multiplication. Sinon, Modulate
a le même effet que Multiply
.
Notez les deux modes nommés ColorDodge
et ColorBurn
. Les mots dodge and burn proviennent de pratiques photographiques de salle noire. Un agrandisseur fait une impression photographique en éclatant la lumière à travers un négatif. Sans lumière, l’impression est blanche. L’impression devient plus sombre, car plus de lumière tombe sur l’impression pendant une plus longue période. Les imprimeurs utilisaient souvent une main ou un petit objet pour empêcher une partie de la lumière de tomber sur une certaine partie de l’impression, ce qui rend cette zone plus claire. C’est ce qu’on appelle le dodging. À l’inverse, un matériau opaque avec un trou dans celui-ci (ou les mains bloquant la plupart de la lumière) peut être utilisé pour diriger plus de lumière dans un endroit particulier pour l’assombrir, appelé brûlure.
Le programme Dodge et Burn est très similaire à Lighten et Darken. Le fichier XAML est structuré de la même façon, mais avec des noms d’éléments différents, et le fichier code-behind est de même assez similaire, mais l’effet de ces deux modes de fusion est assez différent :
Pour les petites Slider
valeurs, le Lighten
mode éclaircit d’abord les zones sombres, tout en ColorDodge
éclaircit plus uniformément.
Les programmes d’application de traitement d’images permettent souvent de restreindre et de brûler des zones spécifiques, comme dans une salle sombre. Cela peut être effectué par dégradés ou par une bitmap avec des nuances de gris variables.
Exploration des modes de fusion séparables
La page Modes de fusion séparables vous permet d’examiner tous les modes de fusion séparables. Il affiche une destination bitmap et une source de rectangle coloré à l’aide de l’un des modes de fusion.
Le fichier XAML définit un Picker
(pour sélectionner le mode blend) et quatre curseurs. Les trois premiers curseurs vous permettent de définir les composants rouges, verts et bleus de la source. Le quatrième curseur est destiné à remplacer ces valeurs en définissant une nuance grise. Les curseurs individuels ne sont pas identifiés, mais les couleurs indiquent leur fonction :
<?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>
Le fichier code-behind charge l’une des ressources bitmap et le dessine deux fois, une fois dans la moitié supérieure du canevas et à nouveau dans la moitié inférieure du canevas :
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);
}
}
}
Vers le bas du PaintSurface
gestionnaire, un rectangle est dessiné sur la deuxième bitmap avec le mode de fusion sélectionné et la couleur sélectionnée. Vous pouvez comparer la bitmap modifiée en bas avec la bitmap d’origine en haut :
Couleurs primaires additives et soustractives
La page Couleurs primaires dessine trois cercles qui se chevauchent de rouge, de vert et de bleu :
Il s’agit des couleurs primaires additives. Les combinaisons de deux produits cyan, magenta et jaune, et une combinaison des trois est blanche.
Ces trois cercles sont dessinés avec le SKBlendMode.Plus
mode, mais vous pouvez également utiliser Screen
, Lighten
ou Difference
pour le même effet. Voici le programme :
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);
}
}
}
}
Le programme comprend un TabGestureRecognizer
. Lorsque vous appuyez ou cliquez sur l’écran, le programme utilise SKBlendMode.Multiply
pour afficher les trois primaires soustractives :
Le Darken
mode fonctionne également pour ce même effet.