Filtres d’images SkiaSharp
Les filtres d’image sont des effets qui fonctionnent sur tous les bits de couleur de pixels qui composent une image. Ils sont plus polyvalents que les filtres de masque, qui fonctionnent uniquement sur le canal alpha comme décrit dans l’article Filtres de masque SkiaSharp. Pour utiliser un filtre d’image, définissez la ImageFilter
propriété d’un SKPaint
objet de type SKImageFilter
que vous avez créé en appelant l’une des méthodes statiques de la classe.
La meilleure façon de se familiariser avec les filtres de masque consiste à expérimenter ces méthodes statiques. Vous pouvez utiliser un filtre de masque pour flouter une image bitmap entière :
Cet article montre également l’utilisation d’un filtre d’image pour créer une ombre goutte-à-goutte, et pour les effets d’embossage et de gravure.
Flou des graphiques vectoriels et des bitmaps
L’effet de flou créé par la SKImageFilter.CreateBlur
méthode statique présente un avantage significatif sur les méthodes floues de la SKMaskFilter
classe : le filtre d’image peut flouter une image bitmap entière. La méthode a la syntaxe suivante :
public static SkiaSharp.SKImageFilter CreateBlur (float sigmaX, float sigmaY,
SKImageFilter input = null,
SKImageFilter.CropRect cropRect = null);
La méthode a deux valeurs sigma : la première pour l’étendue floue dans la direction horizontale et la seconde pour la direction verticale. Vous pouvez appliquer des filtres d’images en cascade en spécifiant un autre filtre d’image comme troisième argument facultatif. Un rectangle de rognage peut également être spécifié.
La page Image Blur Experiment dans l’exemple comprend deux Slider
vues qui vous permettent d’expérimenter la définition de différents niveaux de flou :
<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.ImageBlurExperimentPage"
Title="Image Blur Experiment">
<StackLayout>
<skia:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Slider x:Name="sigmaXSlider"
Maximum="10"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference sigmaXSlider},
Path=Value,
StringFormat='Sigma X = {0:F1}'}"
HorizontalTextAlignment="Center" />
<Slider x:Name="sigmaYSlider"
Maximum="10"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference sigmaYSlider},
Path=Value,
StringFormat='Sigma Y = {0:F1}'}"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
Le fichier code-behind utilise les deux Slider
valeurs à appeler SKImageFilter.CreateBlur
pour l’objet utilisé pour afficher à la fois du SKPaint
texte et une bitmap :
public partial class ImageBlurExperimentPage : ContentPage
{
const string TEXT = "Blur My Text";
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(MaskBlurExperimentPage),
"SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");
public ImageBlurExperimentPage ()
{
InitializeComponent ();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear(SKColors.Pink);
// Get values from sliders
float sigmaX = (float)sigmaXSlider.Value;
float sigmaY = (float)sigmaYSlider.Value;
using (SKPaint paint = new SKPaint())
{
// Set SKPaint properties
paint.TextSize = (info.Width - 100) / (TEXT.Length / 2);
paint.ImageFilter = SKImageFilter.CreateBlur(sigmaX, sigmaY);
// Get text bounds and calculate display rectangle
SKRect textBounds = new SKRect();
paint.MeasureText(TEXT, ref textBounds);
SKRect textRect = new SKRect(0, 0, info.Width, textBounds.Height + 50);
// Center the text in the display rectangle
float xText = textRect.Width / 2 - textBounds.MidX;
float yText = textRect.Height / 2 - textBounds.MidY;
canvas.DrawText(TEXT, xText, yText, paint);
// Calculate rectangle for bitmap
SKRect bitmapRect = new SKRect(0, textRect.Bottom, info.Width, info.Height);
bitmapRect.Inflate(-50, -50);
canvas.DrawBitmap(bitmap, bitmapRect, BitmapStretch.Uniform, paint: paint);
}
}
}
Les trois captures d’écran montrent différents paramètres pour les sigmaX
paramètres et sigmaY
les paramètres :
Pour maintenir la cohérence du flou entre différentes tailles d’affichage et résolutions, définissez sigmaX
et définissez des sigmaY
valeurs proportionnelles à la taille de pixel rendue de l’image à laquelle le flou est appliqué.
Ombre portée
La SKImageFilter.CreateDropShadow
méthode statique crée un SKImageFilter
objet pour une ombre portée :
public static SKImageFilter CreateDropShadow (float dx, float dy,
float sigmaX, float sigmaY,
SKColor color,
SKDropShadowImageFilterShadowMode shadowMode,
SKImageFilter input = null,
SKImageFilter.CropRect cropRect = null);
Définissez cet objet sur la ImageFilter
propriété d’un SKPaint
objet, et tout ce que vous dessinez avec cet objet aura une ombre portée derrière lui.
Les dx
paramètres indiquent dy
les décalages horizontaux et verticaux de l’ombre en pixels de l’objet graphique. La convention dans les graphiques 2D consiste à supposer une source de lumière provenant du coin supérieur gauche, ce qui implique que ces deux arguments doivent être positifs pour positionner l’ombre en dessous et à droite de l’objet graphique.
Les sigmaX
paramètres et sigmaY
les paramètres sont des facteurs flous pour l’ombre portée.
Le color
paramètre est la couleur de l’ombre portée. Cette SKColor
valeur peut inclure la transparence. Une possibilité est la valeur SKColors.Black.WithAlpha(0x80)
de couleur pour assombrir n’importe quel arrière-plan de couleur.
Les deux derniers paramètres sont facultatifs.
Le programme Drop Shadow Experiment vous permet d’expérimenter des valeurs de , dy
, sigmaX
et sigmaY
d’afficher une chaîne de dx
texte avec une ombre portée. Le fichier XAML instancie quatre Slider
vues pour définir ces valeurs :
<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.DropShadowExperimentPage"
Title="Drop Shadow Experiment">
<ContentPage.Resources>
<Style TargetType="Slider">
<Setter Property="Margin" Value="10, 0" />
</Style>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ContentPage.Resources>
<StackLayout>
<skia:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Slider x:Name="dxSlider"
Minimum="-20"
Maximum="20"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference dxSlider},
Path=Value,
StringFormat='Horizontal offset = {0:F1}'}" />
<Slider x:Name="dySlider"
Minimum="-20"
Maximum="20"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference dySlider},
Path=Value,
StringFormat='Vertical offset = {0:F1}'}" />
<Slider x:Name="sigmaXSlider"
Maximum="10"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference sigmaXSlider},
Path=Value,
StringFormat='Sigma X = {0:F1}'}" />
<Slider x:Name="sigmaYSlider"
Maximum="10"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference sigmaYSlider},
Path=Value,
StringFormat='Sigma Y = {0:F1}'}" />
</StackLayout>
</ContentPage>
Le fichier code-behind utilise ces valeurs pour créer une ombre de dépôt rouge sur une chaîne de texte bleue :
public partial class DropShadowExperimentPage : ContentPage
{
const string TEXT = "Drop Shadow";
public DropShadowExperimentPage ()
{
InitializeComponent ();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Get values from sliders
float dx = (float)dxSlider.Value;
float dy = (float)dySlider.Value;
float sigmaX = (float)sigmaXSlider.Value;
float sigmaY = (float)sigmaYSlider.Value;
using (SKPaint paint = new SKPaint())
{
// Set SKPaint properties
paint.TextSize = info.Width / 7;
paint.Color = SKColors.Blue;
paint.ImageFilter = SKImageFilter.CreateDropShadow(
dx,
dy,
sigmaX,
sigmaY,
SKColors.Red,
SKDropShadowImageFilterShadowMode.DrawShadowAndForeground);
SKRect textBounds = new SKRect();
paint.MeasureText(TEXT, ref textBounds);
// Center the text in the display rectangle
float xText = info.Width / 2 - textBounds.MidX;
float yText = info.Height / 2 - textBounds.MidY;
canvas.DrawText(TEXT, xText, yText, paint);
}
}
}
Voici le programme en cours d’exécution :
Les valeurs de décalage négatives dans la capture d’écran plateforme Windows universelle à l’extrême droite entraînent l’apparition de l’ombre au-dessus et à gauche du texte. Cela suggère une source de lumière en bas à droite, ce qui n’est pas la convention pour les graphiques informatiques. Mais il ne semble pas mal d’une manière quelconque, peut-être parce que l’ombre est également très floue et semble plus ornementale que la plupart des ombres goutte.
Effets d’éclairage
La SKImageFilter
classe définit six méthodes qui ont des noms et des paramètres similaires, répertoriées ici dans l’ordre de complexité croissante :
CreateDistantLitDiffuse
CreateDistantLitSpecular
CreatePointLitDiffuse
CreatePointLitSpecular
CreateSpotLitDiffuse
CreateSpotLitSpecular
Ces méthodes créent des filtres d’images qui imitent l’effet de différents types de lumière sur des surfaces tridimensionnelles. Le filtre d’image résultant illumine les objets à deux dimensions comme s’ils existaient dans l’espace 3D, ce qui peut entraîner l’apparition de ces objets élevés ou en retrait, ou avec une mise en surbrillance spéculaire.
Les Distant
méthodes de lumière supposent que la lumière provient d’une distance éloignée. Dans le but d’éclairer des objets, la lumière est supposée pointer dans une direction cohérente dans l’espace 3D, comme le Soleil sur une petite zone de la Terre. Les Point
méthodes de lumière imitent une ampoule positionnée dans l’espace 3D qui émet la lumière dans toutes les directions. La Spot
lumière a à la fois une position et une direction, beaucoup comme une lampe de poche.
Les emplacements et les directions dans l’espace 3D sont tous deux spécifiés avec des valeurs de la SKPoint3
structure, qui est similaire à SKPoint
mais avec trois propriétés nommées X
, Y
et Z
.
Le nombre et la complexité des paramètres de ces méthodes rendent l’expérimentation difficile. Pour commencer, la page Expérience légère distante vous permet d’expérimenter des paramètres dans la CreateDistantLightDiffuse
méthode :
public static SKImageFilter CreateDistantLitDiffuse (SKPoint3 direction,
SKColor lightColor,
float surfaceScale,
float kd,
SKImageFilter input = null,
SKImageFilter.CropRect cropRect = null);
La page n’utilise pas les deux derniers paramètres facultatifs.
Trois Slider
vues dans le fichier XAML vous permettent de sélectionner la Z
coordonnée de la SKPoint3
valeur, du surfaceScale
paramètre et du kd
paramètre, qui est défini dans la documentation de l’API comme « constante d’éclairage diffuse » :
<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="SkiaLightExperiment.MainPage"
Title="Distant Light Experiment">
<StackLayout>
<skia:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface"
VerticalOptions="FillAndExpand" />
<Slider x:Name="zSlider"
Minimum="-10"
Maximum="10"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference zSlider},
Path=Value,
StringFormat='Z = {0:F0}'}"
HorizontalTextAlignment="Center" />
<Slider x:Name="surfaceScaleSlider"
Minimum="-1"
Maximum="1"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference surfaceScaleSlider},
Path=Value,
StringFormat='Surface Scale = {0:F1}'}"
HorizontalTextAlignment="Center" />
<Slider x:Name="lightConstantSlider"
Minimum="-1"
Maximum="1"
Margin="10, 0"
ValueChanged="OnSliderValueChanged" />
<Label Text="{Binding Source={x:Reference lightConstantSlider},
Path=Value,
StringFormat='Light Constant = {0:F1}'}"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentPage>
Le fichier code-behind obtient ces trois valeurs et les utilise pour créer un filtre d’image pour afficher une chaîne de texte :
public partial class DistantLightExperimentPage : ContentPage
{
const string TEXT = "Lighting";
public DistantLightExperimentPage()
{
InitializeComponent();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float z = (float)zSlider.Value;
float surfaceScale = (float)surfaceScaleSlider.Value;
float lightConstant = (float)lightConstantSlider.Value;
using (SKPaint paint = new SKPaint())
{
paint.IsAntialias = true;
// Size text to 90% of canvas width
paint.TextSize = 100;
float textWidth = paint.MeasureText(TEXT);
paint.TextSize *= 0.9f * info.Width / textWidth;
// Find coordinates to center text
SKRect textBounds = new SKRect();
paint.MeasureText(TEXT, ref textBounds);
float xText = info.Rect.MidX - textBounds.MidX;
float yText = info.Rect.MidY - textBounds.MidY;
// Create distant light image filter
paint.ImageFilter = SKImageFilter.CreateDistantLitDiffuse(
new SKPoint3(2, 3, z),
SKColors.White,
surfaceScale,
lightConstant);
canvas.DrawText(TEXT, xText, yText, paint);
}
}
}
Le premier argument est SKImageFilter.CreateDistantLitDiffuse
la direction de la lumière. Les coordonnées X et Y positives indiquent que la lumière est pointée vers la droite et vers le bas. Les coordonnées Z positives pointent vers l’écran. Le fichier XAML vous permet de sélectionner des valeurs Z négatives, mais c’est seulement pour voir ce qui se passe : conceptuellement, les coordonnées Z négatives entraînent la lumière à pointer hors de l’écran. Pour quoi que ce soit d’autre puis de petites valeurs négatives, l’effet d’éclairage cesse de fonctionner.
L’argument surfaceScale
peut aller de -1 à 1. (Les valeurs supérieures ou inférieures n’ont aucun effet supplémentaire.) Il s’agit de valeurs relatives dans l’axe Z qui indiquent le déplacement de l’objet graphique (dans ce cas, la chaîne de texte) de l’aire de canevas. Utilisez des valeurs négatives pour élever la chaîne de texte au-dessus de la surface du canevas et les valeurs positives pour la décompresser dans le canevas.
La lightConstant
valeur doit être positive. (Le programme autorise les valeurs négatives afin que vous puissiez voir qu’elles provoquent l’arrêt du travail.) Les valeurs plus élevées provoquent une lumière plus intense.
Ces facteurs peuvent être équilibrés pour obtenir un effet embossé lorsqu’il surfaceScale
est négatif (comme avec les captures d’écran iOS et Android) et un effet gravé lorsqu’il surfaceScale
est positif, comme avec la capture d’écran UWP à droite :
La capture d’écran Android a une valeur Z de 0, ce qui signifie que la lumière pointe vers le bas et vers la droite. L’arrière-plan n’est pas éclairé et la surface de la chaîne de texte n’est pas éclairée non plus. La lumière n’affecte que le bord du texte pour un effet très subtil.
Une autre approche du texte embossé et gravé a été illustrée dans l’article The Translate Transform : The Translate String is afficher deux fois avec des couleurs différentes qui sont décalées légèrement les unes des autres.