Polices freetype et GD 2
Polices Freetype et gd-2.0
Introduction
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.
Préparatifs
Compilation et installation de freetype-2
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".
Compilation et installation de gd
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) :
- Vérifiez que vous avez supprimé les anciennes librairies libgd.so*, sinon faites-le.
- lancez ldconfig.
- Vérifiez que /usr/local/lib est dans votre fichier /etc/ld.so.conf sur une ligne seule
- Vérifiez que vous avez bien installé freetype-2 par défaut. Sinon, trouvez le répertoire contenant un sous-répertoire freetype et mettez le en lieu et place de /usr/local/include/freetype2 dans la ligne INCLUDEDIRS du Makefile.
Utilisation
Pour les notions de base concernant gd, reportez vous à l'[libgd.php3 article précédent], celui-ci constitue une suite.
Exemple1
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 :
- Aller chercher la police. Si vous avez un Windows d'installé, allez les récupérer dans le répertoire win*\Fonts.
par exemple :
mkdir /usr/share/ttf
cp /mnt/NTC/winnt/Fonts/comic.ttf /usr/share/ttf/ - Créer la croix comme la dernière fois
- Créer le texte
- Finir l'image comme la dernière fois
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ù :
- im est un pointeur vers l'image dans laquelle on "écrit".
- brect est un pointeur vers un tableau dans lequel on range les coordonnées du plus petit rectangle contenant le texte
- color est la coueleur utilisée pour le texte. Notons que si on utilise -fg, la couleur est la même mais celà désactive l'anti-aliasing (l'anti-crénelage pour les francophones)
- fontname est un pointeur vers le chemin de la police
- ptsize est la taille désirée du texte
- angle est l'angle du texte par rapport à l'horizontale
- x et y sont les coordonées de placement du texte
- chaine est un pointeur vers le texte à écrire
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.
Exemple2 : Selon un angle ?
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.
Quoi de neuf dans gd-2 ?
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 :
- Support Freetype2. (1.8.4)
- Recherche des polices dans les répertoires pointés par les variables d'environement DEFAULT_FONTPATH et GDFONTPATH. (1.8.4)
- Support des images truecolor (2.0)
- Support du canal alpha (pour la transparence) (2.0)
- Gestion de l'épaisseur de tracé des lignes, ça fera plaisir à des gens dans le forum de léa ;-) (2.0)
- Suppression de l'utilisation de Freetype1.x en faveur de Freetype2.x, les anciennes fonctions ne font qu'appeler les nouvelles. (2.0)
- Correction et améliorations pour la version 2.0.1, y compris un meilleur support des caractères japonais et mise à jour de la doc.
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.
Exemple3 : Transparence
/* * 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 :
- en haut à gauche qu'on voit l'arrière plan de Gimp (mode écrasement, il n'y a plus de trace de l'image du dessous)
- à droite le bleu se mélange à l'image du dessous
- en haut à droite 50% de bleu mélangé à 50% de bleu, ça fait ??? 100% de bleu !!!
- La fonction gdImageCopyResampled marche bien mieux que l'ancienne gdImageCopyResized !
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.
Autres ressources
Voir aussi, l'introduction à gd
@ Retour à la rubrique Développement
Copyright
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/ |