[cairo] RGB Buffer to Cairo Surface

richard boaz ivor.boaz at gmail.com
Mon Apr 14 08:44:26 PDT 2008


To answer my own questions:

In order to use cairo_image_surface_create_for_data(), the caller can
provide an ARGB buffer with a stride that is either 1) aligned perfectly on
(width X 4), or 2) aligned with a stride computed using
cairo_format_stride_for_width().  In the case of 2, it is the end of the row
that should be padded with nothingness.

Also, special care must be taken if the code is expected to run on multiple
platforms since the ARGB buffer is required to be in native endian format.
(imho, this is something that should be shielded from the caller, but there
you go.)

So, to fill an ARGB buffer suitable for use in
cairo_image_surface_create_for_data(), the following snippet will do:

short int    word = 0x0001;
char *byte = (char *) &word;
width = 550;
height = 425;
stride = cairo_image_surface_create_for_data(CAIRO_FORMAT_ARGB24, width)
rgbbuf = calloc(stride * h, sizeof(char));
pos = rgbbuf;
for(i=0;i<height;i++)
{
  A = (some computed alpha_value);
  R = (some computed red_value);
  B = (some computed blue_value);
  G = (some computed green_value);
  colorProb = colorP((float) PIX2USERY(&grL, i));
  for(j=0;j<width;j++)
  {    //      ENDIANTEST ? LITTLE  : BIG
      *pos++ = (byte[0])  ? B       : A;
      *pos++ = (byte[0])  ? G       : R;
      *pos++ = (byte[0])  ? R       : G;
      *pos++ = (byte[0])  ? A       : B;
  }
  // advance to beginning of next row
  pos += (stride/4 - width)*4;
}
cBar = cairo_image_surface_create_for_data(rgbbuf, CAIRO_FORMAT_RGB24,
COLORBW, h, stride);

What I also found, curiously, was that the following code sequence produced
wrong results on LINUX and a crash on MAC:

colorBar = cairo_image_surface_create_for_data(rgbbuf,
            CAIRO_FORMAT_RGB24, width, h, stride);
free(rgbbuf);
cBar2 = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
cr = cairo_create(cBar2);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
cairo_set_source_surface (cr, colorBar, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (colorBar);

Playing around, it seems that the rgbbuf used to create colorBar cannot be
freed until you're done with the colorBar surface itself.  This is not
stated in the documentation, so can cause serious head-scratching.  Anyone
know why the rgbbuf is required to hang around?

Moving the free() to after cairo_surface_destroy() removed this problem:

colorBar = cairo_image_surface_create_for_data(rgbbuf,
            CAIRO_FORMAT_RGB24, width, h, stride);
cBar2 = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
cr = cairo_create(cBar2);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
cairo_set_source_surface (cr, colorBar, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (colorBar);
free(rgbbuf);

And one other thing I discovered was that the PangoCairo routines are not
thread-safe.  Any idea if these are intended to be or will be in a future
version?  If so, which?

I think the documentation re: providing your own ARGB buffer could be made a
little more robust in describing how to properly create an ARGB buffer for
Cairo usage.

Thanks to those who provided pointers, they helped.

cheers,

richard

On Wed, Apr 9, 2008 at 9:39 AM, richard boaz <ivor.boaz at gmail.com> wrote:

> Hi,
>
> I have a problem and a couple of questions related thereto.
>
> The problem: I am trying to convert a programmatically generated RGB
> Buffer to a Cairo surface.  Up till now, I have used GDK to create all my
> graphics (since I started before Cairo came to be, and required display
> within a GUI), but now need to convert to Cairo since I need to generate
> these PDF plots in the background on a server machine without a display.
> All fine and good.
>
> Until I try to understand how to convert my gdk_* routines to their cairo
> equivalents.
>
> In GDK, once I have created and filled my RGB buffer (3-byte color, RGB),
> I call:
>
> rgbbuf = malloc(wL * hL * 3);            // RGB Buffer - 3-byte color -
> RGB
> memset(rgbbuf, 240, wL * hL * 3);        // make the grey background
> pdf(rgbbuf, wL, hL, pdfReq, &gr, perB);  // make the PDF plot
>
> gdk_draw_rgb_image (pmap, gc, sideM, topM, wL, hL, GDK_RGB_DITHER_NONE,
> rgbbuf, wL*3);
>
> After investigating how to do this in Cairo, I came up with this
> replacement:
>
> rgbbuf = malloc(wL * hL * 4);            // RGB Buffer - 4-byte color -
> ARGB
> memset(rgbbuf, 240, wL * hL * 4);        // make the grey background
> pdf(rgbbuf, wL, hL, pdfReq, &gr, perB);  // make the PDF plot
>
> pdfOut = cairo_image_surface_create_for_data(rgbbuf, CAIRO_FORMAT_RGB24,
> wL, hL, wL*4);
> cairo_set_source_surface (cr, pdfOut, sideM, topM);  // cr is previously
> created
> cairo_rectangle (cr, sideM, topM, wL, hL);
> cairo_fill (cr);
> cairo_surface_destroy (pdfOut);
>
> I have modified the RGB buffer size to 4-byte colors (ARGB) and filled it
> according to the cairo_format_t definition for CAIRO_FORMAT_RGB24.
> However, this does not result in a picture that is correct.
>
> My suspicion is that since the row stride is being optimized by Cairo, it
> does not nicely align on a boundary of width*4.  The documentation currently
> states that in order to obtain the proper stride, the routine cairo_format_stride_for_width()
> should be used.  And also says that this is available since 1.6.
>
> My questions:
>
>    1. I do not find a v1.6 of Cairo available from the download site.
>    Is it really true?  The documentation preceeds the release of the software
>    itself?  (wow...)  Or am I missing something?
>    2. If v1.6 isn't yet available, how do I get the optimized stride
>    defined internally by Cairo?
>    3. Anyway, assuming for the moment this routine existed, how would I
>    use it properly?  Meaning, how do I programmatically generate a RGB buffer
>    for display?
>
> My guess at Q3 would be:
>
>    1. obtain the row stride using the cairo routine.
>    2. fill my RGB buffer, row by row, keeping track when i've hit the
>    stride (computed in 1) to advance to the next proper 4-byte RGB location.
>
> This is based, however, on too many assumptions:
>
>    1. I'm assuming that to optimize, Cairo makes the stride bigger
>    (smaller makes no sense to me) than simply width*4 bytes.
>    2. Every row is guaranteed to be the same?  Including the last?
>    3. Where are the empty bytes placed?  at the end of the row or at
>    the beginning?
>    4. Is the stride always a multiple of 4?
>
> More generally, it seems that programmatically generating a RGB buffer for
> conversion to a Cairo surface is not obvious (to me, yet).  Am I wrong about
> this?  Is there a more straightforward way of doing this I haven't yet
> teased from the documentation?  Is there a different way of accessing the
> individual pixels of an RGB buffer I am unaware of that would allow me to
> fill them up individually without having to make wrong assumptions and
> guesses?
>
> Any information to help me out of my pickle would be greatly appreciated.
>
> regards,
>
> richard
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.cairographics.org/archives/cairo/attachments/20080414/632c384a/attachment.html 


More information about the cairo mailing list