La Xlib propose une structure assez proche dans son utilisation des Pixmaps, la structure XImage. Cette structure permet d'encapsuler un buffer au sens du langage C, par exemple :
char *buffer = (char *) malloc(nb_cols * nb_lignes *
sizeof(char));
...dans une structure de plus haut niveau : un objet de type XImage manipulable par la Xlib.
Le principal avantage des XImages sur les Pixmaps est que la manipulation des données graphiques qu'elles contiennent se fait en attaquant directement le buffer à l'aide de fonctions C standards. Ceci permet d'optimiser les opérations graphiques. Le dessin d'un rectangle uni se fera à l'aide d'un appel à la fonction C memcopy()par exemple...
Leur principal désavantage est que l'on ne peut plus utiliser les fonctions de dessin de la Xlib. On doit tout faire à la main. La seule fonction graphique disponible est une macro qui permet de remplir un point de l'XImage avec une couleur donnée!!!
Rappelons que les Pixmaps ne peuvent être manipulés qu'au travers de fonctions Xlib et donc au travers du protocole X11.
Cette fonction permet d'encapsuler un buffer standard alloué par l'application client (char *data= malloc(width*height*sizeof(char)) par exemple), dans une structure de type XImage manipulable par les fonctions Xlib.
Pour les machines sur lesquelles nous allons travailler on mettra les paramètres un peu mystérieux aux valeurs suivantes:
Voir le manuel de la fonction pour plus de détails.
Attention :
XGetImage(...) et XGetSubImage(...)
Remplit une XImage à partir d'un drawable (window ou pixmap)
XPutImage(display, image, drawable, x_src, y_src, x_dest, y_dest, width, height)
Recopie une XImage dans un drawable. Nécessaire pour rendre une XImage visible.
Libère la mémoire allouée pour l'XImage. Attention, si l'XImage a été créée avec XCreateImage, XGetImage ou XGetSubImage, cette fonction libère à la fois le buffer et la structure d'encapsulation.
XGetPixel(ximage, x, y) et XPutPixel(ximage, x, y, pixel_value)
Macros permettant de lire ou d'écrire un pixel dans une XImage. XGetPixel() renvoie lapixel value du point passé en paramètre, XPutPixel() permet de colorer un pixel avec une pixel_value.
...
/* Alloue une XImage de width pixels de large * height pixels de haut */ char *buffer = NULL; XImage *XIma = NULL;
/* On alloue donc le buffer qui va contenir les graphiques
manuellement a l'aide d'un malloc */
if (buffer=(char *) malloc(width * height*sizeof(char)) {
perror("malloc failed \n");
exit(0);
}
/* Allocation d'une XImage à partir du buffer, plus rapide pour
le dessin et l'affichage qu'un Pixmap */
XIma=XCreateImage(display, visual ,8, ZPixmap ,0 ,(char *) buffer,
width,height,8,0);
...
/* On remplit avec la pixel value 0 le point (x, y) */ buffer[x*y+x] = 0;
/* On affiche le buffer dans une fenêtre */ XPutImage(dpy, win, gc, XIma, 0, 0, 0, 0, width, height);
Dans cet exemple, on alloue d'abord un buffer standard puis on l'encapsule dans une XImage. Le buffer est utilisé directement pour dessiner :
buffer[x*y+x] = 0;
On aurait pu aussi bien utiliser la fonction XPutPixel() de la manière suivante.
XPutPixel(XIma, x, y, 0);
Je pense que les deux écritures sont strictement équivalentes, cependant il est avantageux d'attaquer directement le buffer dans le cas d'utilisation de fonctions de type memset() ou memcpy(), utiles pour remplir des zones de mémoire rapidement.
Enfin, l'affichage se fait en recopiant l'XImage dans une fenêtre :
XPutImage(dpy, win, gc, XIma, 0, 0, 0, 0, width, height);
Certaines implémentations de la Xlib fournissent des fonctions permettant d'allouer une XImage dans une zone de mémoire partagée par l'application client et le serveur X. Les versions Solaris, SunOS et Linux de la Xlib en font partie.
On gagne au moins un facteur deux en performances pures lors d'opérations comme XPutImage() qui interviennt très souvent sitôt que l'on fait de l'animation. Il est donc très intéressant d'utiliser la mémoire partagée lorsqu'on en a la possibilité.
Malheureusement, il n'est possible d'allouer cette mémoire partagée que lorsque l'application client tourne sur la même machine que le serveur. En d'autres termes : si vous êtes connectés sur une autre machine que celle sur laquelle vous travaillez, ne comptez pas sur une application distante pour ouvrir une mémoire partagée sur votre machine.
Conclusion : si vous voulez qu'une application fonctionnent "normalement", en local comme en remote, prévoyez le cas ou l'allocation de la mémoire partagée échoue.
L'exemple qui suit présente une fonction qui essaie d'allouer une XImage dans une zone de mémoire partagée. Si il y a echec, alors l'XImage est allouée de manière standard.
/*----------------------------------------*/ XImage* Alloc_XImage(long width, long height) /*----------------------------------------*/ /* Alloue un buffer de de width pixels de large * height pixels de haut dans une XImage */
{
/* Pour la shared memory */
XShmSegmentInfo Shminfo;
int CompletionType;
unsigned char Shm_Hard_Buffer_Flag;
XImage *XIma=NULL;
long Shm_OK;
/* Allocation d'une XImahe en Shared memory si possible */
Shm_OK=XShmQueryExtension(display);
switch(Shm_OK) {
case 0:
/* On a pas pas pu allouer de Shared memory. On alloue
donc le Buffer a l'aide d'un malloc */
if (buffer=(char *) malloc(width * height *sizeof(char)) {
perror("malloc failed \n");
exit(0);
}
/* Allocation d'une XImage normale */
XIma=XCreateImage(display, visual ,
8, ZPixmap , 0,(char *) buffer ,
width, height,8,0);
/* Flag qui indique qu'on a pas alloue la Shared Memory */
Shm_Hard_Buffer_Flag = False;
break;
case 1:
/* On a pu allouer la Shared memory. Le buffer va donc se
trouver dans cette zone. On ne fait de malloc() */
XIma=XShmCreateImage(display,visual ,8,ZPixmap ,
NULL,&Shminfo,width,height);
Shminfo.shmid = shmget(IPC_PRIVATE,width * height,
IPC_CREAT | 0777);
Shminfo.shmaddr = XIma->data = buffer =
shmat(Shminfo.shmid, NULL, 0);
if (buffer) {
fprintf(stderr,"erreur d'allocation en Shared memory\n");
exit(0);
}
/* Shared memory alloue */
Shminfo.readOnly = False;
XShmAttach(display, &Shminfo);
Shm_Hard_Buffer_Flag = True;
CompletionType = XShmGetEventBase(display) + ShmCompletion;
break;
}
return XIma;
}

Ouf!!!
Remarquons plusieurs choses :