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
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.