pythoncairopycairo

How to change cairo context source color for grayscale images


I am trying to create images in greyscale using Cairo, however, I am having issues controlling the pixel intensity of the pen.

For example, in an RGB color image, I would use this code to paint the background a shade of red with a pixel intensity of 127 in the red channel:

surface = cairo.ImageSurface(cairo.FORMAT_RGB24, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.set_source_rgb(.5, 0, 0)
ctx.rectangle(0, 0, WIDTH, HEIGHT)
ctx.fill()

I can't find any equivalent code for a grayscale image. I can't simply use the alpha channel because then I can't draw circles over rectangles. For example, take the below code snippet, where I would like to have:

surface = cairo.ImageSurface(cairo.FORMAT_A8, WIDTH, HEIGHT)
ctx = cairo.Context(surface)
ctx.set_source_rgba(0, 0, 0, 0.5)
ctx.rectangle(0, 0, WIDTH, HEIGHT)
ctx.fill()
ctx.set_source_rgba(0, 0, 0, 0.0)
ctx.arc(WIDTH//2, HEIGHT//2, r, 0, 2*math.pi)
ctx.fill()

In the above code, the black circle won't appear because its alpha channel is lower than the gray background. How can I fix this?


Solution

  • In the above code, the black circle won't appear because it's alpha channel is lower than the gray background.

    The default operator is OVER, which overlay things. If you have some completely transparent overlay, then this overlay is, well, invisible. So, this is not because of the lower alpha channel. If you had a slightly higher alpha channel, let's say 0.5 and 0.1, the result would be an alpha channel with a value around 0.6 in the resulting image.

    How can I fix this?

    surface = cairo.ImageSurface(cairo.FORMAT_A8, WIDTH, HEIGHT)
    ctx = cairo.Context(surface)
    // I added the following line, but I am not sure about the syntax.
    // In C, this would by cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE);
    ctx.set_operator(cairo.OPERATOR_SOURCE)
    ctx.set_source_rgba(0, 0, 0, 0.5)
    ctx.rectangle(0, 0, WIDTH, HEIGHT)
    ctx.fill()
    ctx.set_source_rgba(0, 0, 0, 0.0)
    ctx.arc(WIDTH//2, HEIGHT//2, r, 0, 2*math.pi)
    ctx.fill()