Monday, February 20, 2006

Le traitement d'images PNG en C

J'ai découvert la semaine dernière un fichier qui trainait sur mon disque dur : falsecolor.c, qui datait de l'année dernière, ou peut-être même d'avant. Il s'agit d'un fichier altérant les couleurs d'un fichier PNG pour les rendre en trois (ou quatre) couleurs.

Et c'est ainsi que j'ai découvert qu'il est possible, en incluant le fichier png.h, de traiter des images PNG en C! Ça ne m'étonne pas, évidemment, mais la facilité avec laquelle tout cela se faisait est assez incroyable!

Premièrement, il faut inclure le fichier png.h :

#include <png.h>

Il faut évidemment que le paquet libpng soit installé sur votre système.

Ensuite, il faut savoir qu'un fichier PNG est un fichier binaire débutant par une signature constituée de 8 octets, en hexadécimal (source : Wikipedia) :

  1. 89 : Le bit de valeur la plus haute (le bit de gauche) est à 1, pour détecter les systèmes de transmission ne supportant pas les données 8 bits, et aussi pour s'assurer que le fichier n'est pas un fichier texte.
  2. 50 : Caractère 'P'.
  3. 4E : Caractère 'N'.
  4. 47 : Caractère 'G' (les numéros 2, 3 et 4 constituent en fait le mot "PNG", permettant au lecteur qui lit le fichier PNG dans un éditeur de texte d'identifier le fichier PNG comme une image PNG.
  5. 0D : Carriage Return (Retour chariot).
  6. 0A : Line Feed (Changement de ligne). Les numéro 5 et 6 (CRLF) permettent d'identifier les fins de lignes DOS
  7. 1A : un octet permettant d'arrêter l'affichage du fichier sous DOS.
  8. 0A : Line Feed (Changement de ligne) permettant de détecter la fin de ligne sous UNIX.
On comprendra que les numéros 2,3,4 vont ensemble, ainsi que les numéros 5 et 6.

Sachant cela, on peut ouvrir le fichier PNG en tant que fichier binaire :

FILE *fImagePNG;
fImagePNG=fopen("image.png","rb");

Pour ensuite lire la signature :

char Signature[8];

fread(Signature,sizeof(char),8,fImagePNG);

La fonction png_check_sig() (qui retourne 1 ou 0) permet de tester si la signature est valide.

Je n'entrerai pas dans les détails de la manipulation d'image, or, pour continuer, il faut créer une structure de lecture de l'image PNG ainsi qu'une structure d'informations sur l'image, et ensuite on peut lire l'information sur l'image (hauteur, largeur, profondeur de bits, etc.), avec la fonction png_get_IHDR().

Puis, avec la fonction malloc(), on allouée autant de mémoire nécessaire pour stocker l'image PNG, et l'on fait pointer un tableau d'octets dessus, et avec la fonction png_read_image() (puis png_read_end() pour lire la fin du fichier PNG), on copie l'information de l'image dans la mémoire allouée, puis on détruit la structure de lecture (dont on a plus besoin car l'image a été copiée en mémoire).

On peut ensuite traiter l'image, et les couleurs de chaque pixel avec des jeux de pointeurs.

Une fois que c'est fait, on ferme le fichier PNG qui a été ouvert en lecture :

fclose(fImagePNG);

Puis on le rouvre en écriture :

fImagePNG=fopen("image.png","wb");

On se définit ensuite une structure d'écriture dans le fichier, puis on écrit la structure PNG (la structure d'écriture basée sur l'image stockée en mémoire) dans le fichier avec la fonction png_write_image() (puis png_write_end() pour écrire la fin du fichier PNG). On détruit ensuite la structure d'écriture (on en a plus besoin car l'image a été écrite dans le fichier).

Et voilà!

Il ne faut pas oublier de fermer le fichier ouvert en écriture :

fclose(fImagePNG);

Et c'est tout! On a pu traiter une image PNG! Évidemment, le nom du fichier image PNG dans lequel on écrit peut être différent de celui dans lequel on lit (et ça peut être préférable si on modifie une image, ce qui est habituellement le cas lorsqu'on fait appel à une structure d'écriture PNG).

J'étudierai le code plus en détails et j'essaierai de faire mes propres petits programmes C qui manipulent des images PNG (en me basant sur falsecolor.c).

Note : le fichier falsecolor.c a été écrit par Michael Still (http://www.stillhq.com/, mikal@stillhq.com), et tout le crédit du code lui revient. Si vous désirez voir son code, il est disponible sur son site Web/blog, donc l'adresse a été donnée plus haut (entre les paranthèses).

Sur ce, je vous dis à la prochaine!

-- Guimauve2