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.


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.
  • 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.