L'inclusion de textes dans les images est quelque chose de très utile, pour ne pas dire indispensable et cette facette de gd méritait bien un article à elle toute seule. Je parlerai donc ici de l'utilisation de la librairie freetype-2.x pour la génération d'images avec gd-2.0.1, en langage c. En effet, à l'heure où j'écris ces lignes la librairie gd-2 n'est pas encore stable mais bon, elle le sera bientôt et les seules nouveautés d'ici là ne seront que corrections d'éventuels bugs. Pour ce qui est du choix de ne traiter que la librairie freetype-2, il vient du fait que la version 2 de gd fait pareil. Les anciennes fonction liées à freetype-1 (celles qui se terminent par TTF) ne font que renvoyer vers celles liées à freetype-2 (celles qui se terminent par FT).
A l'issue de cette première partie de l'article, vous pourrez utiliser vos polices de windows à partir de programmes c sous linux, ainsi que toutes les autres polices truetype, freetype, ... (voir http://www.freetype.org pour plus d'infos)
La deuxième partie de cet article examinera les nouveautés de gd dans sa deuxième version.
Téléchargez la dernière version de Freetype-2. Lors de l'écriture de l'article, il s'agissait de la version 2.0.3.
Voici comment on l'installe :
Placez vous dans le répertoire dans lequel vous avez téléchargé freetype puis tapez :
tar xvfy freetype-2.0.3.tar.bz2 cd freetype-2.0.3 make setup make su make install
Cela installe freetype sous /usr/local. Vous pouvez ensuite redevenir "simple utilisateur".
Pour avoir plus d'informations sur l'installation de gd, consultez le premier article sur [libgd.php3 gd], sur léa.
Placez vous dans le répertoire dans lequel vous avez téléchargé gd puis tapez
tar xvfz gd-2.0.1.tar.gz cd gd-2.0.1
Editez le début du Makefile comme suit :
COMPILER=gcc AR=ar CFLAGS=-g -DHAVE_LIBPNG -DHAVE_LIBJPEG -DHAVE_LIBFREETYPE LIBS=-lgd -lpng -lz -ljpeg -lfreetype -lm INCLUDEDIRS=-I. -I/usr/local/include/freetype2 LIBDIRS= INSTALL_LIB=/usr/local/lib INSTALL_INCLUDE=/usr/local/include INSTALL_BIN=/usr/local/bin
Puis tapez:
su make install
Il ne s'agit pas d'une erreur de ma part, il faut bien taper directement make install, c'est comme ça !
Si vous obtenez une erreur du type : unresolved symbol (sur gdImageCreateFromPng par exemple) :
Pour les notions de base concernant gd, reportez vous à l'[libgd.php3 article précédent], celui-ci constitue une suite.
Dans cet exemple nous allons recréer l'image simple du premier exercice du premier article mais ajouterons dans la croix la mention santé écrite en Comics, par exemple, et ce, en jaune.
Il faut :
La declaration de la fonction permettant d'écrire du texte en utilisant FreeType est la suivante :
char *gdImageStringFT(gdImagePtr im, int *brect, int color, char *fontname, double ptsize, double angle, int x, int y, char *chaine)
où :
Le code :
/* * Fichier expl_gd2_1.c * * Pour les explications de base, * se reporter à l'article sur gd. */ #include <stdlib.h> #include <gd.h> // Deux macros qui simplifient la vie #define brect_largeur (brect[4]-brect[0]) #define brect_hauteur (brect[1]-brect[5]) int main(void) { gdImagePtr image; FILE *image_png; char *err; int rouge, blanc, jaune, noir; char *chaine = "santé"; // La chaîne à écrire char *font = "/usr/share/ttf/comic.ttf"; // La police double taille = 20; // La taille de la police int brect[8]; // Les coordonnées du rectangle // entourant le texte entier. /* brect[0] X bas gauche * brect[1] Y bas gauche * brect[2] X bas droit * brect[3] Y bas droit * brect[4] X haut droit * brect[5] Y haut droit * brect[6] X haut gauche * brect[7] Y haut gauche */ image = gdImageCreate(100, 100); blanc = gdImageColorAllocate(image, 255, 255, 255); rouge = gdImageColorAllocate(image, 255, 0, 0); jaune = gdImageColorAllocate(image, 255, 255, 0); noir = gdImageColorAllocate(image, 0, 0, 0); gdImageFilledRectangle(image, 20, 40, 80, 60, rouge); gdImageFilledRectangle(image, 40, 20, 60, 80, rouge); /* Les nouveautés commencent ici */ /* On a droit à 60x20 pour placer notre chaîne * soit brect[4]-brect[0]<60 ET brect[1]-brect[5]<20 * --> Pour récupérer brect sans écrire * le texte, on place im à NULL * Si on a un dépassement on réduit la * taille de la police et on recommence */ do { err = gdImageStringFT (NULL, brect, jaune, font, taille--, 0, 0, 0, chaine); if (err) fprintf(stderr, "%s\n", err); fprintf (stderr, "Essai taille : %.0f\n", taille+1); fprintf (stderr, "* bas gauche ( %d, %d ), haut droite ( %d, %d )\n", brect[0], brect[1], brect[4], brect[5]); fprintf (stderr, "* largeur x hauteur : %dx%d\n", brect_largeur, brect_hauteur); } while ( ( brect_hauteur >= 20 ) || ( brect_largeur >= 60 ) ); /* A décommenter pour voir le brect gdImageRectangle (image, 50-brect_largeur/2, 50-brect_hauteur/2, 50+brect_largeur/2, 50+brect_hauteur/2, noir); */ /* Une fois ici on a la bonne taille moins un. * Le milieu de l'image la moitié de la * largeur nous donne le x gauche. * Le milieu de l'image + la moitié de * la hauteur nous donne le y bas. * On retracnche la moitié des brect[0] et brect[1] * car on a vu qu'il ne valaient pas * nécessairement 0 d'où un décalage */ err = gdImageStringFT (image, brect, // mettre -jaune pour // supprimer l'anti-aliasing jaune, font, ++taille, 0, 50-(brect_largeur-brect[0])/2, 50+(brect_hauteur-brect[1])/2, chaine); if (err) fprintf(stderr, "%s\n", err); /* Les nouveautés s'arrêtent ici */ image_png = fopen("gd2_expl1.png", "w"); gdImagePng(image, image_png); fclose(image_png); gdImageDestroy(image); exit (0); }
On compile en tapant
gcc -o expl_gd2_1 expl_gd2_1.c -lgd -ljpeg -lpng -lfreetype
Après exécution par ./expl_gd2_1, vous obtenez dans le répertoire courant une image gd2_expl1.png, qui sera une des 4 présentées ci-dessous selon les modifications que vous aurez apportées au code :
Image normale Sans anti-aliasing
(-jaune)Avec dessin
du brectAvec brect
Sans anti-aliasing
Remarque : Dans une application réelle, une fois connue la bonne taille de police, vous enleveriez la boucle permettant de la trouver, vous ne traceriez pas le brect, etc ... Je l'ai fait ici dans un but pédagogique.
Nous allons maintenant écrire, selon un angle. Pas de gros changements ... On en profitera toutefois au passage pour faire connaissance avec le type gdPoint, utilisé pour tracer des polygones de façon aisée. Il nous servira pour tracer le brect de ce texte "en pente", grâce à la fonction gdImagePolygon.
On note qu'un type gdPoint a deux champs, x et y. C'est pas plus compliqué que ça !
Le code :
/* * Fichier expl_gd2_2.c * * Pour les explications de base, * se reporter à l'article sur gd. */ #include <stdlib.h> #include <stdio.h> #include <gd.h> #include <math.h> // Une macro pour transformer des degrés en radians // NB: M_PI est définie dans math.h #define en_radians(ndeg) (M_PI*(ndeg)/180) // Deux macros qui simplifient la vie #define brect_largeur (brect[4]-brect[0]) #define brect_hauteur (brect[1]-brect[5]) int main(void) { gdImagePtr image; FILE *image_png; char *err; int rouge, blanc, jaune, noir; char *chaine = "santé"; // La chaîne à écrire char *font = "/home/xavier/Docs/contribs_lea/c4/comic.ttf"; double taille = 20; // La taille de la police int brect[8]; // Les coordonnées du rectangle // entourant le texte entier. gdPoint brect_points[4]; // Le tableau de points // pour tracer le polygone image = gdImageCreate(100, 100); blanc = gdImageColorAllocate(image, 255, 255, 255); rouge = gdImageColorAllocate(image, 255, 0, 0); jaune = gdImageColorAllocate(image, 255, 255, 0); noir = gdImageColorAllocate(image, 0, 0, 0); gdImageFilledRectangle(image, 20, 40, 80, 60, rouge); gdImageFilledRectangle(image, 40, 20, 60, 80, rouge); err = gdImageStringFT (NULL, brect, jaune, font, taille, en_radians(45), 0, 0, chaine); /* on stocke les points dans le tableau de gdPoints */ brect_points[0].x = brect[0]+50-(brect_largeur-brect[0])/2; brect_points[0].y = brect[1]+50+(brect_hauteur-brect[1])/2; brect_points[1].x = brect[2]+50-(brect_largeur-brect[0])/2; brect_points[1].y = brect[3]+50+(brect_hauteur-brect[1])/2; brect_points[2].x = brect[4]+50-(brect_largeur-brect[0])/2; brect_points[2].y = brect[5]+50+(brect_hauteur-brect[1])/2; brect_points[3].x = brect[6]+50-(brect_largeur-brect[0])/2; brect_points[3].y = brect[7]+50+(brect_hauteur-brect[1])/2; /* On trace le polygone */ gdImagePolygon (image, brect_points, 4, noir); /* On ajoute la chaîne de caractères comme avant, mais avec un angle */ err = gdImageStringFT (image, brect, jaune, font, taille, en_radians(45), 50-(brect_largeur-brect[0])/2, 50+(brect_hauteur-brect[1])/2, chaine); if (err) fprintf(stderr, "%s\n", err); image_png = fopen("gd2_expl2.png", "w"); gdImagePng(image, image_png); fclose(image_png); gdImageDestroy(image); exit (0); }
On compile en tapant
gcc -o expl_gd2_2 expl_gd2_2.c -lgd -ljpeg -lpng -lfreetype
Après exécution par ./expl_gd2_2, vous obtenez dans le répertoire courant une image gd2_expl2.png.
Ben oui !!! Vous devez bien vous le demander ! Alors voici ce que dit (en résumé) la section "what's new ?" de la page officielle pour la version 2.0.1 par rapport à la 1.8.3 du précédent article :
Plus des améliorations et corrections que je vous conseille de lire directement sur la page, http://www.boutell.com/gd/
Notez que ce lien vous emmène pour l'instant sur la page de la version stable, qui, à l'heure où ces lignes sont écrites, est encore la 1.8.4. Il y a toutefois un (gros) lien vers la page des versions 2.0.x.
/* * Fichier expl_gd2_3.c * * Pour les explications de base, * se reporter à l'article sur gd. */ #include <stdlib.h> #include <gd.h> int main(void) { FILE *image_png; gdImagePtr image, image_d_avant; int orange, bleu; // On crée une image TrueColor image = gdImageCreateTrueColor(100, 100); // On alloue une couleur orange = gdTrueColor (255, 128, 0); // On trace un rectangleorange gdImageFilledRectangle(image, 0, 0, 100, 100, orange); // On ouvre l'image du premier exercice // et on en crée une image image_png = fopen("expl1.png", "r"); image_d_avant = gdImageCreateFromPng (image_png); fclose (image_png); // on copie avec remise à l'échelle de 100x100 pixels // en partant de (0,0) de l'ancienne image // on place le résultat de taille 90x90 à // (5,5) dans la nouvelle gdImageCopyResampled(image, image_d_avant, 5, 5, 0, 0, 90, 90, 100, 100); // on détruit l'ancienne image en mémoire. gdImageDestroy (image_d_avant); // On alloue une couleur bleue semi transparente bleu = gdTrueColorAlpha(0, 0, 255, gdAlphaTransparent / 2); // on se met en mode écrasement // La où on dessinera il y aura // du bleu semi-transparent, c'est tout gdImageAlphaBlending(image, 0); // ontrca eun rectangle gdImageFilledRectangle(image, 10, 10, 90, 30, bleu); // On se met en mode "mélange" // Ce qu'on dessine, se mélange avec // ce qu'il y a dessous // 50% de bleu et 50% du dessous gdImageAlphaBlending(image, 1); gdImageFilledRectangle(image, 40, 10, 90, 90, bleu); image_png = fopen("gd2_expl3.png", "w"); gdImagePng(image, image_png); fclose(image_png); gdImageDestroy(image); exit (0); }
On compile en tapant
gcc -o expl_gd2_3 expl_gd2_3.c -lgd -ljpeg -lpng -lfreetype
On obtient après exécution, dans gimp :
Notez :
C'est tout pour cette fois !
N'hésitez pas à envoyer vos commentaires par mail en cliquant sur mon nom en haut de la page.
Retrouvez prochainement l'article remis en forme, les sources, archives et binaires sur mon site perso..., http://perso.club-internet.fr/xgarreau.
Vous pouvez également me contacter dans le forum Développement de Léa, je le regarde (très) souvent.
A bientôt.
Copyright © 16/06/2001, Xavier GARREAU
![]() ![]() ![]() ![]() |
Ce document est publié sous licence Creative Commons Attribution, Partage à l'identique, Contexte non commercial 2.0 : http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ |
Voir aussi, l'introduction à gd