Re: Applying to a surface the alpha of other
Krzysztof Kosiński <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <CAFLw2WS_DMphgH=aBVwKgTEBbDh+=kgxdvYYOfBOYr_OuSEFwA@mail.gmail.com> |
2012/10/17 Carlos López González <[email protected]>: > 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; This division would round up if the code was: r = (255 * r + a) / a; Adding a/2 rounds to the nearest value, which is most likely what you want. > 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? AFAIK Cairo rounds to the nearest integer value, e.g. color_integer = round(color_double * 255) > 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. If the other surface has exactly the same dimensions and stride, you can just obtain a second data pointer: cairo_surface_flush(s); cairo_surface_flush(as); 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); char *adata = cairo_image_surface_get_data(as); for (int y = 0; y < h; ++y) { unsigned *row = data + y * stride; unsigned *arow = adata + 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] = (arow[x] & 0xff000000) | (r << 16) | (g << 8) | b; } } cairo_surface_mark_dirty(s); However, if the alpha surface can have different dimensions, the code gets complicated and it's easier to just use a mask operation. cairo_surface_t *result = cairo_surface_create_similar( s, CAIRO_CONTENT_COLOR_ALPHA, cairo_image_surface_get_width(s), cairo_image_surface_get_height(s)); cairo_t *cr = cairo_create(result); // you might need to pass different x and y values // to the calls below to align the alpha and color surfaces properly cairo_set_source_surface(cr, s, 0, 0); cairo_mask_surface(cr, as, 0, 0); cairo_paint(cr); cairo_destroy(cr); Regards, Krzysztof -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo