Polices freetype et GD 2

De Lea Linux
Aller à la navigation Aller à la recherche


Polices Freetype et gd-2.0

Polices Freetype et gd-2.0
Voici le deuxième article concernant gd. Il traite de l'utilisation de Freetype pour inclure du texte dans vos images et des nouveautés apportées à gd par la version 2.

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 brect
Avec 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


Cette page est issue de la documentation 'pré-wiki' de Léa a été convertie avec HTML::WikiConverter. Elle fut créée par Xavier GARREAU le 16/06/2001.

Copyright

Copyright © 16/06/2001, Xavier GARREAU

Creative Commons License
Creative Commons Attribution iconCreative Commons Share Alike iconCreative Commons Noncommercial
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/