[cairo] CAIRO_FORMAT_ARGB32 format [ was: Re: "data" in cairo_image_surface_get_data ()

Nguyen Vu Hung vuhung16plus at gmail.com
Thu Nov 29 19:58:34 PST 2007


2007/11/29, Baz <brian.ewins at gmail.com>:
> > pix.data = cairo_image_surface_get_data (surf) + 1;
> >
> > syntax valid?
>
> When I say 'roughly' I mean I'm not posting tested code, I'm just
> outlining the steps. But yes you can do stuff like that.
>
> http://www.google.com/search?q=pointer+arithmetic
>
> BTW you use pointer arithmetic in your own code: "ppixel = data + i * wpl;"
>
Thanks. Google really helped:
http://www.eskimo.com/~scs/cclass/notes/sx10b.html

> >
> > I'ved tried to convert back PIX to cairo's data format. In the
> > following code, I get PIX's data byte by byte, and set it to cairo's
> > data pointer. The code runs fine, but when I write cairo's *data to a
> > PNG file, the PNG output is weird.
> >
> > One more point, In the function
> >
> > cairo_image_surface_create_for_data
> >
> > do I have to set the last paramater ( stride ) to wpl * 4 or w * 4?
>
> Answered below.
>
> >
> >     U32    *data, *ppixel;
> >
> >     data = (U32*) pixGetData(pixCut); // PIX->data format
> >
> >     U32 wpl = pixGetWpl(pixCut); // word per line
> >     U32 w = pixGetWidth(pixCut); // pix width
> >     U32 h = pixGetHeight(pixCut); // pix height
> >
> >     cairo_surface_t* tmp_surface;
> >     unsigned char * data_cairo;
>
> You've missed out a line that allocates this buffer? Its hard to tell
> what you intended the stride to be without that.
>
Yes, I missed a copy:

data_cairo = (unsigned char *) malloc(w * 4 * h );

> BTW the point of using create_for_data was that to do the
> buffer-sharing trick you need to have allocated memory which extends
> beyond that needed for either PIX or RGB24, and that destroying the
> image surface should not free the buffer since its not owned by the
> image surface. If you're not going to try to share the buffer, you can
> just use cairo_image_surface_create, it's simpler.
I am not going to share the buffers between PIX and cairo.
I just want to "convert" PIX->data to cairo's data, create a cairo
surface with that data, then use some cairo APIs with that surface.

>
> >
> >     int  i, j, k;
> >
> >     unsigned char* rowptr;
> >
> >     for (i = 0; i < h; i++) {
> >       ppixel = data + i * wpl;
> >       rowptr = &data_cairo[i * w * 4];
>
> (w * 4) here should be whatever cairo_image_surface_get_stride()
> returns. If you used cairo_image_surface_create before the loop, you
> would call cairo_image_surface_get_stride() to find this out, if you
> used cairo_image_surface_create_for_data passing in (wpl * 4) as
> stride as you do below, you know the value is going to be (wpl * 4).
> In either case you might as well declare
>
> int stride = wpl * 4; and use it in both places.
Where should I use? ( :D, sorry for a dumb question ).

>
> >       for ( j = k = 0; j < w ; j++) {
> >         rowptr[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
> >         rowptr[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
> >         rowptr[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
> >         rowptr[k++] = 0xff; // alpha,
> >         ppixel++;
>
> I assume you're only running this on a little-endian platform? You're
> writing the data byte-by-byte, instead of word-by-word. See the
> previous post.
>
Yes. My CPU is an Intel Pentium 4.

> Just to spell things out - this is what the previous post implied:
>      for (i = 0; i < h; i++) {
>        ppixel = data + i * wpl;
>        rowptr = (U32 *)(data_cairo + i * w * 4);
>        for ( j = 0; j < w ; j++) {
>            rowptr[j] = ppixel[j] >> 8;
>        }
>     }
>
Did you missed something?
data_cairo, rowptr are pointers of U8*,  but you've casted it to (U32 *)?

rowptr = (U32 *)(data_cairo + i * w * 4);

Or did you mean I have to use

U32* rowptr instead of U8* rowptr?

 rowptr[j] = ppixel[j] >> 8; shifts ppixel 8 bits to the right? But
can I make sure that the the last 8 bits ( alpha chanel ) are OK?

When I did so ( declare U32 *rowptr; and loop ), the got an output PNG
file that has all of its pixels are black :).

Is that has something doing with CAIRO_FORMAT_RGB24 in
cairo_image_surface_create_for_data ?


> ... if you go back and reread what I said in the previous mail you
> should see that this loop can be replaced with two memcpy()s, one for
> the big-endian case and one for the little-endian case.
>
It is somewhat tricky and for me, I found it is hard to understand. I
also want to improve the readability of my code so that the next
maintainer will read it easy.

Here is my code:

		    U32 wpl = pixGetWpl(pixCut);
		    U32 w = pixGetWidth(pixCut);
		    U32 h = pixGetHeight(pixCut);

		    cairo_surface_t* tmp_surface;
		    U32* data_cairo;

		    int stride = wpl * 4;

		    data_cairo = (unsigned char *) malloc(w * 4 * h );

		    unsigned char* rowptr;

		    for (i = 0; i < h; i++) {
		      ppixel = data + i * wpl;
		      rowptr = (U8 *) (data_cairo + i * w * 4);
		      for ( j = 0; j < w; j++) {
			rowptr[j] = ppixel[j] >> 8;
		      }
		    }

		    tmp_surface = cairo_image_surface_create_for_data (data_cairo,
								       CAIRO_FORMAT_RGB24,
								       w, h,
								       stride);


-- 
Best Regards,
Nguyen Hung Vu
vuhung16plus{remove}@gmail.dot.com
An inquisitive look at Harajuku
http://www.flickr.com/photos/vuhung/sets/72157600109218238/


More information about the cairo mailing list