Re: Direct manipulation and write to PNG

Andrea Canciani <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CAN_5=BASaRuTcY5ZYRoVP0omKmYmSCyAZkaq5BO3Brd4c9HFQA@mail.gmail.com>
On Mon, Jul 9, 2012 at 9:16 PM, Carlos López González
<[email protected]> 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
> [email protected]
> http://lists.cairographics.org/mailman/listinfo/cairo
-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.