Porting applications from &Imlib; to &gdk-pixbuf; This appendix contains the basic steps needed to port an application that uses the &Imlib; library to use &gdk-pixbuf; instead. This appendix refers to version 1 of the &Imlib; library; this discussion is not relevant to Imlib 2. Also, we discuss the gdk_imlib API instead of the Xlib-based API. Introduction Prior to the GNOME 1.2 platform, the &Imlib; library was the preferred way of loading and rendering images in GNOME applications. Unfortunately, &Imlib; has important design limitations that make it hard to write efficient and highly modular applications. The &gdk-pixbuf; library was designed as a solution to &Imlib;'s shortcomings. It provides a simple, orthogonal API and convenience functions for the most common operations. In addition, it supports full transparency information for images, or alpha channel. More importantly, it has well-defined semantics for memory management through the use of reference counting; &Imlib; has an intractably complex memory management mechanism and cache that will make your head spin. Differences between &Imlib; and &gdk-pixbuf; Generally, applications that use &Imlib; do not have to be changed extensively to use &gdk-pixbuf;; its simple and flexible API makes things easy. This section describes the differences between &Imlib; and &gdk-pixbuf;; you should take these into account when modifying your applications to use &gdk-pixbuf;. Initialization The &gdk-pixbuf; library does not need to be initialized. In GNOME applications you normally don't need to initialize &Imlib;, as gnome_init() calls gdk_imlib_init() automatically. Memory management The &gdk-pixbuf; library provides a simple, well-defined memory management mechanism for images in the form of reference counting. This makes it very convenient to use for large-scale applications that need to share images between different parts of the program. In stark contrast, &Imlib; has a terribly complex mechanism of an image and pixmap cache which makes it very hard for applications to share image structures between different parts of the program. Unfortunately this mechanism makes things very prone to memory leaks and tricky bugs. The basic principle in &gdk-pixbuf; is that when you obtain a new GdkPixbuf structure, it is created with an initial reference count of 1. When another part of the program wants to keep a reference to the pixbuf, it should call g_object_ref(); this will increase the reference count by 1. When some part of the program does not need to keep a reference to a pixbuf anymore and wants to release the pixbuf, it should call g_object_unref(); this will decrease the reference count by 1. When the reference count drops to zero, the pixbuf gets destroyed or finalized and its memory is freed. For applications that need to implement a cache of loaded images, &gdk-pixbuf; provides a way to hook to the last unreference operation of a pixbuf; instead of finalizing the pixbuf, the user-installed hook can decide to keep it around in a cache instead. Finally, &gdk-pixbuf; does not provide a cache of rendered pixmaps. This is unnecessary for most applications, since the scaling and rendering functions are quite fast and applications may need to use subtly different values each time they call these functions, for example, to take into account dithering and zooming offsets. Most applications will simply need to call g_object_ref() when they want to keep an extra reference to a pixbuf, and then g_object_unref() when they are done with it. The Rendering Process The &gdk-pixbuf; library has the policy of always rendering pixbufs to GDK drawables you provide; it will not create them for you. This is in general more flexible than &Imlib;'s policy of always creating a pixmap and making you use that instead. The disadvantage of always having a pixmap created for you is that it wastes memory in the X server if you intend to copy that rendered data onto another drawable, for example, the final destination window or a temporary pixmap for drawing. This is the most common case, unfortunately, so the &Imlib; policy introduces unnecessary copying. Also, &Imlib; can only render pixmaps that are the whole size of the source image; you cannot render just a subset region of the image. This is inconvenient for applications that need to render small portions at a time, such as applications that do scrolling. Since the whole image must be rendered at a time, this can lead to performance and memory usage problems. The &gdk-pixbuf; library lets you render any rectangular region from an image onto any drawable that you provide. This lets the application have fine control the way images are rendered. Converting Applications to &gdk-pixbuf; This sections describes the actual changes you need to make in an &Imlib; program to make it use &gdk-pixbuf; instead. Image loading and creation The &gdk-pixbuf; library can load image files synchronously (i.e. with a single function call), create images from RGB data in memory, and as a convenience, it can also create images from inline XPM data. To load an image file in a single function call, simply use gdk_pixbuf_new_from_file(). Note that this will make the program block until the whole file has been read. This function effectively replaces gdk_imlib_load_image(). If you have RGB data in memory, you can use gdk_pixbuf_new_from_data() to create a pixbuf out of it; this is a replacement for gdk_imlib_create_image_from_data(). &gdk-pixbuf; does not copy the image data; it is up to you to define the ownership policy by providing a destroy notification function that will be called when the image data needs to be freed. The function you provide can then free the data or do something else, as appropriate. As a convenience, you can use the gdk_pixbuf_new_from_xpm_data() function to create a pixbuf out of inline XPM data that was compiled into your C program. This is a replacement for gdk_imlib_create_image_from_xpm_data(). After you have created a pixbuf, you can manipulate it in any way you please and then finally call g_object_unref() when you are done with it. This can be thought of as a replacement for gdk_imlib_destroy_image() but with much cleaner semantics. Rendering Images Applications that use &Imlib; must first call gdk_imlib_render() to render the whole image data onto a pixmap that &Imlib; creates. Then they must copy that pixmap's data into the final destination for the image. In contrast, &gdk-pixbuf; provides convenience functions to render arbitrary rectangular regions of an image onto a drawable that your application provides. You can use gdk_pixbuf_render_to_drawable() or gdk_pixbuf_render_to_drawable_alpha() to do this; having your application provide the destination drawable and specify an arbitrary region means your application has complete control over the way images are rendered. As a convenience, &gdk-pixbuf; also provides the gdk_pixbuf_render_pixmap_and_mask() function; this will create new pixmap and mask drawables for a whole pixbuf and render the image data onto them. Only trivially simple applications should find a use for this function, since usually you want finer control of how things are rendered. Scaling Images &Imlib; lets you render scaled image data at the time you call gdk_imlib_render(). Again, this unfortunately scales and renders the whole image onto a new pixmap. &gdk-pixbuf; provides a number of functions that do scaling of arbitrary regions of a source pixbuf onto a destination one. These functions can also perform compositing operations against the data in the destination pixbuf or against a solid color or a colored checkerboard. You can use a colored checkerboard as the background for compositing when you want to provide a visual indication that the image has partially opaque areas. This is normally used in image editing and viewing programs. Compositing against a single solid color is actually a special case of a checkerboard; it simply uses checks of the same color. Very simple applications may find it sufficient to use gdk_pixbuf_scale_simple() or gdk_pixbuf_composite_color_simple(). These functions scale the whole source image at a time and create a new pixbuf with the result. More sophisticated applications will need to use gdk_pixbuf_scale(), gdk_pixbuf_composite(), or gdk_pixbuf_composite_color() instead. These functions let you scale and composite an arbitrary region of the source pixbuf onto a destination pixbuf that you provide. Getting Image Data from a Drawable &Imlib; lets you create an image by fetching a drawable's contents from the X server and converting those into RGB data. This is done with the gdk_imlib_create_image_from_drawable() function. &gdk-pixbuf; provides the gdk_pixbuf_get_from_drawable() function instead. It lets you specify a destination pixbuf instead of always creating a new one for you.