Présentation

Le format GIF (Graphics Interchange Format) date de 1987, et a été enrichi en 1989. Il a été déposé par CompuServe, et le but était de permettre la diffusion d'images compressées sur les réseaux télématiques. Sa particularité est de ne pas altérer les images (contrairement au JPEG), de permettre des animations, et de pouvoir afficher les images progressivement (pratique à l'époque du modem 9,6 k). Il est efficace sur les images de petite taille et les images régulières (logos, cartes, ...).

Il est encore utilisé sur de nombreux sites, malgré certaines poursuites judiciaires (UNISYS est détenteur du brevet). Le format PNG remplace petit à petit le GIF car il est libre d'usage. A la différence du GIF, il peut altérer l'image.

L'objet de cet article est de présenter ce format. Il ne se substitue pas au document de référence de CompuServe, mais le complète.

Structure d'un fichier GIF

Cette structure est définie dans le document de référence, et est simple à comprendre. Pour résumer, il s'agit d'une suite de blocs logiques (image, texte, commentaire, bloc spécifique à une application).

Un bloc logique peut contenir des données qui seront découpées en blocs physiques, chacun ne pouvant contenir que 256 octets au maximum.

Chaque image dispose d'une table de couleur, locale à une image ou globale. Les données qui seront stockées dans le fichier correspondent à la couleur de chaque pixel de l'image, de gauche à droite, et de haut en bas  : les données décompressées correspondent à une liste d'indices dans cette table dont la taille est limitée à 256 entrées.

La particularité du format GIF est qu'il repose sur un algorithme de compression révolutionnaire (du moins lorsqu'il a été inventé) qui n'a pas besoin de transmettre de dictionnaire.

Compression des données

Le programme de compression ou décompression gère localement un dictionnaire qu'il va construire au fur et à mesure du traitement. Les codes compressés auront une taille de MCS à 12 bits, MCS (Minimum Code Size) étant fourni dans le fichier GIF et pouvant varier d'une image à une autre du même fichier  la plus petite valeur possible de MCS sera telle que le nombre d'entrées dans la table des couleurs soit inférieur à 2^MCS.

Les premières antrées du dictionnaire sont les entrées de la table des couleurs. Deux codes sont particuliers : RESET = 2^MCS et END = RESET + 1. Le reste du dictionnaire sera construit dynamiquement à partir de END + 1 (il peut donc y avoir un vide dans le dictionnaire entre la dernière entrée de la table des couleurs et RESET ;la fonction taille(dico) retourne en fait l'indice du dernier élément de dico moins 1). RESET signifie que le lecteur doit réinitialiser le Dico.

Prennons par exemple une image de 5 x 4 pixels avec 3 couleurs :

Avec une table de couleurs contenant, dans l'ordre, le mauve (0), le rouge (1) et le bleu (2), les données de l'image non compressée sont :

0000000000
0001000100
0100000001
0202020202

L'algorithme de compression est le suivant :

initialiser Dico
cs := MCS + 1
écrire RESET sur cs bits
token := ""
tant que lit c faire
  si token.c est dans le Dico alors
    token := token.c
  sinon
    ajouter token.c au Dico
    écrire le code de token sur cs bits
    token := c
    si taille(Dico) = 2^cs + 1 alors
      si cs = 12 alors
        initialiser Dico
        cs := MCS + 1
        écrire RESET sur cs bits
        token := ""
      sinon
        cs := cs + 1
      fsi
  fsi
ftq
Si on part avec MCS = 2, on va avoir l'exécution suivante :

cstokencdicoout
3RESET004
300
30000006:0000000
30001007:0001000
30100008:0100001
40000
4000000009:000000006
40001
400010000a:000100007
40001
4000100
40001000100b:0001000100a
40100
401000000c:010000008
40000
400000100d:000001006
4010200e:0102001
4020200f:0202002
40202
4020202010:02020200f
50202
5020200f, 005

On obtient donc les données compressées 0, 0, 1, 6, 7, a, 8, 6, 1, 2, f, f avec un 4 en en-tête et un 5 en fin de bloc. En binaire, avec le bon nombre de bits, cela donne 100, 000, 000, 001, 0110, 0111, 1010, 1000, 0110, 0001, 0010, 1111, 01111, 00101. Pour placer ces bits dans des octets, on les lit de droite à gauche et on les écrit de droite à gauche ; lorsque l'octet est rempli, on passe au suivant :

codeoctet courantrésultat
1000:xxxxx10004
0000:xx00010004
0000:0000010004 00
1:xxxxxxx0
0011:xxxx001004 02
01101:0110001004 62
01112:xxxx011104 62 07
10102:1010011104 62 a7
10003:xxxx100004 62 a7 08
01103:0110100004 62 a7 68
00014:xxxx000104 62 a7 68 01
00104:0010000104 62 a7 68 21
11115:xxxx111104 62 a7 68 21 0f
011115:1111111104 62 a7 68 21 ff 00
6:xxxxxxx0
001016:xx00101004 62 a7 68 21 ff 0a

Le bloc de données dans le fichier contiendra donc 7 octets : 04 62 a7 68 21 ff 0a.

Décompression

L'algorithme de décompression est un peu plus complexe :
token := ""
cs := MCS + 1
tant que (lit code sur cs bits) <> END faire
  si code = RESET alors
    initialiser Dico
    cs := MCS + 1
    token := ""
  sinon
    si code est dans le Dico alors
      out := Dico(code)
      ajouter token.premier_octet(out) au Dico
    sinon
      out := token.premier_octet(token)
      ajouter out au Dico
    fsi
    si taille(Dico) = 2^cs alors
      cs := cs + 1
    fsi
    écrire out
    token := out
  fsi
ftq

Pour la décompression, on va avoir :
tokencsvaleurdicoout
3004RESET
300000
003000006:000000
003001007:000101
014006008:01000000
00004007009:0000000001
0001400a00a:000100000100
000100400800b:000100010100
0100400600c:0100000000
0000400100d:00000101
01400200e:010202
02400f00f:02020202
0202500f010:0202020202
02025005END

On peut remarquer que le dictionnaire construit dynamiquement du côté du décompresseur est identique à celui qui avait été construit au niveau du compresseur.

Images animées

Pour obtenir une image animée, il suffit de placer plusieurs images dans le fichier, avec des Graphic Control Extension (GCE).

Prennons par exemple un fichier avec 2 images. Sur la première, on utilise un GCE dans lequel le delay est à 100 : l'image 1 va s'afficher pendant 1 seconde, puis l'image 2 va appara&icric;tre. Cette dernière image restera visible ensuite.

Si on veut que l'affichage soit cyclique, on va ajouter au début du fichier un bloc Application Extension, dans lequel l'identifiant est NETSCAPE, le code d'authentification 2.0 et les données 1, 0, 0 : une fois la dernière image affichée, le viewer revient sur la première. Le premier chiffre doit toujours être à 1 ; les 2 autres représentent le nombre de boucles (en théorie, car la plupart des logiciels bouclent à l'infini quelque soit cette valeur).

Affichage progressif

Lors de la lecture d'un flux, chaque ligne peut être affichée dès qu'elle est décompressée. Si le bit n° 6 du flag de l'image (2ème bit en partant de la gauche du 10ème octet de l'entête) est à 1, l'image est entrelacée : les lignes sont placées dans le fichier dans l'ordre 0, 8, 16, 24, ... puis 4, 12, 20, ... puis 2, 6, 10, ... et enfin 1, 3, 5, ... On a donc 4 groupes :