SVG : les filtres

Vous devez trouver que mes dessins sont enfantins et vous avez raison. Il n'y a pas de floutage, par d'ombrage, pas de dégradé. Pour que des dessins numériques aient un côté plus artistique il faut utiliser entre autres les ombrages et les floutages.

Les floutages et ombrages sont produits grâce à des filtres.
Mais grâce aux filtres SVG on peut appliquer aux images insérées d'autres effets qui sont bien connus des utilisateurs de photoshop : filtres de couleur, dilatation, contraction, luminosité, contraste, etc.
Un filtre est défini (dans la partie DEFS) grâce au conteneur filter avec l'attribut id pour identifier le filtre.
On applique un filtre à un objet SVG via l'attribut filter

Si vous produisez du SVG via Snap SVG vous pouvez faire l'impasse sur ce chapitre.
Cependant les possibilités sont plus étendues en SVG traditionnel ...
Il y a dans ce tuto une page sur la définition des filtres avec Snap.

Les filtres simples

Dans cette section de page je vais présenter des filtres simples c'est à dire basés sur une seule "primitive".

Floutage

Exemple

jolie fille nue

Le code correspondant

<svg width="50%" height="50%" viewBox ="0 0 400 200"> <defs> <filter id="flou"> <feGaussianBlur stdDeviation="6" /> </filter> </defs> <g style = "fill-opacity : 0.5 ; stroke-width : 5px;" filter = 'url(#flou)' > <rect x="25" y="25" fill = "orange" stroke="olive" width = '100' height = '100' ry ='10' /> <rect x="150" y="75" fill = 'yellow' stroke = 'purple' width = '200' height = '100' rx = '15' /> </g> </svg> <img width ="50%" src ="../images/jolie_fille.jpg" style ="filter : url(#flou) ;" />

Vous constatez que les rectangles ainsi que la photo sont floutés. On parle de flou gaussien.

J'ai défini un flou gaussien avec le conteneur filter incluant la balise feGaussianBlur.
On dit que feGaussianBlur est une primitive.
Ce filtre est identifié "flou". Pour diminuer le floutage il suffirait de réduire la valeur de l'attribut stdDeviation.

Le flou défini en SVG a été appliqué à un objet SVG mais aussi à un élément HTML (une image).
Maintenant le fait d'appliquer un filtre SVG à un élément HTML est une technique obsolète car désormais depuis la version 3 on peut définir des filtres en CSS.

La primitive feOffset

Exemple

Un rectangle et son ombre Une ellipse et son ombre

Le code SVG correspondant

<svg width="50%" height="50%" viewBox ="0 0 400 300"> <defs> <filter id="decale"> <feOffset dx="20" dy ="20"/> </filter> </defs> <title>Un rectangle et son ombre</title> <rect x="50" y="50" width = '100' height = '100' fill ='gray' filter="url(#decale)"/> <rect x="50" y="50" width = '100' height = '100' fill ='red'/> <title>Une ellipse et son ombre</title> <ellipse cx ="200" cy="200" rx ="100" ry ="50" fill ="gray" filter="url(#decale)" /> <ellipse cx ="200" cy="200" rx ="100" ry ="50" fill ="green" /> </svg>

La primitive feOffset décale tout simplement la forme selon les valeurs des attributs dx et dy.

Observez bien le code SVG. Les deux rectangles ont exactement les mêmes coordonnées pour l'arête supérieure gauche et les mêmes dimensions et pourtant le rectangle rempli de gris est décalé de 20 pixels en bas et à droite car il lui a été affecté le filtre identifié "decale".
Les deux ellipses ont aussi les mêmes coordonnées mais l'ellipse grise est aussi décalée de 20px par rapport à la verte.

Donc j'ai créé un effet d'ombre. Vous allez rétorquer à juste titre qu'une ombre c'est non seulement la même forme remplie de gris et décalée par rapport à la forme principale en premier plan mais que la forme grise doit être aussi légèrement floutée.

Il y a un deuxième bémol. L'ellipse grise est tronquée ...

Pour produire une ombre véritable il faudrait donc jouer sur deux primitives : feOffset et feGaussianBlur. Il faudrait donc créer un filtre basé sur ces deux primitives. Les filtres basés sur plusieurs primitives sont évoqués plus loin.

La primitive feMorphology

Exemple

Le code SVG correspondant

<svg width="100%" height="100%" viewBox ="0 0 800 200" > <defs> <filter id="dilatation"><feMorphology operator ="dilate" radius ="1" /></filter> <filter id="dilatation2"><feMorphology operator ="dilate" radius ="2" /></filter> <filter id="contraction"><feMorphology operator ="erode" radius ="1" /></filter> <filter id="contraction2"><feMorphology operator ="erode" radius ="2" /></filter> </defs> <image xlink:href="../images/jolie_fille.jpg" width="160" height ="200" x = "0" y = "0" filter = 'url(#dilatation)' /> <image ... filter = 'url(#dilatation2)' /> <image ... filter = 'url(#contraction)' /> <image ... filter = 'url(#contraction2)' /> </svg>

Les images font penser à des tableaux du courant "impressionniste"
Les deux images de gauche subissent une "dilatation" et celles de droite une "contraction" !

La primitive feMorphology permet de modifier la morphologie de l’image d'une image.
Deux opérations sont possibles : la dilatation et la contraction. L'attribut operator peut prendre en effet deux valeurs erode ou dilate.
Le niveau de contraction ou de dilatation est réglé grâce à l’attribut radius.

Les filtres de couleur

La primitive matrice de couleur permet de recalculer la valeur de chaque pixel de l’image (comme pour la matrice de convolution)
La nouvelle valeur du pixel est calculée par rapport aux quatre composantes: rouge, vert, bleu, canal alpha (transparence).
La primitive feColorMatrix a deux attributs type et values.
L'attribut type peut prendre les valeurs matrix, saturate, hueRotate, luminanceToAlpha.

Valeur de l'attribut type est hueRotate

Commençons par le type hueRotate car c'est le plus simple.

Exemple

Le code SVG correspondant

<svg width ="100%" height ="auto" viewBox ="0 0 800 200" > <defs> <filter id="rotation0"> <feColorMatrix type= "hueRotate" values ="0" /> </filter> <filter id="rotation90"> <feColorMatrix type= "hueRotate" values ="90" /> </filter> <filter id="rotation180"> <feColorMatrix type= "hueRotate" values ="180" /> </filter> <filter id="rotation270"> <feColorMatrix type= "hueRotate" values ="270" /> </filter> <filter id="rotation360"> <feColorMatrix type= "hueRotate" values ="360" /> </filter> </defs> <image xlink:href ="../images/jolie_fille.jpg" width="160" height="200" x="0" y ="0" filter ="url(#rotation0)"/> <image ... filter ="url(#rotation90)"/> <image ... filter ="url(#rotation180)"/> <image ... filter ="url(#rotation270)"/> <image ... filter="url(#rotation360)"/> </svg>

On définit différents filtres SVG de type hueRotate.
Notez que les valeurs de l'attribut values sont comprises entre 0 et 360 (degrés).
Il s’agit d’une rotation sur le cercle chromatique. Attention une rotation de 360° équivaut à une rotation de 0°.
Une rotation de 90 verdit l'image, une rotation de 180 bleuit la photo et une rotation de 270 rougit l'image.
Une rotation de 360 équivaut à une rotation de 0 et donc n'a indicidence sur l'image.

On applique ces différents filtres à chacune des insertions de la même image matricielle.

Valeur de l'attribut type est saturate

Un filtre de couleur avec l'attribut type valant saturate est aussi très simple.

Exemple

Le code SVG correspondant

<svg width ="100%" height ="auto" viewBox ="0 0 900 200"> <defs> <filter id="saturation0"> <feColorMatrix type= "saturate" values ="0" /> </filter> <filter id="saturation2"> <feColorMatrix type= "saturate" values ="2" /> </filter> <filter id="saturation1"> <feColorMatrix type= "saturate" values ="1" /> </filter> <filter id="saturation4"> <feColorMatrix type= "saturate" values ="4" /> </filter> <filter id="saturation6"> <feColorMatrix type= "saturate" values ="6" /> </filter> </defs> <image xlink:href ="../images/jolie_fille.jpg" width="160" height="200" x="0" y ="0" filter ="url(#saturation0)"/> <image ... filter ="url(#saturation2)"/> <image ... filter ="url(#saturation1)"/> <image ... filter ="url(#saturation4)"/> <image ... filter ="url(#saturation6)"/> </svg>

On définit différents filtres de type saturate.

La saturation permet d’abaisser ou augmenter l’intensité des couleurs d’une image.
Si l'attribut type vaut saturate alors l'attribut values prend comme valeur un entier positif.
Si la valeur est 0 alors l'image est en nuances de gris et si la valeur est 1 alors l'image filtrée est identique à l'original. Si la valeur est supérieure à 1 il y a saturation.

On applique ces différents filtres aux différentes insertions dans le canevas SVG de la même photo.

Valeur de l'attribut type est Matrix

On arrive à des choses un peu plus compliquées car il faut créer une matrice 4 * 5 !

Exemple

Le code correspondant

<svg width ="100%" height ="auto" viewBox ="0 0 900 200"> <defs> <filter id="moins_rouge"> <feColorMatrix type= "Matrix" values = "1 0 0 0 -0.3 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0" /> </filter> <filter id="moins_vert"> <feColorMatrix type= "Matrix" values = "1 0 0 0 0 0 1 0 0 -0.3 0 0 1 0 0 0 0 0 1 0" /> </filter> <filter id="moins_bleu"> <feColorMatrix type= "Matrix" values = "1 0 0 0 0 0 1 0 0 0 0 0 1 0 -0.3 0 0 0 1 0" /> </filter> </defs> <image xlink:href ="../images/jolie_fille.jpg" width="160" height="200" x="0" y ="0" filter ="url(#moins_rouge)"/> <image ... filter ="url(#moins_vert)"/> <image ... filter ="url(#moins_bleu)"/> </svg>

Trois filtres définis :

Les filtres de convolution

Les filtres de convolution permettent d’appliquer sur des images divers effets très utiles comme le floutage, l’embossage, la détection des contours ou le rehaussement des détails.

Un peu de théorie

Une convolution est un traitement d'une matrice par une autre appelée matrice de convolution ou « noyau » (kernel).

Le filtre étudie successivement chacun des pixels de l'image. Pour chaque pixel appelé « pixel initial », il multiplie la valeur de ce pixel et de chacun des 8 pixels qui l'entourent par la valeur correspondante dans le noyau. Il additionne l'ensemble des résultats et le pixel initial prend alors la valeur du résultat final.

Le noyau (valeur de l'attribut kernelMatrix est une matrice de 3 par 3.

Exemple

Le code SVG correspondant

<svg width ="100%" height ="auto" viewBox ="0 0 900 220" > <defs> <filter id="contraster"> <feConvolveMatrix kernelMatrix ="0 -1 0 -1 5 -1 0 -1 0" /> </filter> <filter id="flou"> <feConvolveMatrix kernelMatrix ="1 1 1 1 1 1 1 1 1" /> </filter> <filter id="rehausse"> <feConvolveMatrix kernelMatrix ="-1 -1 -1 -1 9 -1 -1 -1 -1" /> </filter> <filter id="repoussage"> <feConvolveMatrix kernelMatrix ="-2 -1 0 -1 1 1 0 1 2" /> </filter> <filter id="detecter"> <feConvolveMatrix preserveAlpha = "true" kernelMatrix ="-1 -1 -1 -1 8 -1 -1 -1 -1" /> </filter> </defs> <image xlink:href ="../images/jolie_fille.jpg" width="160" height="200" x="0" y ="0" filter ="url(#contraster)"/> <image ... filter ="url(#flou)"/> <image ... filter ="url(#rehausse)"/> <image ... filter ="url(#repoussage)"/> <image ... filter ="url(#detecter)"/> </svg>

On définit cinq filtres dans le conteneur defs

Attention notez que pour ce dernier filtre, outre l'attribut kernelMatrix il y a l'attribut preserveAlpha avec la valeur true. Cela indique que le filtre de convolution ne s'applique pas à la couche Alpha (opacité)

On insère dans le canevas cinq fois la même image matricielle et pour chaque insertion on applique un des filtres.

Les filtres composites en SVG

Effet d'ombre

un rectangle ombré une ellipse ombrée

Le code SVG correspondant

<svg width="50%" height="50%" viewBox ="0 0 400 300"> <defs> <filter id="ombrage"> <feGaussianBlur stdDeviation="3" result ="flou"/> <feOffset in ="flou" dx="20" dy ="20" /> </filter> </defs> <title>un rectangle ombré</title> <rect x="50" y="50" width = '100' height = '100' fill ='gray' filter="url(#ombrage)" /> <rect x="50" y="50" width = '100' height = '100' fill ='red'/> <title>une ellipse ombrée</title> <ellipse cx="200" cy="200" rx = '100' ry = '50' fill ='gray' filter="url(#ombrage)" /> <ellipse cx="200" cy="200" rx = '100' ry = '50' fill ='red'/> </svg>

Le filtre identifié ombrage est basé sur deux primitives :

Notez l'emploi de l'attribut result pour le première primitive et de l'attribut in pour la deuxième primitive.
Cela veut dire que l'on chaîne les filtres ; la primitive FeOffset s'applique au flou produit par la première primitive et identifié "flou".

Ce filtre composite est appliqué à deux formes grises (un rectangle et une ellipse).
Retour menu