Re: Applying to a surface the alpha of other
Krzysztof Kosiński <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <CAFLw2WTyROhbSKZuv2gp4Xdh0bfrs+fArJ8Kycv2F1TFY7JfwQ@mail.gmail.com> |
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 -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo