8

I'm using a radial gradient in Cairo, but I'm not getting the expected results. The radial gradient I'm getting is much less fuzzy than I'd expect and I can't seem to fiddle with the color stops in order to get the desired results. Here is the code:

cairo_pattern_t *pat;

pat = cairo_pattern_create_radial(100.0, 100.0, 0.0, 100.0, 100.0, 20.0);
cairo_pattern_add_color_stop_rgba(pat, 0, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 0);

Here is an image of what I'm talking about.

radial gradient

Q2Ftb3k
  • 678
  • 3
  • 9
  • 18
  • How did you create the 'What I want' image? – Uli Schlachter Jul 06 '12 at 17:15
  • I went into Pixelmator and used a brush that with 0% hardness set. – Q2Ftb3k Jul 06 '12 at 17:37
  • The cairo result is using interpolating linearily. Each pixel further away from the center gets 2 shades of gray lighter. The 'What I want'-result isn't linear. If you want me to guess, the Pixelmator result is gamma corrected, which works around the human vision. – Uli Schlachter Jul 06 '12 at 21:23
  • Is there a possible solution other than placing colour stops in a non-linear fashion programmatically? – Q2Ftb3k Jul 06 '12 at 23:04

1 Answers1

6

The #cairo IRC channel suggested (Thanks Company!) to use cairo_mask() instead of cairo_paint() to draw the gradient. That results in a squared instead of linear progression.

I did the following in lua. Sorry for the language, but it's easier to prototype something. This maps 1:1 to the C API and shouldn't be hard to translate:

cairo = require("lgi").cairo

s = cairo.ImageSurface(cairo.Format.ARGB32, 200, 100)
c = cairo.Context(s)
c:set_source_rgb(1, 1, 1)
c:paint()

p = cairo.Pattern.create_radial(50, 50, 0, 50, 50, 20)
p:add_color_stop_rgba(0, 0, 0, 0, 1)
p:add_color_stop_rgba(1, 0, 0, 0, 0)

c:save()
c:rectangle(0, 0, 100, 100)
c:clip()
c.source = p
c:paint()
c:restore()

p = cairo.Pattern.create_radial(50, 50, 2, 50, 50, 25)
p:add_color_stop_rgba(0, 0, 0, 0, 1)
p:add_color_stop_rgba(1, 0, 0, 0, 0)

c:translate(100, 0)
c:save()
c:rectangle(0, 0, 100, 100)
c:clip()
c.source = p
c:mask(p)
c:restore()

s:write_to_png("test.png")

To me, the second circle (The one that was cairo_mask()'d with a black source) looks a lot more like what you want:

The image that the lua code produces

Uli Schlachter
  • 9,337
  • 1
  • 23
  • 39