Critcl et GD

 

XG - 30 Août 2005


Maintenant que nous avons vu une utilisation basique de critcl dans l'Introduction à Critcl, on va s'intéresser à un exemple plus utile.

On va créer une procédure permettant de générer une image contenant un texte écrit dans une taille donnée, avec une police donnée. Et pour atteindre ce but, on va utiliser la librairie gd (avec le support fontconfig).

Le but ici n'est pas d'apprendre à configurer et compiler gd. On va donc partir du principe que vous avez réussi à le faire et que la librairie gd est installé dans /myprefix/lib et les headers dans le répertoire /myprefix/include. Pour bien faire il faudrait utiliser les librairies situées dans les emplacements standards, afin de rendre tout ça aisément portable mais ça permet ici de voir des options supplémentaires.

On doit commencer par charger le package critcl

 package require critcl
 ...

Ensuite, on doit ajouter des options au linker pour que ce dernier puisse trouver les librairies nécessaires. On utilise pour cela la comme ::critcl::clibraries qui passe au linker les options qui suivent, sans modification.

 ::critcl::clibraries -lgd -lpng -lfreetype -lfontconfig -ljpeg -L/myprefix/lib
 ...

Il faut également signaler au préprocesseur où aller chercher les fichiers d'entête. On utilise à cette fin la commande ::critcl::cheaders.

 ::critcl::cheaders -I/myprefix/include
 ...

Enfin, on utilise la commande ::critcl::ccode pour "injecter" du code en tête du code qui suivra. C'est typiquement ici que l'on ajoutera les #include, #define, typedef et les variables globales nécessaires dans le reste du code.

 ::critcl::ccode {
 #include <stdlib.h>
 #include <stdio.h>
 #include <gd.h>
 }
 ...

On peut ensuite attaquer le code de génération de l'image lui même. On va créer une procédure nommée drawTextToFile qui prendra en argument la taille du texte, la police, le texte à écrire et enfin le nom du fichier généré. J'ai choisi arbitrairement le format png pour l'exemple.

 ::critcl::cproc drawTextToFile {int fontsize char* font char* s char* pngname} int {
	gdImagePtr im;
	FILE *pngout;
	int bgColor;
	int fgColor;
	int brect[8];
	int w, h;
	char *err;
	...

Détaillons un peu.

On déclare ensuite 6 variables intermédiaires pour nos couleurs.

	unsigned long bgR, bgG, bgB, fgR, fgG, fgB;
	bgR = 0xff;
	bgG = 0xff;
	bgB = 0xff;
	fgR = 0;
	fgG = 0;
	fgB = 0;
	...

On signale à gd que l'on va utiliser fontconfig pour rechercher les polices à utiliser.

	gdFTUseFontConfig(1);

On supprime les retours à la ligne en fin de chaîne.

	while (s[strlen(s)-1]=='\n' || s[strlen(s)-1]=='\r') s[strlen(s)-1]='\0';
	...

Enfin on détermine la taille d'image nécessaire pour notre texte.

	err = gdImageStringFT(NULL,&brect[0],0,font,fontsize,0.,0,0,s);
	if (err) {
		return TCL_ERROR;
	}

Les arguments pris par gdImageStringFT sont les suivants:

 0 coin bas gauche, X
 1 coin bas gauche, Y
 2 coin bas droite, X
 3 coin bas droite, Y
 4 coin haut droite, X
 5 coin haut droite, Y
 6 coin haut gauche, X
 7 coin haut gauche, Y

Si cette instruction se passe mal, on renvoit TCL_ERROR à l'interpréteur pour faire savoir qu'il y a eu un problème.

On détermine la largeur et la hauteur nécessaire à notre texte.

	w = brect[2]-brect[6];
	h = brect[3]-brect[7];
	...

On crée l'image, on alloue les couleurs nécessaires puis on dessine le texte, "pour de vrai".

	im = gdImageCreate(w,h);
	bgColor = gdImageColorResolve(im, bgR, bgG, bgB);
	fgColor = gdImageColorResolve(im, fgR, fgG, fgB);

	err = gdImageStringFT(im,&brect[0],fgColor,font,fontsize,0.,-brect[6],-brect[7],s);
	if (err) {
		return TCL_ERROR;
	}
	...

On finit.

	pngout = fopen(pngname, "w");
	gdImagePng(im, pngout);
	fclose(pngout);
	gdImageDestroy(im);
	return TCL_OK;
 }

On sauve ensuite notre travail dans drawText.tcl et on peut d'ores et déjà le tester.

 $ tclkit
 % source critcl.kit
 % source drawText.tcl
 % drawTextToFile 48 Mono:Bold "test" mono.png
 0
 %

Notez que dans tclkit, on peut directement "sourcer" un .kit.

La valeur 0 correspond à TCL_OK, en cas d'erreur drawTextToFile renverrait 1. Obtenir un message plus informatif fera l'objet d'un cours ultérieur.

Votre répertoire de travail contient alors un fichier mono.png du plus bel effet ...


Mon extension drawText

Tout cela fonctionne mais n'est pas vraiment pratique, on va donc générer une extension drawText. Tout a été pensé dans ce sens et ce n'est qu'une formalité ...

Il suffit d'ajouter une ligne en tête du fichier drawText.tcl:

 package provide drawText 1.0

Puis d'invoquer la commande suivante

 $ tclkit critcl.kit -pkg drawText
 Source: drawText.tcl
 Library: drawText.dylib
 Package: /Users/zazou/Devel/Tcl-Tk/critcl/lib/drawText

critcl.kit génère pour vous tout ce qu'il faut dans le répertoire lib/drawText, vous pouvez ensuite copier ce répertoire ou Tcl pourra le trouver (ou modifier la variable auto_path) et vous pouvez utiliser ce package comme n'importe quel autre.

La preuve en image:

 % package require drawText
 1.0
 % drawTextToFile 24 Futura:italic "Bonjour le monde !" futura.png
 0


Voir aussi:


Catégorie Cours