Exemples ImageMagick -- Anticrénelage
- Exemples ImageMagick : préface et index
- Introduction à l'anticrénelage
- Dessiner avec seulement des couleurs précises
- Dessiner de fins cercles bitmap
- Anticrénelage et problèmes de remplissage par diffusion
L'anticrénelage occupe une place majeure dans toutes les opérations de dessin d'ImageMagick. Malheureusement, il peut aussi provoquer de nombreux problèmes. Cette page tente de couvrir ces problèmes et d'en présenter les solutions.
Introduction à l'anticrénelage Lorsqu'ImageMagick dessine des images, il le fait d'une manière très particulière. Il les dessine au moyen d'une opération appelée « anticrénelage ». Pour le montrer, je vais dessiner une image sur un fond transparent, puis agrandir une petite partie de l'image afin que vous puissiez voir ce qui se passe.
magick -size 80x80 xc:none \
-fill white -draw "circle 40,40 15,20" \
-fill black -draw "line 5,30 78,2" drawn.png
magick drawn.png -crop 10x10+50+5 +repage -scale 80x80 drawn_mag.png
On pourrait penser que l'image ci-dessus ne comporte que trois couleurs, « white », « black » et « transparent », puisque c'est tout ce que nous avons demandé à IM d'utiliser. Mais comme vous pouvez le constater lorsque l'image est agrandie, elle contient toute une gamme de couleurs. Ce faisant, ImageMagick rend l'image plus lisse et plus agréable à l'œil grâce à une technique appelée « anticrénelage ». Ce terme savant signifie simplement qu'il remplit les pixels du bord de l'objet avec un mélange de couleurs, voire de transparences, afin de rendre l'objet plus lisse. Sans anticrénelage, les bords de tous les objets dessinés présenteraient un effet d'escalier appelé « crénelage », plus communément désigné par le terme d'« aspect crénelé » (les jaggies). Ici, nous dessinons de nouveau l'image, mais cette fois en demandant à IM de désactiver ses opérations d'anticrénelage automatiques, à l'aide de « [+antialias](https://imagemagick.org/command-line-options/#antialias) ».
magick -size 80x80 xc:none +antialias \
-fill white -draw "circle 40,40 15,20" \
-fill black -draw "line 5,30 78,2" drawn_jaggies.png
magick drawn_jaggies.png -crop 10x10+50+5 +repage -scale 80x80 \
drawn_jaggies_mag.png
Cette fois, l'image ne comporte réellement que trois couleurs. Mais le résultat n'est pas beau du tout. Sur les versions récentes d'IM, une seule rangée de pixels est tracée, en escalier. Sur les versions plus anciennes d'IM, la ligne aurait aussi eu une apparence assez épaisse, ce qui la rendait encore plus laide. Fondamentalement, ce n'est pas quelque chose que l'on souhaite normalement faire. L'escalier des effets de « crénelage », aussi couramment appelé « aspect crénelé », est précisément ce qu'IM cherchait à éviter. Mais si vous voulez des couleurs précises, il vous faudra l'accepter, ou recourir à d'autres techniques (comme la quantification des couleurs) pour garantir de n'employer que certaines couleurs. Notez qu'il se produit en réalité deux formes d'anticrénelage. La première est un mélange des couleurs blanche et noire de l'image, produisant diverses nuances, du gris dans ce cas. L'autre forme est un mélange de la couleur et de la transparence pour générer des pixels semi-transparents dans l'image. Cette dernière est un point à garder à l'esprit, car de nombreux formats d'image (comme le GIF) ne savent pas gérer les pixels semi-transparents et rendront ces pixels soit totalement opaques, soit totalement transparents. Les exemples de la page Transparence booléenne du GIF montrent des méthodes permettant de contrôler le traitement des pixels semi-transparents lors de l'enregistrement dans de tels formats.
Résumé
L'anticrénelage est très important dans tout type de dessin d'image, et c'est un point à garder à l'esprit. Sans prendre en compte les couleurs mélangées et les pixels semi-transparents générés par l'anticrénelage d'IM, vos propres créations d'images peuvent avoir un très mauvais rendu dans certains formats. Cela devient encore plus important lorsque vous créez des images dans un format qui n'autorise pas les pixels semi-transparents, comme le très répandu format « GIF ». Voir Transparence booléenne du GIF pour des façons de gérer ce problème. IM est très bon pour l'anticrénelage des couleurs et des transparences, mais en réalité très mauvais pour dessiner uniquement des pixels purement « crénelés » (afin de correspondre à une table de couleurs précise, par exemple). On m'a dit que ce serait l'objet d'une prochaine version d'IM.
Dessiner en utilisant seulement des couleurs précises
En construction
De meilleures façons de dessiner sans anticrénelage, afin de générer des images aux couleurs exactes. C'est-à-dire pour les « images indexées ». Plus précisément, dessiner dans un canevas transparent, appliquer un seuil sur le canal alpha, puis superposer, de sorte que seuls des pixels totalement opaques soient jamais dessinés.
Dessiner de fins cercles bitmap
Nous examinons ici comment tenter de dessiner des cercles bitmap à « fine ligne » avec IM. Normalement, cela se fait à l'aide d'un algorithme de tracé de cercle bitmap couramment connu sous le nom d'algorithme du cercle de Bresenham, mais plus correctement appelé algorithme du point médian pour le cercle. Malheureusement, il n'est pas disponible dans ImageMagick, et ne le sera peut-être jamais, car il est inutile dans un environnement de dessin entièrement anticrénelé. Une autre solution pour dessiner des cercles, que nous verrons dans un instant, consiste à utiliser la morphologie pour « dilater » un pixel unique à l'aide du noyau en anneau spécial.
Par exemple, la façon habituelle dont IM dessine un cercle produit beaucoup de couleurs d'anticrénelage grises pour donner au cercle une apparence lisse. |
magick -size 15x15 xc: -fill none -stroke black \
-draw 'translate 7,7 circle 0,0 5,0' \
-scale 500% circle_antialiased.gif
![[IM Output]](../static/img/antialiasing/circle_antialiased.gif)
Cependant, se contenter de désactiver l'anticrénelage produit des cercles et des lignes qui ne sont pas de belles et fines lignes « bitmap ». |
magick -size 15x15 xc: -fill none -stroke black +antialias \
-draw 'translate 7,7 circle 0,0 5,0' \
-scale 500% circle_aliased.gif
![[IM Output]](../static/img/antialiasing/circle_aliased.gif)
Ce qu'il faut faire, c'est aussi ajuster « [-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) », qui vaut par défaut 1 pixel de large, à une valeur plus petite, telle que 0,5 pixel de large. |
magick -size 15x15 xc: -fill none -stroke black +antialias \
-strokewidth 0.5 -draw 'translate 7,7 circle 0,0 5,0' \
-scale 500% circle_thin_stroke.gif
![[IM Output]](../static/img/antialiasing/circle_thin_stroke.gif)
Mieux, mais pas tout à fait parfait. Mais on peut aussi rendre la largeur du trait trop petite, en particulier avec des rayons de taille impaire. |
magick -size 15x15 xc: -fill none -stroke black +antialias \
-strokewidth 0 -draw 'translate 7,7 circle 0,0 5,0' \
-scale 500% circle_zero_stroke.gif
![[IM Output]](../static/img/antialiasing/circle_zero_stroke.gif)
Et voici une bonne solution pour un cercle de 5 pixels centré sur une position de pixel réelle entière. |
magick -size 15x15 xc: -fill none -stroke black +antialias \
-strokewidth 0.4 -draw 'translate 7,7 circle 0,0 5,0' \
-scale 500% circle_perfect.gif
![[IM Output]](../static/img/antialiasing/circle_perfect.gif)
Cependant, après de nombreuses expériences, je n'ai pu trouver aucune « [-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) » qui fonctionne pour tous les rayons et tous les centres. En particulier pour un cercle légèrement décentré.
Il n'existe pas de solution idéale pour toutes les situations
Par exemple, ce cercle qui n'est centré ni sur un pixel ni sur une frontière de pixel présente non seulement des lacunes en haut, mais est aussi trop épais en bas ! Beurk ! |
magick -size 15x15 xc: -fill none -stroke black +antialias \
-strokewidth 0.47 -draw 'translate 7,7.3 circle 0,0 5,0' \
-scale 500% circle_bad_stroke.gif
![[IM Output]](../static/img/antialiasing/circle_bad_stroke.gif)
Voici un tableau des bonnes valeurs de « [-strokewidth](https://imagemagick.org/command-line-options/#strokewidth) » permettant de générer un fin cercle d'un pixel de large pour un rayon donné. Notez que la meilleure valeur à utiliser varie selon que le cercle est centré soit sur un pixel réel (comme « 5 , 5 »), soit sur une frontière de demi-pixel (comme « 5.5 , 5.5 »). Rayon du cercle | SW réel | SW demi
---|---|---
1 | 0.3 | 0.3 ¶
1.5 | 0.5 ¶ | 0.3
2 | 0.3 | 0.3 §
2.5 | 0.5 ¶ | 0.3 ¤
3 | 0.3 ¤ | 0.3
3.5 | 0.5 | 0.3 ¤
4 | 0.5 § | 0.3
4.5 | 0.5 | 0.3
5 | 0.4 | 0.3
5.5 | 0.5 ¶ | 0.3
6 | 0.3 | 0.5 §
6.5 | 0.5 | 0.43
7 | 0.5 | 0.434
7.5 | 0.5 § | 0.5 §
8 | 0.4 | 0.5
¤ Très bon petit cercle
§ aucune largeur idéale trouvée
¶ le cercle est très mauvais
REMARQUE : pour centrer un cercle sur une image, en coordonnées de dessin (coordonnées de pixel), c'est (size-1)/2
Anticrénelage et problèmes de remplissage par diffusion En raison des fonctionnalités d'anticrénelage d'IM, le remplissage par diffusion (« [-draw](https://imagemagick.org/command-line-options/#threshold) color floodfill ») pose des problèmes lorsqu'il est utilisé sur des images comportant des effets d'anticrénelage. Il présente aussi des problèmes similaires avec les images lues depuis le format « JPG ». Fondamentalement, comme la plupart des objets dans IM sont anticrénelés (ou lus depuis un fichier image au format « JPG »), les couleurs près des bords des objets dessinés sont rarement la couleur précise que vous utilisez le remplissage par diffusion pour remplacer. Cela signifie que le remplissage par diffusion ne remplira pas les tout bords des zones que vous essayez de remplir, à moins d'éviter entièrement l'anticrénelage. Essentiellement, le remplissage par diffusion, ou même le remplacement de couleur, ne comprend pas l'anticrénelage et n'utilise pas non plus lui-même de techniques d'anticrénelage. Par conséquent, le remplissage par diffusion manquera généralement les pixels situés au tout bord de la zone que vous remplissez. Par exemple, effectuons ici une opération de remplissage par diffusion typique. Dessinons un cercle, puis essayons de le remplir avec un motif... |
magick -size 60x60 xc:lightblue -strokewidth 2 \
-fill none -stroke red -draw "circle 30,30 5,30" \
-tile tile_weave.gif -draw "color 30,30 floodfill" \
tile_fill_1.gif
magick tile_fill_1.gif -crop 10x10+35+4 +repage -scale 80x80 \
tile_fill_1_mag.gif
![[IM Output]](../static/img/antialiasing/tile_fill_1_mag.gif)
Comme vous pouvez le voir dans la partie agrandie de l'image, une rangée de pixels « de couleur légèrement différente » a été complètement manquée par l'opération de remplissage par diffusion, car la couleur de ces pixels n'était pas tout à fait la même que celle de la zone que vous remplissiez. Une façon d'améliorer cela est de préremplir les zones que vous comptez remplir avec une couleur qui correspond au motif que vous utilisez. Le motif ne remplira toujours pas la zone entièrement, mais au moins l'aspect ne sera pas aussi mauvais. |
magick -size 60x60 xc:lightblue -strokewidth 2 \
-fill black -stroke red -draw "circle 30,30 5,30" \
-tile tile_weave.gif -draw "color 30,30 floodfill" \
tile_fill_2.gif
magick tile_fill_2.gif -crop 10x10+35+4 +repage -scale 60x60 \
tile_fill_2_mag.gif
![[IM Output]](../static/img/antialiasing/tile_fill_2_mag.gif)
Une autre façon de procéder est de remplir la zone avec votre motif en utilisant un facteur de flou (fuzz) élevé, afin de forcer le motif à remplir complètement la zone, jusqu'au tout bord, sans manquer les pixels du bord. |
magick -size 60x60 xc:lightblue -strokewidth 2 \
-fill none -stroke red -draw "circle 30,30 5,30" \
-fuzz 35% -tile tile_weave.gif -draw "color 30,30 floodfill" \
tile_fill_3.gif
magick tile_fill_3.gif -crop 10x10+35+4 +repage -scale 60x60 \
tile_fill_3_mag.gif
![[IM Output]](../static/img/antialiasing/tile_fill_3_mag.gif)
| Notez qu'un facteur de flou élevé comme celui-ci, ou une bordure trop fine, peut faire « déborder » le motif de remplissage hors de la zone définie. Une certaine prudence est toujours nécessaire lors de l'utilisation d'une opération de remplissage par diffusion. Je ne la recommande d'ailleurs pas comme solution générale, pour cette raison.
---|---
Le problème est que, comme le remplissage par diffusion, par sa nature même, n'utilise PAS lui-même l'anticrénelage, les bords de la zone remplie souffrent de l'« aspect crénelé » ou des effets de crénelage. Vous pouvez améliorer cette situation en séparant le dessin de l'image en plusieurs étapes distinctes. Créez un cercle coloré, remplissez-le, puis dessinez la bordure. |
magick -size 60x60 xc:lightblue -fill black -draw "circle 30,30 5,30" \
-tile tile_weave.gif -draw "color 30,30 floodfill" +tile \
-fill none -stroke red -strokewidth 2 -draw "circle 30,30 5,30" \
tile_fill_4.gif
magick tile_fill_4.gif -crop 10x10+35+4 +repage -scale 60x60 \
tile_fill_4_mag.gif
![[IM Output]](../static/img/antialiasing/tile_fill_4_mag.gif)
C'est une façon simple d'améliorer le remplissage par diffusion. Une autre consiste à utiliser une superposition en forme, mais cette méthode peut être délicate à mettre au point. J'examinerai plus tard des modifications similaires sur des images existantes. Bien entendu, si vous dessinez vous-même la zone remplie par diffusion et n'utilisez pas une image existante, la solution idéale serait d'éviter le remplissage par diffusion en spécifiant le motif de remplissage dès l'opération de dessin d'origine. |
magick -size 60x60 xc:lightblue -strokewidth 2 \
-tile tile_weave.gif -stroke red -draw "circle 30,30 5,30" \
tile_fill_5.gif
magick tile_fill_5.gif -crop 10x10+35+4 +repage -scale 60x60 \
tile_fill_5_mag.gif
FUTUR : problèmes d'anticrénelage sur des images préexistantes (surtout au format JPG).
Par exemple, recolorer et superposer une image de texte ou de schéma sur une
couleur ou un arrière-plan.
Également, réajouter de la transparence à des fichiers GIF, et à des JPEG redimensionnés pour un usage en icône.
**Lissage ou anticrénelage d'images à jeu de couleurs limité**
Plus précisément les images bitmap (noir et blanc pur).
D'abord, l'anticrénelage ne fonctionne pas sur les images bitmap.
L'anticrénelage consiste à utiliser un mélange de couleurs et de transparences pour
tenter de lisser l'effet d'« escalier » ou d'« aspect crénelé » des lignes obliques et
des frontières de couleur. Si seules deux couleurs sont disponibles, aucun anticrénelage ne peut se produire !
L'image doit être convertie depuis le N&B ou les niveaux de gris au minimum avant
de pouvoir utiliser l'anticrénelage.
Une façon simple de lisser les bords est d'appliquer un léger flou après avoir lu
une image N&B ou une image dont la palette est de taille minuscule.
EX : magick image.xbm -blur 0x.3 smoothed_image.png
![[IM Output]](../static/img/antialiasing/drawn.png)
![[IM Output]](../static/img/antialiasing/drawn_mag.png)
![[IM Output]](../static/img/antialiasing/drawn_jaggies.png)
![[IM Output]](../static/img/antialiasing/drawn_jaggies_mag.png)
![[IM Output]](../static/img/antialiasing/tile_fill_5.gif)
![[IM Output]](../static/img/antialiasing/tile_fill_5_mag.gif)