Re: Applying to a surface the alpha of other

Carlos López González <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <CAF52pzLZJY=Qu6BB8dfMcLsW_vvjSF2ZT16xo4ttKk=dF=G5YQ@mail.gmail.com>
Hi Krzysztof,
thank you for the code sample to perform the bit operations on the
pixel. I already was aware about how to manipulate them, thanks to the
help of this cairo mailing list.

I guess that the reason to sum a/2 is to do a rounded up operation on
the result. Is there any kind of convention on that? If I were done
the code my self I would just do:
 r = (255 * r ) / a;
So I guess that the internals of Cairo does the rounding up operation
when receive a color by its components. Is that true or is there
anything else hidden on that code?

Regarding to my problem, in case I would use direct pixel manipulation
I would do all the operations in that level so instead of set the
alpha result to 0xff000000 I would use the value from the other
surface, that is what I want.

In any case thank you very much.

Regards

2012/10/17 Krzysztof Kosiński <[email protected]>:
> 2012/10/16 Carlos López González <[email protected]>:
>> Hi,
>> unfortunately the proposed solution doesn't work. When a ARGB32 color
>> is painted in a RGB24 surface, the colors are multiplied by the alpha.
>> Say I have a ARGB color:
>> ARGB(0.8, 1.0, 0.5, 0.5)
>> once painted to a RGB24 surface it becomes:
>> RGB(0.8, 0.4, 0.4)
>>
>> Later if I mask back this color thru a 0.6 alpha mask, then it keeps
>> the RGB values and keeps the alpha but the colors are washed out:
>>
>> ARGB(0.6, 0.8, 0.4, 0.4)
>>
>> When my desired result is
>> ARGB(0.6, 1.0, 0.5, 0.5) that is keep the colors of one surface and
>> apply the alpha of other.
>>
>> Any other idea?
>
> For an image surface, you can manipulate the pixels directly with code
> like this:
>
> cairo_surface_flush(s);
> int w = cairo_image_surface_get_width(s);
> int h = cairo_image_surface_get_height(s);
> int stride = cairo_image_surface_get_stride(s);
> char *data = cairo_image_surface_get_data(s);
>
> for (int y = 0; y < h; ++y) {
>   unsigned *row = data + y * stride;
>   for (int x = 0; x < w; ++x) {
>     unsigned px = row[x];
>     unsigned a = (px & 0xff000000) >> 24;
>     unsigned r = (px & 0x00ff0000) >> 16;
>     unsigned g = (px & 0x0000ff00) >> 8;
>     unsigned b = (px & 0x000000ff);
>
>     // un-premultiply color values
>     if (a != 0) {
>       r = (255 * r + a/2) / a;
>       g = (255 * g + a/2) / a;
>       b = (255 * g + a/2) / a;
>     }
>
>     // assemble the resulting pixel from components
>     row[x] = 0xff000000 | (r << 16) | (g << 8) | b;
>   }
> }
>
> cairo_surface_mark_dirty(s);
>
> Note that since Cairo uses premultiplied alpha compositing, you will
> lose a lot of precision precision for low alpha values, which may look
> very ugly. This could be solved with a floating point surface format,
> but Cairo doesn't have one right now.
>
> Regards, Krzysztof



-- 
Carlos
http://synfig.org
-- 
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.