Reading images from file

All modules seen so far do a direct drawing on the root window. In this page, we show how images can be read from file and copied into the root window. The example we use is the module image.c, which read the picture in monalisa.xpm and displays it in random position of the screen, clearing the root window once in a while.

This is not much different from what is done in sizeofscreen.c, the only change being that we want to display copies of the image, instead of white rectangles. The first thing to do is to read the image from file. X provides some functions for doing this very easily. To use these function, we first include their header file:

#include<X11/xpm.h>

The function for reading the image from file needs a variable of type XImage * to work, so we have to declare such function:

  XImage *img;

The function for reading an xpm file is XpmReadFileToImage, which takes a display, a file name (in this case, "monalisa.xpm"), the variabile of type XImage *, and two other pointers which can be NULL for now. This function returns a boolean that tells whether the operation of reading was successful or not (failure may be due, for example, to the lack of such file). In our case, we can use the following fragment of code to read the image and check the result:

  /* read the image */
  if (XpmReadFileToImage (dpy, "monalisa.xpm", &img, NULL, NULL)) {
      printf ("Error reading file\n");
      exit (1);
  }

If the file cannot be read, the program prints the error message and stops. If the operation is successful, the image is stored into the variabile img. We do not care much how the image is represented, that is, we need not to know what the image variabile is. What is important is that XImage is a structure that contains (among others) two fields width and height which indicates the size of the image. After the file is read, its size is in img->width and img->height.

The most natural use of an image is to copy it into a window. The command for doing this is XPutImage, which takes a bunch of arguments. In particular: the first is the display, the second is the window to copy to, the third is the graphics context, the fourth is an XImage * variable (i.e. one of those used in XpmReadFileToImage), the other arguments are coordinates. To copy the whole image to the coordinates x,y, use the numbers 0,0,x,y,ir->width, ir->height (for more details, see the man page).

In our case, we want the image img to be copied as a whole to the window root, using the graphics context g and random coordinates. For the x coordinate we can choose a random number between 0 and wa.width, but this displays some images too close to the right border of the screen, so that part of them are cut by the border. Since we know the x size of the image, this is not a problem: since the point to copy must be at least img->widht far from the border, we can choose a random number from 0 to wa.width-img->widht. The same has to be done for the y coordinate.

      /* copy the image to a random position of the screen */
      XPutImage(dpy, root, g, img, 0, 0,
                random()%(wa.width-img->width),
                random()%(wa.height-img->height),
                img->width, img->height );

The arguments of this function may look complex to get. However, besides the display, window, image, and graphics context, the only things that typically changes are the coordinates of the point to copy the image to.

In order to compile the file, the library containing the operation on xpm file is needed. The name of this library is libxpm.so, and is in /usr/X11R6/lib. As a result, the command line to compile the module is:

gcc -o image image.c -L/usr/X11R6/lib -lX11 -lXpm

The complete code: image.c. The image file monalisa.xpm is needed, and must be in the directory from which image is run. A possible improvement to this module is the ability to pass the image as an argument to it.


Next: embedding images into programs