[cairo] X11 image data rendering problems (Xrender ?)

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Sun Mar 23 15:06:54 PDT 2008


Julien Danjou wrote:
> Hi people,
> 
> Well, I've been using cairo for some time and had no problem. Until now.
> 
> I used to render PNG data onto Xlib Drawable using the
> cairo_image_surface_create_from_png().
> Some others pictures were rendered using
> cairo_image_surface_create_for_data().
> 
> Everything was fine.
> 
> Now, I dropped the usage of cairo_image_surface_create_from_png() since
> I heard that is was not the Good Way To Go anyway, and use only
> cairo_image_surface_create_for_data() for all types of data file I
> get. FWIW, I use Imlib2 to get image data in ARGB32 format.

Imlib2's ARGB32 format is, however, incompatible with cairo's, because
cairo expects pre-multiplied alpha images. (This is mentioned in passing
at
  http://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t
but I don't know whether the docs explain this in detail.)

You can use imlib2 to do the pre-multiplication:

    /* in: image = source imlib image with alpha */

    imlib_context_set_image(image);
    int w = imlib_image_get_width();
    int h = imlib_image_get_height();

    /* create temporary image */
    Imlib_Image premul = imlib_create_image(w, h);
    /* FIXME: add error handling */

    /* fill with opaque black */
    imlib_context_set_image(premul);
    imlib_context_set_color(0, 0, 0, 255);
    imlib_image_fill_rectangle(0, 0, w, h);

    /* blend source image on top - in effect this multiplies the
     * rgb values by alpha */
    imlib_blend_image_onto_image(image, 0, 0, 0, w, h, 0, 0, w, h);
    /* and use the alpha channel of the source image */
    imlib_image_copy_alpha_to_image(image, 0, 0);

    /* now pass the result to cairo */
    cairo_surface_t *result = cairo_image_surface_create_for_data(
        (void *) imlib_image_get_data_for_reading_only(),
        CAIRO_FORMAT_ARGB32, w, h, sizeof(DATA32) * w);

    /* out: result = cairo surface */

You can use something like

    static void free_imlib_image(void *img)
    {
        Imlib_Image save = imlib_context_get_image();
        imlib_context_set_image(img);
        imlib_free_image();
        imlib_context_set_image(save);
    }

    [...]
    static cairo_user_data_key_t free_premul_image_key;
    cairo_surface_set_user_data(
        result, &free_premul_image_key, (void *) prepare, free_imlib_image);

to automatically free the premultiplied data along with the cairo surface.

(This assumes that Imlib_Image is a pointer. It is, but that's not
documented.)

HTH,

Bertram


More information about the cairo mailing list