3
votes

I am trying to draw a png image, the contents of which I have in memory in an ARGB32 format, using C++ Cairo and Gtk on Ubuntu.

First, I create a GtkDrawingArea, then on its expose-event I draw a solid blue background with a red line from top left to bottom right, then I create a surface and try to draw it onto the drawing area. Here's my expose-event callback:

unsigned char *pCairoBuf = ...

....

gboolean OnDrawingAreaExposeEvent(GtkWidget *pWidget, GdkEventExpose *pEvent, gpointer data)
{
    cairo_t *cr = gdk_cairo_create(pWidget->window);

    cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
    cairo_rectangle(cr, 0.0, 0.0, pEvent->area.width, pEvent->area.height);
    cairo_fill(cr);

    cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
    cairo_set_line_width(cr, 10.0);
    cairo_move_to(cr, 0.0, 0.0);
    cairo_line_to(cr, pEvent->area.width, pEvent->area.height);
    cairo_stroke(cr);

    // Use the existing buffer pCairoBuf that has (iRenderWidth * iRenderHeight * 4) bytes, 4 bytes per pixel for ARGB32 and zero row padding   
    cairo_surface_t *pSurface = cairo_image_surface_create_for_data(pCairoBuf, CAIRO_FORMAT_ARGB32, iRenderWidth, iRenderHeight, (iRenderWidth * 4));

    cairo_set_source_surface(cr, pSurface, 0.0, 0.0);
    cairo_paint(cr);

    cairo_destroy(cr);

    return TRUE;
}

The drawing area and the image are both 244x278 pixels. The image is an image of Smokey the Bear's head and is transparent around his head:

enter image description here

And I expect the final result to look like this:

enter image description here

But it ends up looking like this:

enter image description here

I did not add the code that shows how I got the data buffer pCairoBuf because I figured it would only cloud the issue, but perhaps I'm wrong? I figured that there's something else I'm doing wrong having to do with cairo surfaces, etc. that would explain the difference between what I'm expecting and what I'm getting.

Thanks in advance for any help!

2
Is the data in pCairoBuf alpha-premultiplied?andlabs
Yes, thank you @andlabs for asking. Just to clarify, my interpretation of "alpha-premultiplied" is that if the original pixel is, say, a nice shade of blue (0, 148, 255) and the alpha is 27.45%, then the full ARGB would be 0x46002946, am I understanding that right?user2062604

2 Answers

1
votes

As a guess, not having used any of those libraries, I'd say your alpha channel's uniform across your image and the rendering's applying this also to the parts of the image you'd like non-transparent. Try only applying the alpha channel to those pixels which you'd like to be transparent.

0
votes

I figured it out. When I was filling in the ARGB32 data in the buffer that I pass to cairo_image_surface_create_for_data(), I was filling in the bytes in that order, A, R, G, B. As an experiment I reversed the order and filled in the bytes B, G, R, A, and it worked perfectly.