Afficher des images tramées avec Motif 

Introduction

Le but de ce chapitre est de comprendre comment réaliser un affichage d'images en milliers ou millions de couleurs à l'intérieur d'une application utilisant Motif.
 

Techniques de tramage ordonné

Si l'on a une seule image à afficher, un tramage de type Floyd-Steinberg est la meilleure solution, cependant, ce tramage n'est pas adpaté sitôt que l'on désire afficher plusieurs images à la fois, dans n'importe quel ordre.
 

Utilisation d'une colormap privée, ressources propres à une application

Pour utiliser une colormap privée, nous allons utiliser des fonctions xlib standard, de type XCreateColormap, XallocColorCells, etc...  Il faudra positionner la ressource XmNcolormap de chaque fenêtre indépendante manipulable par le window manager (chaque fenêtre de type Shell).

La méthode proposée ici permet de faire en sorte que les couleurs des widgets de l'interface Motif ne soient pas affectés par
le fait que l'on utilise une colormap privée. Même si on a spécifié des couleurs dans le fichier de ressources, ces couleurs
seront bien utilisées par Motif.

Pour que ça fonctionne, il faut :

  1. Ne plus utiliser XtVaAppInitialize(...) pour créer la fenêtre initiale, car cette fonction lit le fichier de ressources. Pourquoi faut-il éviter de lire le fichier de ressources dès le début ? Parceque si  on a spécifié une couleur dans ce fichier, par exemple avec les lignes :
  2. *.background:                           #e0e0e0
    *.foreground:                           #383830
    
    *selectColor:                           #00ffd0
    *topShadowColor:                        #f0f0f0
    *bottomShadowColor:                     #a0a0a0
    *highlightThickness:                    1
    ... Xt regarde dans la colormap existante, c'est-à-dire la colormap standard, dans quelles cases se trouvent les  couleurs les plus proches. Si par la suite on remplace la colormap standard par une autre à nous (une colormap privée, les couleurs ne correspondront plus et lorsque l'application récupèrera le focus de la souris, il y a fort à parier pour que les couleurs de l'interface prennent une couleur horrible.

    La solution va donc consister à "faire à la main" ce que fait la fonction XtVaAppInitialize(...), sauf la lecture du fichier de ressources.
     

  3. Créer une colormap privée, mais sans allouer toutes les couleurs. Il faut laisser des cases libres pour que Motif puisse les utiliser lorsqu'il aura lu le fichier de ressources.
  4. Remplir une partie de la colormap privée avec les couleurs requises par l'application. On prendra soin de laisser une vingtaine de cases pour les couleurs de l'interface.
  5. Positionner la ressource XmNcolormap de la fenêtre top-level avec la colormap que l'on vient de créer.
  6. Lire le fichier de ressources. En le lisant après avoir changé la colormap, Motif va regarder si les couleurs spécifiées se trouvent parmi les couleurs que nous avons allouées. Si elles n'y sont pas, Motif va essayer de les allouer dans les cases libres de la colormap. Comme nous avons pris soin d'en laisser une vingtaine de disponibles, ça va marcher.
  7. La lecture du fichier de ressources se fait à l'aide de la fonction XtGetApplicationResources(...). Cette fonction permet de lire le fichier de ressources, mais aussi de spécifier des ressources propres à notre application.

    Exemple de ressources propres que l'on peut spécifier dans le fichier de ressources :

    ! Ressources propres a l'application
    *.TextureDir: ./textures
    *.resourceFileLoaded: True
    Cet exemple indique que l'on spécifie dans le fichier de ressources un répertoire où on va lire des textures (des images). Le type de la valeur attendue est une chaîne de caractères. On attend aussi une ressource de nom "resourceFileLoaded" de type booléen. Cette dernière ressource est utile, nous allons le voir, pour pouvoir tester si le fichier de ressources a bien été lu par l'application.

Exemple de code

  

  /* Contexte general */
  XtAppContext app_context;
  Display *dpy = NULL;
  int screen;   
  Window root;  
  Visual *visual;
  GC gc;
  Colormap cmap;
  XGCValues gcv;
  / * Pour les ressources propres à l'application */
  typedef struct _my_application_instance_variables{
    Bool resourceLoaded;
  } _my_app_inst_rec;
 
  static XtResource my_app_resources[] =
  {
    {
        "resourceFileLoaded",   /* Noms attendus dans le fichier de ressources */
        "ResourceFileLoaded",
        XtRBool, sizeof (Bool), /* type de la ressource */
        XtOffsetOf(_my_app_inst_rec, resourceLoaded), /* variable qui va recevoir
                                                         le résultat */
        XtRString, "False"      /* valeur par défaut si la ressource 
                                   n'est pas présente */
    }
  };
  /* Structure où vont être stockées les valeurs des ressources
     propres */
  _my_app_inst_rec ir;
  /*... dans le programme principal ... */

  ...

  /*----------------------------------------------*/
  /* 1) Ouverture du toolkit, en plusieurs etapes */
  /*----------------------------------------------*/

  XtToolkitInitialize();
  app_context = XtCreateApplicationContext();
  dpy         = XtOpenDisplay(app_context, NULL, NULL, "AffImage", NULL, 0,
                              &argc, argv);
  screen      = DefaultScreen(dpy);
  root        = RootWindow(dpy, screen);
  visual      = DefaultVisual(dpy, screen);
 
  if (!dpy) {
    fprintf(stderr, "%s: Unable to open display\n", argv[0]);
    exit(0);
  }
 
  /*------------------------------------------------------------------------*/
  /* 2) Creation du top_level, le fichier de resources s'appelle "AffImage" */
  *------------------------------------------------------------------------*/
  top_wid = XtAppCreateShell(NULL, "AffImage", applicationShellWidgetClass, 
                             dpy, NULL, 0);
  /*---------------------------------------*/
  /* 3) Installation d'une colormap privée */
  /*---------------------------------------*/
  /*     - a) Création de la colormap, en mode AllocNone car on ne va pas utiliser toutes
              les colorcells, on va en laisser quelques unes pour Motif, pour être sûrs
              que les couleurs des widgets existent */
  cmap = XCreateColormap(dpy, root, visual, AllocNone);
  /*     - b) Remplissage de la colormap avec nos couleurs 
              (on laisse une vingtaine de couleurs pour Motif) */
  Lut_VisuColor(dpy, cmap);
  /*     - c) On associe cette colormap à la fenêtre top-level. */  
  XtVaSetValues(top_wid, XmNcolormap, cmap, XtNvisual, visual,NULL);
  /*-------------------------------------*/ 
  /* 4) Lecture du fichier de ressources */
  /*-------------------------------------*/
  XtGetApplicationResources(top_wid, &ir, my_app_resources,
                            XtNumber(my_app_resources), NULL, 0);
  /*---------------------------------------------------------------------*/
  /* 5) Vérification de la bonne lecture du fichier. Si la ressource 
         "resourceFileLoaded ne vaut pas True, le fichier n'a pas été lu */
  /*---------------------------------------------------------------------*/
      if (!ir.resourceLoaded) {
        fprintf(stderr, 
                "%s: Fichier de ressources de nom AffImage non trouve.\n",
                  argv[0]);
          fprintf(stderr, "Assurez-vous que XFILESEARCHPATH ou XAPPLRESDIR est b
ien positionnee,\n");
          fprintf(stderr, "et que le fichier AffImage se trouve dans le chemin d
e recherche,\n ou bien utilisez xrdb pour ajouter le contenu du fichier AffImage
 au serveur X.\n");
/*          exit(0); */
        }
    }

 Que mettre dans la colormap ?

Tout dépend de l'application. Pour afficher plusieurs images, ou encore faire un programme de synthèse d'image nécessitant de nombreuses nuances, on va avoir envie d'avoir une palette proposant des couleurs obtenues par un mélange des composantes bleu, rouge et vert. Sur un écran 256 couleurs, la technique consiste à mettre un peu moins de bleu que de rouge et de vert car l'oeil humain  distingue moins de nuances de bleu.

Nous nous inspirons ici de ce que font les programmes Netscape ou Xv, mais le traitement demeure cependant original. Voici la colormap que nous allons utiliser :