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.
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.
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 :
00 | 00 | 00 | 00 | 00 |
00 | 01 | 00 | 01 | 00 |
01 | 00 | 00 | 00 | 01 |
02 | 02 | 02 | 02 | 02 |
L'algorithme de compression est le suivant :
Si on part avec MCS = 2, on va avoir l'exécution suivante :
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
cs | token | c | dico | out |
---|---|---|---|---|
3 | RESET | 004 | ||
3 | 00 | |||
3 | 00 | 00 | 006:0000 | 000 |
3 | 00 | 01 | 007:0001 | 000 |
3 | 01 | 00 | 008:0100 | 001 |
4 | 00 | 00 | ||
4 | 0000 | 00 | 009:000000 | 006 |
4 | 00 | 01 | ||
4 | 0001 | 00 | 00a:000100 | 007 |
4 | 00 | 01 | ||
4 | 0001 | 00 | ||
4 | 000100 | 01 | 00b:00010001 | 00a |
4 | 01 | 00 | ||
4 | 0100 | 00 | 00c:010000 | 008 |
4 | 00 | 00 | ||
4 | 0000 | 01 | 00d:000001 | 006 |
4 | 01 | 02 | 00e:0102 | 001 |
4 | 02 | 02 | 00f:0202 | 002 |
4 | 02 | 02 | ||
4 | 0202 | 02 | 010:020202 | 00f |
5 | 02 | 02 | ||
5 | 0202 | 00f, 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 :
code | octet courant | résultat |
---|---|---|
100 | 0:xxxxx100 | 04 |
000 | 0:xx000100 | 04 |
000 | 0:00000100 | 04 00 |
1:xxxxxxx0 | ||
001 | 1:xxxx0010 | 04 02 |
0110 | 1:01100010 | 04 62 |
0111 | 2:xxxx0111 | 04 62 07 |
1010 | 2:10100111 | 04 62 a7 |
1000 | 3:xxxx1000 | 04 62 a7 08 |
0110 | 3:01101000 | 04 62 a7 68 |
0001 | 4:xxxx0001 | 04 62 a7 68 01 |
0010 | 4:00100001 | 04 62 a7 68 21 |
1111 | 5:xxxx1111 | 04 62 a7 68 21 0f |
01111 | 5:11111111 | 04 62 a7 68 21 ff 00 |
6:xxxxxxx0 | ||
00101 | 6:xx001010 | 04 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.
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 :
token | cs | valeur | dico | out |
---|---|---|---|---|
3 | 004 | RESET | ||
3 | 000 | 00 | ||
00 | 3 | 000 | 006:0000 | 00 |
00 | 3 | 001 | 007:0001 | 01 |
01 | 4 | 006 | 008:0100 | 0000 |
0000 | 4 | 007 | 009:000000 | 0001 |
0001 | 4 | 00a | 00a:000100 | 000100 |
000100 | 4 | 008 | 00b:00010001 | 0100 |
0100 | 4 | 006 | 00c:010000 | 0000 |
0000 | 4 | 001 | 00d:000001 | 01 |
01 | 4 | 002 | 00e:0102 | 02 |
02 | 4 | 00f | 00f:0202 | 0202 |
0202 | 5 | 00f | 010:020202 | 0202 |
0202 | 5 | 005 | END |
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.
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).