[cairo] CAIRO_FORMAT_ARGB32 format [ was: Re: "data" in cairo_image_surface_get_data ()
brian.ewins at gmail.com
Wed Nov 28 03:16:11 PST 2007
On Nov 28, 2007 6:07 AM, Nguyen Vu Hung <vuhung16plus at gmail.com> wrote:
> Hi all,
> Can anyone explain how 8 bits ( one bytes ) are stored in a cairo's
> surface under CAIRO_FORMAT_ARGB32 format?
> For example, when I get data from a surface like:
> unsigned char *data_cairo = cairo_image_surface_get_data (m_pSurface);
> then, how to get A, R, G, B quantities inside *data_cairo?
PNG uses an RGBA data structure held in 4 octets, the first octet
containing R, the second, G, and so on. The order in which the octets
appear is defined by the spec, not the platform. Because there is a
defined octet order, you read the pixels octet-by-octet.
Cairo's ARGB32 format, by contrast, is held in a 32-bit structure,
with the *highest* 8 bits containing alpha, the next 8 bits containing
red, and so on. Whether the highest 8 bits are the first or not is an
endianness issue - it depends on the platform. Because the structure
is native endian, you read the pixels word-by-word.
Now read the PIX header, it says:
* (4) For 24-bit color images, use 32 bpp data, leaving
* the fourth byte unused. Within each 4 byte pixel, the
* colors are ordered from MSB to LSB, as follows:
* | MSB | 2nd MSB | 3rd MSB | LSB |
* red green blue unused
* 0 1 2 3 (big-endian)
* 3 2 1 0 (little-endian)
Notice that this is the same as cairo, not PNG - data is ordered
MSB->LSB, not left->right. Secondly, this, and the pngio.c you link
to, show that PIX doesn't use alpha (it strips it out of the png
stream). So PIX is is a 24-bit RGB format, like cairo's RGB24 (not
ARGB32). However, PIX leaves the LSB unused, whereas cairo's RGB24
leaves the MSB unused (see
So, converting between cairo's RGB24 and PIX, pixel by pixel, is just
(pixel32 >> 8), and from PIX to RGB24 is (pixel32 << 8).
You can share buffers between cairo and leptonica directly though,
with a bit of trickery. Consider a 2-pixel image, in RGB24 format
(choosing some rgb values to make this clear)
on a big-endian platform: (xrgbxrgb)
0x00 0xa1 0xa2 0xa3 0x00 0xa4 0xa5 0xa6
on a little-endian platform: (bgrxbgrx)
0xa3 0xa2 0xa1 0x00 0xa6 0xa5 0xa4 0x00
now here's that data in PIX format:
on a big-endian platform: (rgbxrgbx)
0xa1 0xa2 0xa3 0x00 0xa4 0xa5 0xa6 0x00
on a little-endian platform: (xbgrxbgr)
0x00 0xa3 0xa2 0xa1 0x00 0xa6 0xa5 0xa4
It should be obvious what the trick is now. Add 0x00 padding to the
ends of the buffer, then if the cairo image is at 'c', the PIX image
is at 'c + 1' on big-endian systems, and at 'c - 1' on little-endian
systems. Of course, YMMV, one of the libs will not be accessing
word-aligned data. You could use the same trick to copy the data from
one buffer to another as well, avoiding individual bit shifts.
So, assuming you are using a buffer which has padding around it as
above (ie you've allocated it yourself and used
cairo_image_surface_create_for_data), setting up a PIX structure for
an RGB24 buffer is something like
pix.w = cairo_image_surface_get_width (surf);
pix.h = cairo_image_surface_get_height (surf);
pix.d = 8;
pix.wpl = cairo_image_surface_get_stride (surf) / 4;
pix.data = cairo_image_surface_get_data (surf) + 1; // big-endian;
little endian would have -1 here.
> # Baz said it is a endianness thingy but I don't fully understand it!
Yeah, me too. My head hurts thinking about endianness. You should
check my working.
> Best Regards,
> Nguyen Hung Vu
> An inquisitive look at Harajuku
> cairo mailing list
> cairo at cairographics.org
More information about the cairo