Automatiser son site avec m4 et make
Introduction
Nous allons voir comment automatiser un site « côté auteur », à l'aide d'un langage de macro et d'un outil de compilation sélective. Le choix du langage de macro utilisé n'a pas grande importance: il doit simplement répondre à vos besoins. Nous avons choisi GNU m4 car c'est un langage de macro répandu sur les machines de type Unix (GNU/Linux, FreeBSD...), mais nous aurions pu également utiliser cpp (le préprocesseur du compilateur C), ou même un langage de script plus avancé comme PHP, Perl...Comme outil de compilation sélective, nous utiliserons GNU make (pour les raisons évoquées précédemment). Il s'agit d'un outil permettant de ne regénérer que les fichiers modifiés. C'est à dire que si vous avez un site comprenant plusieurs milliers de pages, et que vous en modifiez deux, make permettra de ne regénérer que ces deux pages.
Note: pour ce qui suit, vous aurez besoin d'un terminal (ou console), de savoir vous en servir un minimum, et de connaître les commandes de base. Les commandes sont indiquées pour les systèmes de type Unix.
Introduction à GNU make
GNU make est généralement utilisé pour la compilation de programmes, mais n'est pas limité à cet usage. Une documentation complète peut être trouvée sur le site du projet GNU, mais nous tenterons d'introduire ici les notions nécessaires.Cibles
Make fonctionne sur un concept très simple de cibles et de dépendances. Dans un fichier nommé Makefile, il faut écrire la définition des cibles à construire, indiquer de quel(s) fichier(s) elles dépendent, et indiquer les commandes à effectuer pour les construire.
Par exemple,
macible: echo "toto"Indique une cible "macible", et indique que pour construire "macible", il faut effectuer la commande
echo "toto". Les commandes
sont indiquées à la suite, une par ligne, et précédées d'une tabulation.
Pour exécuter ce fichier, tapez "make macible", ou simplement "make",
puisqu'il n'existe qu'une seule cible.
macible: autre_cible echo "Terminé" autre_cible: echo "Je suis une autre cible"Indique alors une cible "macible", qui dépend de la cible appelée "autre_cible". C'est à dire que pour construire "macible", il faut d'abord construire "autre_cible". Si vous tapez "make macible", vous verrez d'abord s'afficher "Je suis une autre cible", puis "Terminé". Jusque là, rien de bien passionnant. Là où les choses deviennent plus intéressantes, c'est que vous pouvez dire à make l'équivalent de "si le fichier de destination est plus récent que le fichier source, pas besoin de construire la cible". Par exemple, en nous rapprochant un peu de notre sujet:
index.html: index.source cp index.source index.htmlSignifie que si le fichier index.html est plus ancien que le fichier index.source, alors on copie index.source dans index.html. Ainsi, si les pages de votre site web sont stockées dans des fichiers ".src", et que vous modifiez, disons, toto.src, alors seule la cible "toto.html" aura besoin d'être reconstruite.
Dernier point sur les cibles, nous pouvons utiliser une seule cible pour regrouper, par exemple, toutes les cibles se terminant par ".html", afin de dire qu'elles se construisent toutes de la même manière. Dans ce cas, on utilise la variable pré-définie $* qui représente le nom de la cible (sans le .html), et $@ qui représente le nom de la cible avec le .html. Par exemple:
macible: toto.html titi.html echo "Terminé" %.html: echo $*Indique que pour chaque cible (donc toto.html et titi.html) se construisent suivant cette règle.
Variables
Make permet également de définir des variables, pratiques pour stocker des valeurs suceptibles de changer. On définit les variables en début de fichier, comme ceci:A= toto.html B= toto.src toto2.src LONG= 1Pour utiliser des variables qui ont été définies (c'est à dire remplacer le nom de la variable par sa valeur), on précède le nom de la variable d'un $ et, si le nom de la variable comprend plus d'un caractère, on le met entre parenthèses:
cible: echo $A echo $(LONG)
Fonctions
Nous aurons également besoin de quelques fonctions utiles de make. Une fonction permet d'insérer dans un makefile le résultat d'un traitement. Un appel de fonction ressemble à cela:$(fonction arguments)Make dispose d'un certain nombre de fonctions qui sont décrites en détail dans le manuel, et nous aurons besoin de deux d'entre elles. La première, $(wilcard motif), permet d'insérer une liste de fichiers correspondant au motif donné.
HTML= $(wildcard *.html)Stockera la liste des fichiers se terminant par ".html" dans la variable HTML.
La deuxième fonction dont nous aurons besoin est la fonction $(subst texte, remplacement, source), qui remplace le "texte" par "remplacement" dans la source donnée. Par exemple:
SRC= $(wildcard *.src) HTML= $(subst .src,.html,$(SRC))Dans cet exemple, on stocke la liste des fichiers se terminant par ".src" dans la variable SRC, puis on remplace tous les ".src" de cette liste par des ".html", et on stocke le résultat dans la variable HTML.
Désormais, nous en savons assez sur make pour produire un Makefile qui correspond à nos besoins. Il ne nous manque plus que les commandes nécessaires à la construction des fichiers (dans nos exemples, nous avons utilisé echo, qui ne fait qu'afficher des choses à l'écran). Il est donc temps de se pencher sur le langage de macros.
Introduction à GNU m4
m4 est un langage de macro, c'est à dire que son objectif, très basique, est de copier en sortie le texte qu'il reçoit en entrée, en remplaçant au passage les macros qu'il rencontre. Une macro est une définition de remplacement, qui peut être pré-définie, ou créée par l'utilisateur. m4 dispose également de fonctions permettant d'include des fichiers, exécuter des commandes Unix, effectuer des calculs, modifier du texte, etc.Vous pourrez trouver le manuel de la version GNU de m4 sur leur site web.
Macros simples
Prenons un exemple simple et analysons son fonctionnement:define(`BONJOUR', `Bonjour tout le monde') Robert se leva, et dit « BONJOUR » !Cet exemple commence par définir une macro nomée BONJOUR, qui se développera en "Bonjour tout le monde". Pour faire facilement la distinction entre ce qui est une macro et le reste, nous nommerons nos macros en majuscule, mais ce n'est pas obligatoire. Remarquons au passage que, en m4, les chaines de caractères doivent être placées entre le caractère (apostrophe gauche) et le caractère (apostrophe droite).
Si vous copiez cet exemple dans un fichier (par exemple, test.m4), et que vous le
lançez en tapant m4 test.m4, vous obtiendrez le résultat suivant:
Robert se leva, et dit « Bonjour tout le monde » !Que s'est-il passé ? Tout d'abord, m4 a lu la première ligne, et effectué la définition de macro. Ensuite, il a envoyé ce qu'il restait de cette ligne en sortie (c'est à dire un caractère de retour à la ligne). Puis, il a lu la ligne suivante, remplacé BONJOUR par "Bonjour tout le monde", et envoyé la ligne sur la sortie.
Notons que nous ne voulions probablement pas afficher le premier retour à la ligne. Pour éviter que m4 affiche les caractères d'une ligne, il faut rajouter "dnl". Par exemple:
define(`toto', `développement de `toto'')dnl Ceci est le toto. dnl Qu'en pensez vous ?Si vous exécutez ceci, vous obtiendrez:
Ceci est le développement de toto.Car, conformément à nos souhaits, tous les caractères suivant "dnl" ont été ommis. Remarquez également le fait que dans la définition de macro, le deuxième toto a été mis entre guillemets simples. Si nous avions simplement mis "développement de toto", puisque toto était une macro, il aurait été développé en "développement de développement de toto", mais comme toto était une macro, il aurait été développé en "développement de développement de développement...". En effet, le texte provenant d'un développement de macro est de nouveau analysé pour effectuer d'autres développements éventuels.
Macros avec arguments
Vous pouvez définir des macros avec des arguments, et le nième argument est représenté par la macro $n. Par exemple:define(`SALUT', `Bien le bonjour, $1, mon ami')dnl SALUT(Robert) SALUT(Jacques) define(`INVERSE', `$2, $1')dnl INVERSE(Gérard, Philippe)Et vous obtiendrez le résultat suivant
Bien le bonjour, Robert, mon ami Bien le bonjour, Jacques, mon ami Philippe, Gérard
Développements conditionnels
Un langage de macro ne serait pas très utile s'il ne permettait pas des branchements conditionnels, c'est à dire s'il ne permettait pas de dire "si cette condition est remplie, écris ceci, sinon écris cela". Nous ne verrons ici qu'un seul type de développement conditionnel, qui se base sur le fait qu'une macro soit définie ou non:ifdef(nom, texte) ifdef(nom, texte, sinon)La première version de ifdef se développe en "texte" si la macro "nom" est définie. La deuxième version se comporte de la même manière, mais de plus se développe en "sinon" si la macro n'est pas définie. Voyons un exemple:
define(`MA_MACRO')dnl ifdef(`MA_MACRO', `Ma macro est définie', `Ma macro n'est pas définie') undefine(`MA_MACRO')dnl ifdef(`MA_MACRO', `Ma macro est définie', `Ma macro n'est pas définie')Si vous exécutez ces instructions, vous obtiendrez d'abord "Ma macro est définie", puis "Ma macro n'est pas définie". Vous pouvez remarquer au passage l'utilisation de "define" sans deuxième argument, qui se contente de définir la macro, sans lui donner de valeur significative, et l'utilisation de "undefine", qui supprime une macro précédemment définie.
Inclure des fichiers
Autre fonction utile de m4: l'inclusion de fichiers. m4 peut prendre le contenu d'un fichier, le traiter et le copier sur la sortie. Cela va nous permettre d'accoler bout à bout plusieurs fichiers constituant les différents éléments de nos pages web.m4 dispose de deux fonctions d'inclusion:
include(nom_du_fichier) sinclude(nom_du_fichier)La première ("include") produit un message d'erreur si le fichier qu'on lui demande ne peut être trouvé. La deuxième ne produit pas de message d'erreur.
Première ébauche de site
Nous en savons assez pour créer un site raisonnablement automatisé à l'aide
de m4 et de make. Nous allons ébaucher une première version, simpliste, puis
voir quels raffinements nous pouvons apporter.
Structure du site
Nous allons créer un site composé de plusieurs rubriques et sous rubriques.
Chaque page comportera un en-tête standardisé, un menu à gauche, le
contenu de la page à droite, et une phrase de copyright en bas. Le menu
s'adaptera à chaque rubrique: nous afficherons le contenu détaillé de la
rubrique à laquelle appartient la page, et simplement le titre des autres
rubriques.
Nous aurons besoin d'un certain nombre de fichiers séparés, que nous incluerons dans chaque page. Nous avons choisi de donner à ces fichiers l'extension .i (pour include), nous aurons donc en particulier menu.i, headers.i et footers.i, pour le menu, l'en-tête et le pied-de-page. Le contenu spécifique de chaque page sera placé dans des fichiers .src (pour source), et le nom du fichier sera le titre de la page (celui utilisé dans le champ <title> de la page). Nous aurons donc par exemple index.src, mon_cv.src, jardinage.src et jardinage_bonsais.src, contenant le texte de la page de garde, de mon CV, de la rubrique jardinage et de la sous rubrique de jardinage consacrée aux bonsaïs. Nous aurons enfin besoin d'une feuille de style (CSS) commune à toutes les pages, d'un modèle de page appelé modele.m4, et d'un Makefile.
Makefile
SRC= $(wildcard *.src) OBJ= $(subst .src,.html,$(SRC)) INCLUDES= $(wildcard *.i) modele.m4 all: $(OBJ) @echo "Compilation terminée" %.html: $(INCLUDES) %.src m4 -DTITLE=$* -DSRC="$*.src" modele.m4 > $@ clean: rm -f $(OBJ)Ce premier Makefile est assez simple.Voyons tout d'abord les variables utilisées:
Tout d'abord, nous stockons dans SRC la liste des fichiers source, c'est à dire les fichiers à partir desquels nous pouvons construire les pages. Puis, nous construisons la liste des fichiers de destination, c'est à dire les fichiers qui sont construits à partir des fichiers source. Ici, il s'agit des mêmes fichiers, mais se terminant par .html. Enfin, nous stockons dans INCLUDES la liste des fichiers d'inclusion (*.i) et le fichier de modèle. En effet, toures les pages du site dépendent de ces fichiers. Si l'un d'entre eux change, alors toutes les pages doivent être reconstruites.
Une fois les variables définies, voyons la cible principale (appelée "all" par convention). Cette cible représente l'ensemble du site, elle dépend donc de tous les objets devant être construits: si l'un d'entre eux n'existe pas ou n'est pas à jour, il faut le recréer. La cible all n'effectue pas de traitement particulier (pour l'instant), elle ne fait qu'afficher "Compilation terminée".
La cible suivante décrit la manière dont doit être construite toute cible se terminant par .html. Chaque cible html dépend des fichiers d'inclusion, et du fichier source qui porte le m≖me nom qu'elle (c'est à dire que index.html dépend de tous les .i, de modele.m4, et de index.src). La règle de construction est simple: nous appelons m4 en lui donnant le fichier modele.m4 comme "programme", et nous stockons le résultat dans $@ (Rappel: $@ est une variable pré-définie qui contient le nom de la cible, par exemple, nous stockons le résultat dans index.html). De plus, nous donnons d'autres arguments à m4. Ces arguments sont des définitions de macro, faites par la ligne de commande (au lieu d'être faites dans modele.m4). -DTITLE=$* définit la macro TITLE en lui donnant la valeur de $* (Rappel: $* est une variable contenant le nom de la cible sans l'extension, par exemple "index"). -DSRC="$*.src" définit une macro SRC et lui donne la valeur "$*.src", c'est à dire $* suivi de ".src". Dans notre exemple, index.src. Nous verrons plus loin l'usage de ces deux macros.
Enfin, la dernière cible est facultative, elle sert à "faire le ménage", en effaçant tous les fichiers de destination.
modele.m4
include(headers.i) include(SRC) include(footers.i)dnlPour l'instant, modele.m4 est un... modèle de simplicité. Il ne fait qu'inclure le fichier headers.i, puis le fichier source, puis le fichier footers.i. C'est ici que nous voyons l'usage de la macro informatique_documentation_automatiser_m4.src: elle sert à donner le nom du fichier source que nous sommes en train de construire. Quand make voudra construire index.html, il appellera m4 avec la macro initialisée à "index.src", ce qui incluera le bon fichier source.
headers.i
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Mon site : TITLE</title> <link title="Defaut" href="style.css" rel="stylesheet" type="text/css"> </head> <body>Ici, il ne s'agit presque que de code HTML, la seule ligne intéressante est celle comprenant la macro TITLE, qui est définie, comme nous l'avons vu, lors de l'appel de m4 par make. C'est de cette manière que nous choisissons le titre de chaque page.
footers.i
</td></tr></table> <p><hr><center><small> Ce site a été conçu avec GNU Emacs, m4 et make. </small></center> </body></html>Aucun commentaire, il s'agit simplement du code HTML qui servira à terminer nos pages.
index.src
define(`GENERAL')dnl include(menu.i)dnl <h1>Page de Robert</h1> ...Nous sommes donc dans la partie qui sera spécifique à chaque page. Nous définissions tout d'abord une macro GENERAL qui sera utilisée dans le menu. En effet, à chaque rubrique correspond une macro. Si la macro GENERAL est définie, alors il faudra afficher le menu correspondant à la rubrique générale. Si la macro JARDINAGE est définie, il faudra afficher le menu correspondant à la rubrique jardinage. Ensuite, on include le fichier menu.i, et on tape le texte de la page.
Note: une fois le système d'automatisation mis en place, vous n'aurez plus à modifier que des fichiers de ce type. Pour ajouter une page à votre site, il suffira de créer un fichier mapage.src comprenant une définition de macro, un include de menu.i, et votre texte.
menu.i
define(`SUBMENU', `<tr><td><table class="submenu" width="100%">$1</table></td></tr>') define(`R', `<tr><td>')dnl define(`ER', `</td></tr>')dnl <table width="100%" class="main"> <tr><td width="15%" valign=top class=first> <table class="menu" width="100%"> ifdef(`GENERAL', SUBMENU(sinclude(general.i)), SUBMENU(R `<tr><td><a href="index.html">Général</a></td></tr>' ER)) ifdef(`JARDINAGE', SUBMENU(sinclude(jardinage.i)), SUBMENU(R `<tr><td><a href="jardinage.html"> Jardinage</a></td></tr>' ER) ) </table> </td> <td valign=top>Notre menu est consitué de deux tables: une table "A" contenant chacun des sous-menus, et une table par sous-menu. Pour ne pas avoir à répéter le même texte pour chaque sous-menu, nous définissons une macro SUBMENU qui créera une rangeée de A pour chaque sous-menu, le texte spécifique au sous-menu étant passé en paramètre ($1). Les deux macros suivantes nous éviteront simplement de répéter la création d'une rangée et d'une colonne pour chaque titre de menu.
Les deux lignes suivantes sont du html spécifique à l'organisation que nous avons choisi pour notre page. L'ensemble de la page est contenu dans une table d'une seule rangée, dont la première colonne contient le menu, et la deuxième contient le corps de la page.
La ligne suivante crée la table A du menu. Puis, nous incluons un développement conditionnel pour chaque sous menu. Si la macro MA_RUBRIQUE est définie, alors on inclue le menu correspondant à la rubrique MA_RUBRIQUE, sinon on inclue un lien vers la page de la rubrique.
general.i
<tr><td class="title">Général</td></tr> <tr><td> <a href="cv.html">Curriculum Vitæ</a> </td></tr> <tr><td>Clé publique GPG</td></tr> <tr><td>M'écrire</td></tr>Le menu général est un exemple des menus que vous pouvez inclure dans menu.i. Ici, nous avons mis chaque ligne de menu dans une rangée de table, et nous avons défini une classe particulière pour le titre du menu, afin de l'afficher différemment (par une CSS).
Note: nous aurions pu utiliser ici les macros définies dans menu.i, c'est à dire R et ER pour écrire <tr><td> et </td></tr>.
Construire son site
À partir de ce point, vous pouvez commencer à contruire votre site. Par la suite, vous pourrez rajouter tous les raffinements que vous voudrez, sans être obligé de tout modifier. Commencez par réfléchir aux différentes rubriques que vous désirez créer, puis rédigez votre fichier menu.i. Ensuite, rédigez les menus spécifiques à vos rubriques. Vous n'êtes pas obligé de connaître à l'avance les sous menus de chaque rubrique, mais vous pouvez vous contenter de ne mettre que la ligne de titre de chaque menu.Ensuite, créez les fichiers .src correspondant à l'index de chacune de vos rubriques. Quand vous avez fait cela, vous pouvez compiler votre site en tapant "make", pour vérifier que tout se passe bien. Si c'est le cas, libre à vous de rédiger toutes les pages que vous voudrez. N'oubliez pas également de créer une feuille de style adéquate (dans headers.i, nous l'avons appelée style.css).
Apporter quelques améliorations
Le langage de macros m4 est très puissant, et vous permet à lui seul d'effectuer bon nombre d'opérations utiles pour l'automatisation d'un site web. Si nous ajoutons à cela le fait qu'il peut utiliser n'importe quelle commande Unix, les possibilités deviennent illimitées. Nous allons en décrire quelques unes qui nous ont paru utiles, mais la seule limite est votre imagination.Utiliser une commande externe
esyscmd( commande )La fonction esyscmd vous permet d'appeler n'importe quelle commande externe, et copie le texte produit par cette commande à l'endroit où vous l'avez appelée (tout en traitant ce texte pour savoir s'il contient lui même des macros à développer). Par exemple, nous avons voulu ajouter en pied de page la date de compilation de la page. Pour cela, nous rajoutons cette commande dans le fichier footers.i:
Ce fichier a été compilé le esyscmd(`date +%x')(Pour avoir des précisions sur la commande utilisée, vous pouvez consulter la page de manuel de "date").
Formatter le titre automatiquement
Nous avons choisi une méthode un peu brutale pour formatter notre titre. Nous avons vu plus haut que l'information sur le titre de la page est passé par make à m4, sous la forme d'une macro TITLE contenant le nom du fichier traité. Nous avons donc choisi de coder ce nom de fichier pour qu'il contienne les informations que nous désirons afficher. Si nous voulons créer un fichier sur les tulipes dans la rubrique jardinage, nous l'appellerons jardinage_tulipes.src. De même, si nous voulons créer un fichier sur les rateaux dans la rubrique outils, elle-même dans la rubrique jardinage, nous appellerons ce fichier jardinage_outils_rateaux.src.De cette manière, TITLE contient la liste des rubriques et le nom de la page, séparés par des traits de soulignement ("_"). Nous voudrions que la présentation soit un peu plus jolie, nous allons donc nous intéresser à la substitution de texte. Dans cet exemple, nous allons remplacer les traits de soulignement par une espace, deux points, une espace (" : ").
patsubst(texte, expression_rationnelle, remplacement)Cette fonction m4 regarde dans le texte si elle trouve des motifs correspondant à l'expression rationnelle passée en paramètre. Si oui, chaque motif est remplacé par le texte de remplacement donné comme troisième paramètre. Les expressions rationnelles sont un sujet un peu difficile à aborder si vous n'en avez jamais entendu parler, mais vous pourrez essayer de vous inspirer de nos exemples et de l'abondante documentation sur internet pour vous familiariser avec cet outil très puissant. Voici quelques exemples avec la ligne produite, à chaque fois:
patsubst(`Toto va à l'école', `l'école', `la maison') Toto va à la maison patsubst(`Toto va à l'école avec tito', `\([Tt][oi]\)+', `Paul') Paul va à l'école avec Paul patsubst(`jardinage_outils_rateaux', `_', ` : ') jardinage : outils : rateaux patsubst(`Jardinage Outils Rateaux', `\w+', `\(\&\)') (Jardinage) (Outils) (Rateaux)La première commande dit de remplacer "l'école" par "la maison", à chaque fois que possible. La deuxième dit de remplacer tous les mots composés de T (ou t) suivi de o (ou i) plusieurs fois (comme Toto, TiTo, TotoTo...) par Paul. La troisième dit simplement de remplacer "_" par " : ", et nous en aurons besoin pour notre titre. Enfin, la quatrième montre un exemple un peu plus sophistiqué, dans lequel on remplace tous les mots (\w représente un caractère de mot, et + indique qu'il y en a un ou plus) par une parenthèse ouvrante, le mot trouvé, et une parenthèse fermante. Ici, \& représente le motif qui a correspondu à l'expression rationnelle. S'il y en a plusieurs, on peut utiliser \1, \2... pour représenter ces motifs.
Pour en revenir à nos moutons, nous voulions améliorer un peu le titre. Pour cela, nous pouvons modifier une ligne de header.i:
<title>patsubst(TITLE, `_', ` : ')</title>
Créer un apperçu (thumbnail) d'une image
La commande "convert" peut être utilisée pour appliquer divers traitements à une image. En particulier, il est possible de redimensionner une image, et de changer son format. Il devient donc possible de définir des macro permettant d'effectuer systématiquement le même traîtement sur des images. Ici, nous allons utiliser m4 pour créer des vignettes d'appercu pour vos images. Tout d'abord, effectuons quelques tests:
define(`BASENAME', `patsubst(`$*',`\([^\.]+\)\.\w+', `\1')')dnl
BASENAME(toto.jpg)
define(`THUMBNAIL', `syscmd(convert -scale x$2 -colors 32 $1 BASENAME($1).png)
<img src="BASENAME($1).png" alt="Apperçu de $1">')dnl
THUMBNAIL(toto.jpg, 100)
La première commande définit une macro BASENAME qui effectue une substitution
sur le texte qu'on lui donne en paramètre. Elle sert a remplacer un nom de fichier
suivi d'une extension par le nom sans l'extension. Par exemple, toto.jpg devient
toto. C'est un remplacement simpliste, qui posera problème si le nom de fichier
contient plusieurs points (par exemple, toto.tata.jpg).
La deuxième commande est un peu plus compliquée. Elle définit une macro THUMBNAIL qui se développera par l'exécution de la commande passée en paramètre à syscmd et par le texte accolé. La commande syscmd ne produit aucun texte, contrairement à esyscmd.
La commande convert utilisée a pour effet de redimensionner l'image en fixant sa hauteur et en préservant le rapport hauteur/largeur (par exemple, THUMBNAIL(toto.jpg, 100) redimensionnera toto.jpg pour que l'image ait une hauteur de 100. La largeur sera adaptée pour que l'image ait la même forme), avec le parmètre scale. Ce paramètre est utilisé comme ceci:
convert -scale largeur x hauteur imagesource imagedestinationPar exemple:
convert -scale 200x300 image.jpg image.pngPrend image.jpg, lui donne la taille 200x300, et place le résultat dans image.png. Vous remarquerez que la hauteur est le deuxième paramètre passé à notre macro. Nous avons choisi de fixer la hauteur (et non la largeur) de manière à pouvoir créer une liste d'apperçus qui s'aligneront correctement sur la page, ayant tous la même hauteur, mais vous pouvez bien sûr faire d'autres choix.
Ensuite, nous fixons un nombre de couleurs réduit, avec le paramètre -color, de manière à réduire la taille de l'apperçu, que nous enregistrons au PNG. Puis, la macro produit le code HTML nécessaire pour afficher l'image que nous venons de produire (et qui est un simple fichier placé dans le répertoire courant).
Pour que notre apperçu soit complet, il faudrait qu'en cliquant dessus, nous puissions afficher l'image originale. Nous pouvons le faire en complétant la macro:
define(`THUMBNAIL', `syscmd(convert -scale x$2 -colors 32 $1 BASENAME($1).png) <a href="$1"><img src="BASENAME($1).png" alt="Apperçu de $1" border="0"></a>')dnl
Note: vous voudrez surement améliorer ces macros de manière à pouvoir placer vos images dans un répertoire et vos apperçus dans un autre, par exemple. C'est relativement simple, il suffit de modifier un peu l'expression rationnelle de patsubst et les chemins de fichiers dans le code html et la commande convert. Par exemple:
define(`FILENAME', `patsubst(`$*', `^\(.+\/\)+', `')')dnl define(`BASENAME', `patsubst(FILENAME($*),`\([^\.]+\)\.\w+', `\1')')dnl BASENAME(/var/ww/html/toto.jpg)Vous permet d'obtenir le nom d'un fichier en enlevant les indications de répertoire qui le précèdent. De cette manière, vous pouvez modifier les macros que nous avons définies pour placer tous les apperçus dans le dossier "thumbnails":
define(`FILENAME', `patsubst(`$*', `^\(.+\/\)+', `')')dnl define(`BASENAME', `patsubst(FILENAME($*),`\([^\.]+\)\.\w+', `\1')')dnl define(`THUMBNAIL', `syscmd(convert -scale x$2 -colors 32 $1 thumbnails/BASENAME($1).png) <a href="$1"><img src="thumbnails/BASENAME($1).png" alt="Apperçu de FILENAME($1)"></a>')dnlEnfin, nous concluerons par une remarque sur une petite faiblesse de ce système: si vous changez une image, mais que vous ne modifiez pas le fichier source qui contient la création de l'apperçu, celui-ci ne sera pas regénéré automatiquement. Il faudrait pour cela que make sache que le fichier source dépend de l'image. Nous aurions la possibilité de le faire, mais cela alourdirait trop les choses pour le moment.