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