Fwd: [cairo] how to use alpha blending by cairo?

Rajeev rajeev.cse at gmail.com
Thu Jul 13 01:23:07 PDT 2006


---------- Forwarded message ----------
From: Rajeev <rajeev.cse at gmail.com>
Date: Jul 13, 2006 1:52 PM
Subject: Re: [cairo] how to use alpha blending by cairo?
To: Carl Worth <cworth at cworth.org>


Hi carl and everyone in cairo family,
am the guy hacked Evolution by improving the look and feel of
evolution calendar with cairo and cairo solved me in great extents.,
now currently am looking for a solution for displaying alpha images
with cairo.
so the code flows like this.

static void
draw_pixmap (HTMLPainter *painter,
             GdkPixbuf *pixbuf,
             gint x, gint y,
             gint scale_width, gint scale_height,
             const GdkColor *color)
{
        GdkRectangle clip, image, paint;
        HTMLGdkPainter *gdk_painter;
        GdkPixbuf *tmp_pixbuf;
        guint n_channels;
        gint orig_width;
        gint orig_height;
        gint bilinear;
        cairo_t *cr;

        gdk_painter = HTML_GDK_PAINTER (painter);
        cr = gdk_cairo_create (gdk_painter->pixmap);

        orig_width = gdk_pixbuf_get_width (pixbuf);
        orig_height = gdk_pixbuf_get_height (pixbuf);

        if (scale_width < 0)
                scale_width = orig_width;
        if (scale_height < 0)
                scale_height = orig_height;

        image.x = x;
        image.y = y;
        image.width  = scale_width;
        image.height = scale_height;

        clip.x = gdk_painter->x1;
        clip.width = gdk_painter->x2 - gdk_painter->x1;
        clip.y = gdk_painter->y1;
        clip.height = gdk_painter->y2 - gdk_painter->y1;

        if (!gdk_rectangle_intersect (&clip, &image, &paint))
            return;

        if (scale_width == orig_width && scale_height == orig_height && color
== NULL) {
                gdk_draw_pixbuf (gdk_painter->pixmap, NULL, pixbuf,
                                 paint.x - image.x,
                                 paint.y - image.y,
                                 paint.x - clip.x,
                                 paint.y - clip.y,
                                 paint.width,
                                 paint.height,
                                 GDK_RGB_DITHER_NORMAL,
                                 paint.x, paint.y);

                return;
        }


        tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
                                     gdk_pixbuf_get_has_alpha (pixbuf),
                                     gdk_pixbuf_get_bits_per_sample (pixbuf),
                                     paint.width, paint.height);

        gdk_pixbuf_fill (tmp_pixbuf, 0xff000000);

        if (tmp_pixbuf == NULL)
                return;

        bilinear = !((scale_width == 1) && (scale_height == 1));

        gdk_pixbuf_composite (pixbuf, tmp_pixbuf,
                              0,
                              0,
                              paint.width, paint.height,
                              (double)-(paint.x - image.x),
                              (double)-(paint.y - image.y),
                              (gdouble) scale_width/ (gdouble) orig_width,
                              (gdouble) scale_height/ (gdouble) orig_height,
                              bilinear ? GDK_INTERP_BILINEAR :
GDK_INTERP_NEAREST,
                              255);

        if (color != NULL) {
                guchar *p, *q;
                guint i, j;

                n_channels = gdk_pixbuf_get_n_channels (tmp_pixbuf);
                p = q = gdk_pixbuf_get_pixels (tmp_pixbuf);
                for (i = 0; i < paint.height; i++) {
                        p = q;

                        for (j = 0; j < paint.width; j++) {
                                gint r, g, b, a;

                                if (n_channels > 3)
                                        a = p[3];
                                else
                                        a = 0xff;

                                r = (a * p[0] + color->red) >> 9;
                                g = (a * p[1] + color->green) >> 9;
                                b = (a * p[2] + color->blue) >> 9;

                                p[0] = r;
                                p[1] = g;
                                p[2] = b;

                                if (n_channels > 3)
                                        p[3] = (a + 127) / 2;

                                p += n_channels;
                        }

                        q += gdk_pixbuf_get_rowstride (tmp_pixbuf);
                }
        }

        gdk_draw_pixbuf (gdk_painter->pixmap, NULL, tmp_pixbuf,
                         0,
                         0,
                         paint.x - clip.x,
                         paint.y - clip.y,
                         paint.width,
                         paint.height,
                         GDK_RGB_DITHER_NORMAL,
                         paint.x, paint.y);
        g_object_unref (tmp_pixbuf);
}

Now is there a work around for adding all channels(say, an alpha
channel) of an image with cairo ?? The current code lacks displaying
alpha layered images :(  - as it displays them, as though there is no
alpha channel and cairo seems to give no options for image dithering /
bilinear filtering etc,. which Gdk offers Am looking for composite
translucent image rendering with cairo.
I tried doing this, adding every detail of channels etc to the pixbuf
and drawing it with cairo but still dint succeed, for instance,

static void
draw_pixmap (HTMLPainter *painter,
             GdkPixbuf *pixbuf,
             gint x, gint y,
             gint scale_width, gint scale_height,
             const GdkColor *color)
{
        GdkRectangle clip, image, paint;
        HTMLGdkPainter *gdk_painter;
        GdkPixbuf *tmp_pixbuf;
        guint n_channels;
        gint orig_width;
        gint orig_height;
        gint bilinear;
        cairo_t *cr;

        gdk_painter = HTML_GDK_PAINTER (painter);
        cr = gdk_cairo_create (gdk_painter->pixmap);

        orig_width = gdk_pixbuf_get_width (pixbuf);
        orig_height = gdk_pixbuf_get_height (pixbuf);

        if (scale_width < 0)
                scale_width = orig_width;
        if (scale_height < 0)
                scale_height = orig_height;

        image.x = x;
        image.y = y;
        image.width  = scale_width;
        image.height = scale_height;

        clip.x = gdk_painter->x1;
        clip.width = gdk_painter->x2 - gdk_painter->x1;
        clip.y = gdk_painter->y1;
        clip.height = gdk_painter->y2 - gdk_painter->y1;

        if (!gdk_rectangle_intersect (&clip, &image, &paint))
            return;

        if (scale_width == orig_width && scale_height == orig_height && color
== NULL) {
/*              gdk_draw_pixbuf (gdk_painter->pixmap, NULL, pixbuf,
                                 paint.x - image.x,
                                 paint.y - image.y,
                                 paint.x - clip.x,
                                 paint.y - clip.y,
                                 paint.width,
                                 paint.height,
                                 GDK_RGB_DITHER_NORMAL,
                                 paint.x, paint.y);
*/

                gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
                cairo_paint(cr);
                cairo_destroy (cr);
                return;
        }


        tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
                                     gdk_pixbuf_get_has_alpha (pixbuf),
                                     gdk_pixbuf_get_bits_per_sample (pixbuf),
                                     paint.width, paint.height);

        gdk_pixbuf_fill (tmp_pixbuf, 0xff000000);

        if (tmp_pixbuf == NULL)
                return;

        /*
         * FIXME this is a hack to work around a gdk-pixbuf bug
         * it could be removed when
         * http://bugzilla.ximian.com/show_bug.cgi?id=12968
         * is fixed.
         */
        bilinear = !((scale_width == 1) && (scale_height == 1));

        gdk_pixbuf_composite (pixbuf, tmp_pixbuf,
                              0,
                              0,
                              paint.width, paint.height,
                              (double)-(paint.x - image.x),
                              (double)-(paint.y - image.y),
                              (gdouble) scale_width/ (gdouble) orig_width,
                              (gdouble) scale_height/ (gdouble) orig_height,
                              bilinear ? GDK_INTERP_BILINEAR :
GDK_INTERP_NEAREST,
                              255);

        if (color != NULL) {
                guchar *p, *q;
                guint i, j;

                n_channels = gdk_pixbuf_get_n_channels (tmp_pixbuf);
                p = q = gdk_pixbuf_get_pixels (tmp_pixbuf);
                for (i = 0; i < paint.height; i++) {
                        p = q;

                        for (j = 0; j < paint.width; j++) {
                                gint r, g, b, a;

                                if (n_channels > 3)
                                        a = p[3];
                                else
                                        a = 0xff;

                                r = (a * p[0] + color->red) >> 9;
                                g = (a * p[1] + color->green) >> 9;
                                b = (a * p[2] + color->blue) >> 9;

                                p[0] = r;
                                p[1] = g;
                                p[2] = b;

                                if (n_channels > 3)
                                        p[3] = (a + 127) / 2;

                                p += n_channels;
                        }

                        q += gdk_pixbuf_get_rowstride (tmp_pixbuf);
                }
        }

/*      gdk_draw_pixbuf (gdk_painter->pixmap, NULL, tmp_pixbuf,
                         0,
                         0,
                         paint.x - clip.x,
                         paint.y - clip.y,
                         paint.width,
                         paint.height,
                         GDK_RGB_DITHER_NORMAL,
                         paint.x, paint.y);
        g_object_unref (tmp_pixbuf);*/

        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
        cairo_paint(cr);
        cairo_destroy (cr);

}


On 7/11/06, Carl Worth <cworth at cworth.org> wrote:
> On Fri, 30 Jun 2006 18:06:12 +0800, "lao wb" wrote:
> > Thanks a lot, Kristian, you are right! gdk_pixbuf_new_from_file helps to
> > keep the alpha channel from being ruined.
> > however my job not accomplished yet, now I can use gdk_pixbuf_composite do
> > an overall alpha blending either by cairo_paint or gdk_draw_pixbuf .  But
> > precisely what I need is to make alpha blending pixel by pixel, is there any
> > api like gdk_pixbuf_composite without an overall_alpha parameter? Can cairo
> > help to render an rgba pixbuf as my wish?
>
> The cairo_paint() function (as well as any other cairo drawing
> function) will always respect any alpha values you have in your source
> pattern. If you are using cairo_paint() and have not changed the
> default cairo operator from CAIRO_OPERATOR_OVER, then I would suspect
> that the problem lies in the alpha values of your source surface.
>
> -Carl
>
>
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://cairographics.org/cgi-bin/mailman/listinfo/cairo
>
>
>


--
--->>>Rajeev<<<----


-- 
--->>>Rajeev<<<----


More information about the cairo mailing list