Partager via


Filtres de couleurs SkiaSharp

Les filtres de couleurs peuvent traduire des couleurs dans une bitmap (ou une autre image) en d’autres couleurs pour des effets tels que la posterisation :

Exemple de filtres de couleurs

Pour utiliser un filtre de couleur, définissez la ColorFilter propriété d’un SKPaint objet de type SKColorFilter créé par l’une des méthodes statiques de cette classe. Le présent article porte sur les éléments suivants :

Transformation de couleur

La transformation de couleur implique l’utilisation d’une matrice pour modifier les couleurs. Comme la plupart des systèmes graphiques 2D, SkiaSharp utilise des matrices principalement pour transformer des points de coordonnées, comme indiqué dans l’article Matrix Transforms in SkiaSharp. La SKColorFilter matrice prend également en charge les transformations de matrice, mais la matrice transforme les couleurs RVB. Certaines connaissances sur les concepts de matrice sont nécessaires pour comprendre ces transformations de couleurs.

La matrice de transformation de couleur a une dimension de quatre lignes et cinq colonnes :

| M11 M12 M13 M14 M15 |
| M21 M22 M23 M24 M25 |
| M31 M32 M33 M34 M35 |
| M41 M42 M43 M44 M45 |

Il transforme une couleur source RVB (R, G, B, A) en couleur de destination (R', G', B', A').

En préparation de la multiplication de matrices, la couleur source est convertie en matrice 5×1 :

| R |
| G |
| B |
| A |
| 1 |

Ces valeurs R, G, B et A sont les octets d’origine compris entre 0 et 255. Elles ne sont pas normalisées en valeurs à virgule flottante comprises entre 0 et 1.

La cellule supplémentaire est requise pour un facteur de traduction. Cela est analogue à l’utilisation d’une matrice 3×3 pour transformer des points de coordonnées à deux dimensions, comme décrit dans la section The Reason for the 3-by-3 Matrix dans l’article sur l’utilisation de matrices pour transformer des points de coordonnées.

La matrice 4×5 est multipliée par la matrice 5×1, et le produit est une matrice de 4×1 avec la couleur transformée :

| M11 M12 M13 M14 M15 |    | R |   | R' |
| M21 M22 M23 M24 M25 |    | G |   | G' |
| M31 M32 M33 M34 M35 |  × | B | = | B' |
| M41 M42 M43 M44 M45 |    | A |   | A' |
                           | 1 |

Voici les formules distinctes pour R', G', B' et A' :

R' = M11·R + M12·G + M13·B + M14·A + M15

G' = M21·R + M22·G + M23·B + M24·A + M25

B' = M31·R + M32·G + M33·B + M34·A + M35

A' = M41·R + M42·G + M43·B + M44·A + M45

La plupart de la matrice se compose de facteurs multiplicatifs qui se trouvent généralement dans la plage de 0 à 2. Toutefois, la dernière colonne (M15 à M45) contient des valeurs ajoutées dans les formules. Ces valeurs varient généralement de 0 à 255. Les résultats sont limités entre les valeurs 0 et 255.

La matrice d’identité est la suivante :

| 1 0 0 0 0 |
| 0 1 0 0 0 |
| 0 0 1 0 0 |
| 0 0 0 1 0 |

Cela ne provoque aucune modification des couleurs. Les formules de transformation sont les suivantes :

R' = R

G' = G

B' = B

A' = A

La cellule M44 est très importante car elle conserve l’opacité. C’est généralement le cas que M41, M42 et M43 sont tous zéro, car vous ne voulez probablement pas que l’opacité soit basée sur les valeurs rouges, vertes et bleues. Mais si M44 est égal à zéro, alors A' sera zéro, et rien ne sera visible.

L’une des utilisations les plus courantes de la matrice de couleurs consiste à convertir une bitmap de couleur en bitmap à l’échelle grise. Cela implique une formule pour une moyenne pondérée des valeurs rouges, vertes et bleues. Pour les affichages vidéo à l’aide de l’espace de couleurs sRGB (« bleu vert rouge standard »), cette formule est la suivante :

gris-nuance = 0,2126· R + 0.7152· G + 0,0722· B

Pour convertir une bitmap de couleur en bitmap à l’échelle grise, les résultats R', G et B' doivent tous être identiques à cette même valeur. La matrice est la suivante :

| 0.21 0.72 0.07 0 0 |
| 0.21 0.72 0.07 0 0 |
| 0.21 0.72 0.07 0 0 |
| 0    0    0    1 0 |

Il n’existe aucun type de données SkiaSharp qui correspond à cette matrice. Au lieu de cela, vous devez représenter la matrice sous la forme d’un tableau de 20 float valeurs dans l’ordre de ligne : première ligne, puis deuxième ligne, etc.

La méthode statique SKColorFilter.CreateColorMatrix a la syntaxe suivante :

public static SKColorFilter CreateColorMatrix (float[] matrix);

matrix est un tableau des 20 float valeurs. Lorsque vous créez le tableau en C#, il est facile de mettre en forme les nombres afin qu’ils ressemblent à la matrice 4×5. Ceci est illustré dans la page Matrice à l’échelle grise de l’exemple :

public class GrayScaleMatrixPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(CenteredTilesPage),
                        "SkiaSharpFormsDemos.Media.Banana.jpg");

    public GrayScaleMatrixPage()
    {
        Title = "Gray-Scale Matrix";

        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();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0,     0,     0,     1, 0
                });

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

La DrawBitmap méthode utilisée dans ce code provient du fichier BitmapExtension.cs inclus dans l’exemple.

Voici le résultat en cours d’exécution sur iOS, Android et plateforme Windows universelle :

Matrice à l’échelle grise

Surveillez la valeur de la quatrième ligne et de la quatrième colonne. C’est le facteur crucial qui est multiplié par la valeur A de la couleur d’origine pour la valeur A de la couleur transformée. Si cette cellule est égale à zéro, rien n’est affiché et le problème peut être difficile à localiser.

Lorsque vous expérimentez avec des matrices de couleurs, vous pouvez traiter la transformation du point de vue de la source ou du point de vue de la destination. Comment le pixel rouge de la source doit-il contribuer aux pixels rouges, verts et bleus de la destination ? Cela est déterminé par les valeurs de la première colonne de la matrice. Sinon, comment le pixel rouge de destination doit-il être affecté par les pixels rouge, vert et bleu de la source ? Cela est déterminé par la première ligne de la matrice.

Pour obtenir des idées sur l’utilisation des transformations de couleurs, consultez les pages Recoloring Images. La discussion concerne Windows Forms et la matrice est un format différent, mais les concepts sont identiques.

La matrice Pastel calcule le pixel rouge de destination en atténuant le pixel rouge source et en mettant légèrement l’accent sur les pixels rouges et verts. Ce processus se produit de la même façon pour les pixels verts et bleus :

public class PastelMatrixPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(PastelMatrixPage),
                        "SkiaSharpFormsDemos.Media.MountainClimbers.jpg");

    public PastelMatrixPage()
    {
        Title = "Pastel Matrix";

        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();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.75f, 0.25f, 0.25f, 0, 0,
                    0.25f, 0.75f, 0.25f, 0, 0,
                    0.25f, 0.25f, 0.75f, 0, 0,
                    0, 0, 0, 1, 0
                });

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

Le résultat est de désactiver l’intensité des couleurs comme vous pouvez le voir ici :

Matrice pastel

Tableaux de couleurs

La méthode statique SKColorFilter.CreateTable est disponible en deux versions :

public static SKColorFilter CreateTable (byte[] table);

public static SKColorFilter CreateTable (byte[] tableA, byte[] tableR, byte[] tableG, byte[] tableB);

Les tableaux contiennent toujours 256 entrées. Dans la CreateTable méthode avec une table, la même table est utilisée pour les composants rouges, verts et bleus. Il s’agit d’une table de recherche simple : si la couleur source est (R, G, B) et que la couleur de destination est (R', B', G'), les composants de destination sont obtenus en indexant table avec les composants sources :

R' = table[R]

G' = table[G]

B' = table[B]

Dans la deuxième méthode, chacun de quatre composants de couleur peut avoir une table de couleurs distincte, ou les mêmes tables de couleurs peuvent être partagées entre deux composants ou plus.

Si vous souhaitez définir l’un des arguments sur la deuxième CreateTable méthode sur une table de couleurs qui contient les valeurs 0 à 255 en séquence, vous pouvez utiliser null à la place. Très souvent, l’appel CreateTable a un null premier argument pour le canal alpha.

Dans la section sur Posterization dans l’article sur l’accès aux bits de pixels bitmap SkiaSharp, vous avez vu comment modifier les bits de pixels individuels d’une bitmap pour réduire sa résolution de couleurs. Il s’agit d’une technique appelée posterisation.

Vous pouvez également poster une bitmap avec une table de couleurs. Le constructeur de la page Posterize Table crée une table de couleurs qui mappe son index à un octet avec les 6 bits inférieurs définis sur zéro :

public class PosterizeTablePage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(PosterizeTablePage),
                        "SkiaSharpFormsDemos.Media.MonkeyFace.png");

    byte[] colorTable = new byte[256];

    public PosterizeTablePage()
    {
        Title = "Posterize Table";

        // Create color table
        for (int i = 0; i < 256; i++)
        {
            colorTable[i] = (byte)(0xC0 & i);
        }

        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();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateTable(null, null, colorTable, colorTable);

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

Le programme choisit d’utiliser cette table de couleurs uniquement pour les canaux verts et bleus. Le canal rouge continue d’avoir une résolution complète :

Posterize Table

Vous pouvez utiliser différents tableaux de couleurs pour les différents canaux de couleur pour différents effets.