Aug 2004, S.Geerken@ping.de ============= Image Buffers ============= General ======= Image buffers depend on the platform (see DwRender.txt), but have a general, platform independant interface, which is described in this section. The next section describes the Gdk version of Imgbuf. The structure ImgBuf will become part of the image processing, between image data decoding and the widget DwImage. Its purposes are 1. storing the image data, 2. handling scaled versions of this buffer, and 3. drawing. The latter must be done independently from the window. Storing Image Data ------------------ Imgbuf supports five image types, which are listed in the table below. The representation defines, how the colors are stored within the data, which is passed to a_Imgbuf_copy_row(). | bytes per | type | pixel | representation ---------------+-----------+------------------------- RGB | 3 | red, green, blue RGBA | 4 | red, green, blue, alpha gray | 1 | gray value indexed | 1 | index to colormap indexed alpha | 1 | index to colormap The last two types need a colormap, which is set by a_Imgbuf_set_cmap(), which must be called before a_Imgbuf_copy_row(). This function expects the colors as 32 bit unsigned integers, which have the format 0xrrbbgg (for indexed images), or 0xaarrggbb (for indexed alpha), respectively. Scaling ------- The buffer with the original size, which was created by a_Imgbuf_new(), is called root buffer. Imgbuf provides the ability to scale buffers. Generally, both root buffers, as well as scaled buffers, may be shared, memory management is done by reference counters. Via a_Imgbuf_get_scaled_buf(), you can retrieve a scaled buffer. The way, how this function works in detail, is described in the code, but generally, something like this works always, in an efficient way: old_buf = cur_buf; cur_buf = a_Imgbuf_get_scaled_buf(old_buf, with, height); a_Imgbuf_unref (old_buf); Old_buf may both be a root buffer, or a scaled buffer. (As an exception, there should always be a reference on the root buffer, since scaled buffers cannot exist without the root buffer, but on the other side, do not hold references on it. So, if in the example above, old_buf would be a root buffer, and there would, at the beginning, only be one reference on it, new_buf would also be destroyed, along with old_buf. Therefore, an external reference must be added to the root buffer, which is in dillo done within the dicache module.) The root buffer keeps a list of all children, and all operations operating on the image data (a_Imgbuf_copy_row() and a_Imgbuf_set_cmap()) are delegated to the scaled buffers, when processed, and inherited, when a new scaled buffer is created. This means, that they must only be performed for the root buffer. Drawing ------- There are two situations, when drawing is necessary: 1. To react on expose events, the function a_Imgbuf_draw() can be used. Notice that the exact signature of this function is platform dependant. 2. When a row has been copied, it has to be drawn. To determine the area, which has to be drawn, the function a_Imgbuf_get_row_area() should be used. In dillo, the dicache module will first call a_Img_copy_row(), and then call a_Dw_image_draw_row() for the images connected to this image buffer. a_Dw_image_draw_row() will then call p_Dw_widget_queue_draw(), with an area determined by a_Imgbuf_get_row_area(). The Gdk Implementation ====================== The Gdk implementation is used by the Gtk+ platform. [... todo] Global Scalers ============== In some cases, there is a context, where images have to be scaled often, by a relatively constant factor. For example, the preview window (GtkDwPreview) draws images via the Imgbuf draw functions, but uses scaled buffers. Scaling such a buffer each time it is needed, causes huge performance losses. On the other hand, if the preview window would keep these scaled buffers (e.g. by lazy mapping of the original buffer to the scaled buffer), the scaled buffers get never freed, since the view is not told about, when the original buffer is not needed anymore. (n.b., that currently, the scaled buffers are destroyed, when the original buffer is destroyed, but this may change, and even this would leave "zombies" in this mapping structure, where the values refer to dead pointers). It is sufficient, that references on the scaled buffers are referred somehow, so that they do not get destroyed between different usages. The caller (in this case the preview) simply requests a scaled buffer, but the Imgbuf returns this from the list of already scaled buffers. These references are hold by special structures, which are called "scalers". There are two types of scalers, local scalers, which are bound to image buffers, and global scalers, which refer to multiple scalers. What happens in different situations: - The caller (e.g. the preview) requests a scaled buffer. For this, it uses a special method, which also passes the global image scaler, which was created before (for the preview, there is a 1-1 association). The Imgbuf uses this global image scaler, to identify the caller, and keeps a list of them. If this global scaler is not yet in the list, it is added, and a local scaler is created. - There are three images in the page, i1a, i1b, and i2. I1a and i1b refer to the same image recource, represented by the root image buffer iba, which original size is 200 x 200. I1a is displayed in original size, while i1b is displayed at 100 x 100. I2 refers to an other recource, ibb, which has the size 300 x 300. I2 is shown in original size. :DwRenderLayout ------------------- :DwPage ----------. / \ | ,----' `----. ,------ i1a:DwImage --+ / \ | | view1:GtkDwViewport view2:GtkDwPreview | ,---- i1b:DwImage --| | | | | ,------------------------------' | | ,-- i2: DwImage --' | | | | | ,-------------------------------------' | | | | ,--------------------------------' | | | | ,----' | | | | | V | V | iba:Imgbuf | ibb:Imgbuf -- 30x30 | | | V | ^ | | +- 100x100 ,- 20x20 ,- 10x10 | | | | | | ^ | ^ | | | | `----------+----|---' | `--. ,--' | | ,--------------' | | | | | | ,------------------' | | | | | | | | | lca:ImgbufLSc lcb:ImgbufLSc | (factor 1/10) (factor 1/10) | \ / | `-----------. ,-------------------' | \ / `------------------> scl:ImgbufGSc (factor 1/10)