Skip to content

X Bitmaps and Pixmaps

One thing many so-called "Multi-Media" applications need to do, is display images. In the X world, this is done using bitmaps and pixmaps. We have already seen some usage of them when setting an icon for our application. Lets study them further, and see how to draw these images inside a window, along side the simple graphics and text we have seen so far.

One thing to note before delving further, is that XCB (nor Xlib) supplies no means of manipulating popular image formats, such as gif, png, jpeg or tiff. It is up to the programmer (or to higher level graphics libraries) to translate these image formats into formats that the X server is familiar with (x bitmaps and x pixmaps).

  1. What is a X Bitmap? An X Pixmap?

    An X bitmap is a two-color image stored in a format specific to the X window system. When stored in a file, the bitmap data looks like a C source file. It contains variables defining the width and the height of the bitmap, an array containing the bit values of the bitmap (the size of the array is (width+7)/8*height and the bit and byte order are LSB), and an optional hot-spot location (that will be explained later, when discussing mouse cursors).

    An X pixmap is a format used to stored images in the memory of an X server. This format can store both black and white images (such as x bitmaps) as well as color images. It is the only image format supported by the X protocol, and any image to be drawn on screen, should be first translated into this format.

    In actuality, an X pixmap can be thought of as a window that does not appear on the screen. Many graphics operations that work on windows, will also work on pixmaps. Indeed, the type of X pixmap in XCB is an Id like a window:

    typedef uint32_t xcb_pixmap_t;
    typedef uint32_t xcb_pixmap_t;

    Like Xlib, there is no difference between a Drawable, a Window or a Pixmap:

    typedef uint32_t xcb_drawable_t;
    typedef uint32_t xcb_drawable_t;

    in order to avoid confusion between a window and a pixmap. The operations that will work the same on a window or a pixmap will require a xcb_drawable_t

    Remark: In Xlib, there is no specific difference between a Drawable, a Pixmap or a Window: all are 32 bit long integer. XCB wraps all these different IDs in structures to provide some measure of type-safety.

  2. Creating a pixmap

    Sometimes we want to create an un-initialized pixmap, so we can later draw into it. This is useful for image drawing programs (creating a new empty canvas will cause the creation of a new pixmap on which the drawing can be stored). It is also useful when reading various image formats: we load the image data into memory, create a pixmap on the server, and then draw the decoded image data onto that pixmap.

    To create a new pixmap, we first ask the X server to give an Id to our pixmap, with this function:

    xcb_pixmap_t xcb_generate_id (xcb_connection_t *c);
    xcb_pixmap_t xcb_generate_id (xcb_connection_t *c);

    Then, XCB supplies the following function to create new pixmaps:

    xcb_void_cookie_t xcb_create_pixmap (xcb_connection_t *c,         /* Pointer to the xcb_connection_t structure */
                                         uint8_t           depth,     /* Depth of the screen */
                                         xcb_pixmap_t      pid,       /* Id of the pixmap */
                                         xcb_drawable_t    drawable,
                                         uint16_t          width,     /* Width of the window (in pixels) */
                                         uint16_t          height);   /* Height of the window (in pixels) */
    xcb_void_cookie_t xcb_create_pixmap (xcb_connection_t *c,         /* Pointer to the xcb_connection_t structure */
                                         uint8_t           depth,     /* Depth of the screen */
                                         xcb_pixmap_t      pid,       /* Id of the pixmap */
                                         xcb_drawable_t    drawable,
                                         uint16_t          width,     /* Width of the window (in pixels) */
                                         uint16_t          height);   /* Height of the window (in pixels) */

    TODO: Explain the drawable parameter, and give an example (like xpoints.c)

  3. Drawing a pixmap in a window

    Once we got a handle to a pixmap, we can draw it on some window, using the following function:

    xcb_void_cookie_t xcb_copy_area (xcb_connection_t *c,             /* Pointer to the xcb_connection_t structure */
                                     xcb_drawable_t    src_drawable,  /* The Drawable we want to paste */
                                     xcb_drawable_t    dst_drawable,  /* The Drawable on which we copy the previous Drawable */
                                     xcb_gcontext_t    gc,            /* A Graphic Context */
                                     int16_t           src_x,         /* Top left x coordinate of the region we want to copy */
                                     int16_t           src_y,         /* Top left y coordinate of the region we want to copy */
                                     int16_t           dst_x,         /* Top left x coordinate of the region where we want to copy */
                                     int16_t           dst_y,         /* Top left y coordinate of the region where we want to copy */
                                     uint16_t          width,         /* Width of the region we want to copy */
                                     uint16_t          height);       /* Height of the region we want to copy */
    xcb_void_cookie_t xcb_copy_area (xcb_connection_t *c,             /* Pointer to the xcb_connection_t structure */
                                     xcb_drawable_t    src_drawable,  /* The Drawable we want to paste */
                                     xcb_drawable_t    dst_drawable,  /* The Drawable on which we copy the previous Drawable */
                                     xcb_gcontext_t    gc,            /* A Graphic Context */
                                     int16_t           src_x,         /* Top left x coordinate of the region we want to copy */
                                     int16_t           src_y,         /* Top left y coordinate of the region we want to copy */
                                     int16_t           dst_x,         /* Top left x coordinate of the region where we want to copy */
                                     int16_t           dst_y,         /* Top left y coordinate of the region where we want to copy */
                                     uint16_t          width,         /* Width of the region we want to copy */
                                     uint16_t          height);       /* Height of the region we want to copy */

    As you can see, we could copy the whole pixmap, as well as only a given rectangle of the pixmap. This is useful to optimize the drawing speed: we could copy only what we have modified in the pixmap.

    One important note should be made: it is possible to create pixmaps with different depths on the same screen. When we perform copy operations (a pixmap onto a window, etc), we should make sure that both source and target have the same depth. If they have a different depth, the operation would fail. The exception to this is if we copy a specific bit plane of the source pixmap using the xcb_copy_plane_t function. In such an event, we can copy a specific plane to the target window (in actuality, setting a specific bit in the color of each pixel copied). This can be used to generate strange graphic effects in a window, but that is beyond the scope of this tutorial.

  4. Freeing a pixmap

    Finally, when we are done using a given pixmap, we should free it, in order to free resources of the X server. This is done using this function:

    xcb_void_cookie_t xcb_free_pixmap (xcb_connection_t *c,        /* Pointer to the xcb_connection_t structure */
                                       xcb_pixmap_t      pixmap);  /* A given pixmap */
    xcb_void_cookie_t xcb_free_pixmap (xcb_connection_t *c,        /* Pointer to the xcb_connection_t structure */
                                       xcb_pixmap_t      pixmap);  /* A given pixmap */

    Of course, after having freed it, we must not try accessing the pixmap again.

    TODO: Give an example, or a link to xpoints.c