Les bases
Dans cette partie, je vais vous présenter les bases qui vont vous permettre d'utiliser le module egd dans vos applications.
Prérequis
Information
Il faut savoir qu'egd considère toujours que l'origine d'un graphique est le point supérieur gauche, il faudra vous souvenir de cela dans la suite de ce tutoriel. À part cela, il n'y a rien de particulier à connaître, on peut commencer !
Types de base
- Les points : représentés dans la doc par le type point(), ce sont en fait de simples couples contenant des entiers. Des entiers uniquement. Si vous utilisez des nombres décimaux, cela va faire échouer votre programme. En Erlang, pour transformer des nombres décimaux en entiers, vous pouvez utiliser deux fonctions :
- « @spec trunc(Number) -> int() » : cette fonction va tronquer le nombre que vous lui passerez et renverra l'entier ainsi obtenu ;
- « @spec round(Number) -> int() » : celle-ci va retourner l'arrondi du nombre passé en argument.
- Les couleurs : représentées par le type color() (étonnant, n'est-ce pas ?
) sont encore une fois des tuples, contenant cette fois un triplet d'entiers contenus entre 0 et 255, vous allez ainsi représenter vos couleurs avec la notation RGB.
- L'image est, elle, représentée par le type egd_image() (eh oui, cette fois y a un préfixe, c'est plus long à écrire
) et elle contient en fait deux valeurs, la hauteur et la largeur.
En fait, j'ai un peu simplifié les choses quand je vous ai dit que le type color() était un tuple contenant 3 entiers : le type est en fait le résultat de la fonction egd:color/1 où l'argument est bien le tuple présenté précédemment. De même pour le type de l'image, il faut en fait passer la largeur et la hauteur en arguments de la fonction egd:create/2 qui va, elle, retourner le type image qui va être utilisé par la suite.
Parmi les types que vous venez de découvrir, certains vont vous servir dans la quasi-totalité des fonctions que vous allez rencontrer : c'est le type
egd_image() et le type
color(). Mais plutôt que d'en parler, voyez par vous-mêmes.
Relier deux points
C'est probablement la plus simple des fonctions, mais ce n'est pas la moins utilisée. Nous allons ici découvrir une fonction permettant de relier deux points du graphique :
«
@spec egd:lines(Image::egd_image(), Point1::point(), Point2::point(), Couleur::point()) -> ok »
Bon ok, je ne vous apprends rien, vous auriez pu lire la doc pour savoir ça

(et pour tout dire, ça n'aurait pas forcément été une mauvaise idée).
À ce stade, vous devez être capables de créer votre image, de définir les couleurs que vous allez utiliser et désormais tracer des segments, voyons voir ça :
Code : Erlang 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | -module(graph). % oui, le nom est très recherché :)
-compile(export_all). % très utile lorsque vous exportez toutes vos fonctions
% et que vous en avez vraiment une liste considérable (ok,
% ce n'est pas le cas ici, mais tant pis, j'avais la flemme).
-define(height, 170). % définir de telles macros peut rendre votre code _bien_ plus
-define(width, 170). % lisible, notamment pour des personnes tierces.
init() ->
MyImage = egd:create(?width, ?height),
Black = egd:color({0, 0, 0}),
Red = egd:color({255, 0, 0}),
Green = egd:color({0, 255, 0}),
drawLines(MyImage, [Black, Red, Green]).
getPoints(X, Y, Nb) ->
MaxX = X + (50 * Nb),
MaxY = Y + (50 * Nb),
Xs = list:seq(X, MaxX, 50),
Ys = list:seq(Y, MaxY, 50),
lists:zip(Xs, Ys).
drawLines(Img, ColorList) ->
Nb = length(ColorList),
PointList = getPoints(0, Nb, {10, 10}, []),
List = lists:zip(PointList, ColorList),
lists:foreach(fun({{P1, P2}, Color}) -> egd:lines(Img, P1, P2, Color) end, List).
|
Ce code va en fait tracer autant de segments que vous définirez de couleurs ; dans le cas présent, ça va faire deux segments. Voyons comment observer le résultat !
Tracer et enregistrer votre graphique
Pour ce faire, vous allez avoir besoin de deux fonctions :
- « @spec egd:render(Image::egd_image()) -> binary() » qui va se charger de « tracer » votre graphique ;
- « @spec egd:save(Binary::binary(), Filename::string()) -> ok » ; vous devrez lui passer le résultat de la fonction egd:render/1 et indiquer le nom de l'image que vous souhaitez enregistrer.
Vous pouvez désormais modifier le code précédent afin qu'il enregistre votre image une fois que vous aurez fini de tracer votre graphique. Voici la nouvelle fonction
init/0 :
Code : Erlang1
2
3
4
5
6
7 | init() ->
MyImage = egd:create(?width, ?height),
Black = egd:color({0, 0, 0}),
Red = egd:color({255, 0, 0}),
drawLines(MyImage, [Black, Red]),
ToSave = egd:render(MyImage),
egd:save(ToSave, "<votre_dossier>/images/tutoriel.png").
|
Voilà, il ne vous reste qu'à baver (ou pas

) devant votre superbe graphique.
Maintenant que vous savez tracer des traits et enregistrer vos graphiques, on va pouvoir commencer à regarder plus sérieusement ce module, parce que bon, tracer des segments, ça va bien deux minutes, et même si on peut tout faire avec, ce n'est vraiment pas le truc le plus pratique, ni le plus rapide au monde. Heureusement, les développeurs d'egd ont pensé à vous, et ils ont rajouté quelques fonctions assez utiles pour tracer, entre autres, des formes géométriques.
Des formes plus élaborées
1/ Des rectangles
Sans doute la forme la plus simple, vous pouvez tracer des rectangles simplement à l'aide des fonctions :
- « @spec egd:rectangle(Image::egd_image(), Point1::point(), Point2::point(), Color::color()) -> ok »
- « @spec egd:filledRectangle(Image::egd_image(), Point1::point(), Point2::point(), Color::color()) -> ok »
Qui vont respectivement vous créer des rectangles vides ou colorés.
Point1 sera le point supérieur gauche du rectangle et
Point2, le point inférieur droit. Bref, rien de bien compliqué.

Vous pouvez essayer de modifier le code précédent pour qu'il vous trace des rectangles à la place des segments.
2/ Des ellipses
Vous ne disposez cette fois que d'une seule fonction :
«
@spec egd:filledEllipse(Image::egd_image(), Point1::point(), Point2::point(), Color::color()) -> ok »
Les deux points sont ici les points supérieur gauche et inférieur droit du rectangle entourant l'ellipse. N'ayez crainte, vous ne verrez pas des rectangles autour de vos ellipses, c'est juste plus simple de se l'imaginer ainsi. Si vous voulez voir de quoi je parle, couplez cette fonction à la fonction
egd:rectangle/4.
Avec les fonctions que l'on a vues dans les deux parties précédentes, vous devriez être en mesure de tracer bon nombre de graphiques, mais il vous faut savoir écrire du texte, et découvrir les quelques options avancées d'egd. Après quoi vous pourrez faire à peu près tout ce que vous voulez.
3/ Écrire du texte
La police
Pour écrire du texte, il va tout d'abord falloir définir la police que vous souhaitez utiliser ; les polices disponibles par défaut se trouvent dans le répertoire :
$ERLANG/lib/percept-$version/priv/Fonts, où
$ERLANG est le dossier où vous avez installé Erlang. Pour pouvoir sélectionner une police, il faut tout d'abord indiquer son adresse à l'aide de la fonction :
filename:join/1 (cf.
la doc pour plus d'informations). Voilà comment faire utiliser, par exemple, la police
6x11_latin1 :
Code : Erlang1 | Filename = filename:join([code:priv_dir(percept), "fonts", "6x11_latin1.wingsfont"])
|
Une fois que vous avez l'adresse du fichier, il suffit juste de le charger à l'aide de
egd_font:load/1 :
Code : Erlang1 | Font = egd_font:load(Filename)
|
Écrire
Une fois que vous avez défini votre police, il ne vous reste plus qu'à écrire votre texte. Pour cela, il vous suffit d'utiliser la fonction :
«
@spec egd:text(Image::egd_image(), Point::point(), Text::string(), Color::color()) -> ok »
Où
Point est le point supérieur gauche de la première lettre de votre texte.
Les options de render
Le type de l'image
Vous avez vu précédemment que la fonction
egd:render/1 vous permettait d'enregistrer vos images au format
png, cette fonction est en fait un lien vers
egd:render/2, mais le 2e argument est directement mis à
png. Si jamais vous ne voulez pas utiliser le
png,
egd:render/2 vous permet de choisir le type de votre image entre
bitmap et...
png.

Les deux types disponibles sont donc :
Opaque ou... ?
Eh oui, vous pouvez aussi spécifier si le fond de votre image sera opaque ou non, cela à l'aide des options de
egd:render/3 : le 3e argument est de type :
render_option(), c'est-à-dire un des deux tuples suivants :
- {render_engine, opaque}
- {render_engine, alpha}