Passons la brosse au délégué
Par Jean-Seb le samedi 17 janvier 2009, 09:37 - Coding - Lien permanent
Aujourd'hui, on passe la brosse.
Rassurez-vous, il ne s'agit pas d'un vil fayotage de bas étage.
Le délégué en question est un filtre ImageMagick
Etendre ImageMagick
- ImageMagick présente une pléthore de formats.
- Malgré tout, il arrive que certains formats ne soient pas supportés.
- Vous pouvez aussi avoir envie de voir votre propre format supporté.
- A titre d' exemple, je vous propose le format gbr (Gimp Brush, ce sont les brosses de Gimp).
- La doc du format se trouve dans les sources de Gimp (cherchez le fichier
gbr.txt
).
- gbr est supporté depuis la version 6.4.6-5 de ImageMagick.
- L'arbre portage de Gentoo ne contient pas une version supportant le format gbr.
- Vous pouvez évidemment récupérer une version plus récente, ou vous servir sur le cvs de ImageMagick.
Mise au point
- Je vous présente ici quelques pièges classiques , rencontrés lors du développement de filtres.
Problèmes de conversion
- En C, une erreur redoutable est le problème de conversion signed/unsigned
lors de la copie de données.
- -Wall signale pas mal de choses, mais pas ces problèmes de conversions.
- -Wconversion vous le signalera, et devrait être obligatoire pour arrêter les tractions capillaires lors de la mise au point !
- Cas typique signalé par -Wconversion :
- Débordement des valeurs envoyées dans un buffer de type
char *buffer - En effet, ce buffer est signed (déclaration par défaut du type char), ce qui n'est probablement pas ce que vous voulez.
- Débordement des valeurs envoyées dans un buffer de type
Chargement et sauvegarde de structures
- Les structures sont la plaie du C, quand il s'agit de les charger ou les
décharger.
- Pas d'autres choix que de sauver distinctement chacun des membres.
- Le chargement se fait également membre par membre.
- Ne vous amusez pas à packer vos structures afin d'éviter le padding du compilateur. C'est une très mauvaise idée pour la portabilité, même au sein d'une même architecture.
Problèmes liés au format TGA
- Attention, le format TGA est codé en BGR, et non pas en RGB.
- Exemple d'une conversion avec la source en 24 bits, et la destination en 32 bits (on ajoute juste le channel alpha, bloqué à 255).
for (i=0; i < tga_i->tga_x * tga_i->tga_y * 3; i+=3) {
b_dst[j] = b_src[i+2]; //RGB -> BGR
b_dst[j+1] = b_src[i+1];
b_dst[j+2] = b_src[i];
b_dst[j+3] = 255; //alpha
j+=4;
}
Problèmes liés au format GBR
- Les entiers (type int) de Gimp sont au format Motorola (Big-Endian).
- La conversion vers le format Little-Endian se fera à l'aide de deux fonctions.
- Une fonction pour lire les entiers :
int read_uint32 (unsigned char *p)
{
return p[3] + (p[2]*256) + (p[1]*65536) + (p[0]*16777216);
}
- Une fonction pour écrire les entiers :
void write_uint32 (int i, FILE *fp)
{
unsigned char c[4]={0};
c[0] = (i>>24)&0xff;
c[1] = (i>>16)&0xff;
c[2] = (i>>8)&0xff;
c[3] = i&0xff;
writebuf (c, sizeof(int), fp);
}
- Pour mes conversions, j'ai été obligé de faire un flip horizontal
et vertical de l'image, avant de l'enregistrer au format
gbr
- Il suffit de reprendre le contenu du buffer TGA, et de le recopier en l'inversant, et en tenant compte du fait qu'il est stocké au format BGR (BlueGreenRed).
- Pour info :
//gbr->datas[] est le buffer source
// flipped_pic est le buffer destination (qui contient les données flippées de la brosse)
for (h = 0; h < gbr->height; h++) {
h_beg=h*gbr->width*4;
h_end=(gbr->height*gbr->width*4)-(h*gbr->width*4);
for (w = 0; w < gbr->width*4; w+=4) {
flipped_pic[h_end-1-(w+3)] = gbr->datas[h_beg+(gbr->width*4)-w-4];
flipped_pic[h_end-1-(w+2)] = gbr->datas[h_beg+(gbr->width*4)-w-3];
flipped_pic[h_end-1-(w+1)] = gbr->datas[h_beg+(gbr->width*4)-w-2];
flipped_pic[h_end-1-(w)] = gbr->datas[h_beg+(gbr->width*4)-w-1];
}
}
delegates.xml
Principe
- Le fichier delegates.xml sert à la configuration des
filtres ImageMagick.
- Ces filtres sont appellés des
delegates
dans la terminologie ImageMagick.
- Ces filtres sont appellés des
- Vous pouvez le trouver avec un locate. Pour ma part, il se trouve
ici:
/usr/lib64/ImageMagick-6.3.7/config/delegates.xml
- Dans ce fichier, vous trouverez la description des filtres et leur
paramétrage.
- Plutot que de vous livrer une longue liste de paramètres, je vous invite à lire ce fichier : tout ce qui est important est décrit en commentaires, au début du fichier.
Le delegate le plus simple du monde
- renommez l'extension d'un fichier png en pong
- créez un fichier "pong_convert", rendez le exécutable, et insérez-y ces lignes:
#!/bin/bash if [[ x"$1" != x"" && x"$2" != x"" ]] then cp $1 $2 echo "$1" a été converti en "$2" else echo "Usage: $0 source.pong dest.png" fi
- Ajoutez dans votre fichier fichier delegates.xml la ligne suivante:
<delegate decode="pong" encode="png" command='"/tmp/pong_convert "%i" "%o"'/>
- Vous pouvez maintenant utiliser votre convertisseur
convert source.pong dest.png
Utiliser tout ça ensemble
Mais tout a déja été dit
- Je pense que l'essentiel a été dit.
- Je pourrais bien sûr reprendre les paragraphes précédents, et détailler la méthode pour la conversion des fichiers gbr.
- Mais je ne ferais que répéter ce que vous avez déja lu, sans apporter grand
chose d'intéressant.
- Si vous avez des questions, n'hésitez pas, les commentaires sont là pour ça.
Et les sources ?
- Je ne publie pas mes sources, car:
- la partie TGA est assez ancienne (2002) et mériterait un bon nettoyage.
- Un filtre gbr est disponible dans le cvs de ImageMagick, et ne tardera donc pas à être intégré aux releases.
- Le post des sources dans ce billet est donc sans intêret.
- Si néanmoins, et pour une raison qui m'échappe, vous désirez les sources du convertisseur, demandez les en commentaire et je les posterai.