[cairo] Direct manipulation and write to PNG

Andrea Canciani ranma42 at gmail.com
Mon Jul 9 12:41:42 PDT 2012


On Mon, Jul 9, 2012 at 9:16 PM, Carlos López González
<genetita at gmail.com> wrote:
> Hi!
> I'm working on doing direct manipulation of a image surface data and
> I'm obtaining weird results when writing to png.
>
> I want to obtain a image like this:
> http://imagebin.org/220100
>
> but I get this:
> http://imagebin.org/220098
>
> To create the image I use the following code:
>
> /////////////////////////////////////////////////
> #include <cairo.h>
>
> int main (int argc, char *argv[])
> {
>         cairo_surface_t *surface;
>         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 480, 270);
>         cairo_surface_flush(surface);
>
>         unsigned char* data;
>         unsigned char*position;
>         int w, h, stride;
>         data=cairo_image_surface_get_data(surface);
>         w=cairo_image_surface_get_width(surface);
>         h=cairo_image_surface_get_height(surface);
>         stride=cairo_image_surface_get_stride(surface);
>         unsigned char a, r, g, b;
>         int x, y;
>         a=255;
>         r=178;
>         g=55;
>         b=55;
>         for(y=0; y<h; y++)
>         {
>                 for(x=0; x<w*4; x+=4)
>                 {
>                         position= (unsigned char*)(((char*)data)+y*stride);
>                         position[x]=a;
>                         position[x+1]=r;
>                         position[x+2]=g;
>                         position[x+3]=b;

This is wrong as it won't work on little-endian machines.
You should access pixels as uint32_t pointers:

                         uint32_t *okposition=
(uint32_t*)(((char*)data)+y*stride);
                         okposition[x/4]=(a << 24) | (r << 16) | (g << 8) | b;

>                 }
>         }
>         cairo_surface_mark_dirty(surface);
>
>         cairo_surface_write_to_png(surface, "image.png");
>
>         cairo_surface_destroy(surface);
>
>         return 0;
> }
> //////////////////////////////////////////////
>
> I compiled it with:
>
> $ gcc -o cairo4 `pkg-config --cflags --libs gtk+-2.0` cairo4.c
>
> The png image file has the color somehow twisted and modified:
> a=56
> r=255
> g=9
> b=88
>
>  I've re-checked that the written bytes are fine on the memory but I
> don't get the right results on the png file.
> Can anyone help me to let me know what I'm doing wrong? Or maybe it is
> something related to png backend?

The issue was simply that you were assuming a different byte order
than the one used on your machine.
To avoid having these issues, always access whole pixels.
Some documentation about pixel formats can be found here:
http://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t
As you can see, ARGB32 is a 32-bits format stored native-endian.

I hope this helps, but don't hesitate to ask for more clarification if
it is not sufficient.

Andrea

>
> Thank you very much!!
> --
> Carlos
> http://synfig.org
> --
> cairo mailing list
> cairo at cairographics.org
> http://lists.cairographics.org/mailman/listinfo/cairo


More information about the cairo mailing list