[cairo] Applying to a surface the alpha of other
Krzysztof Kosiński
tweenk.pl at gmail.com
Tue Oct 16 15:48:05 PDT 2012
2012/10/16 Carlos López González <genetita at gmail.com>:
> 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
More information about the cairo
mailing list