[cairo] Repeating gradient patterns

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Sat Aug 23 13:58:25 PDT 2008


J. Ali Harlow wrote:
> Guys,
> 
> I'm trying to use repeating gradient patterns to draw the background 
> for a matrix of 27x27 cells. Cells are labelled with two colours. I 
> want to show these by placing the first colour in the top-left corner 
> and the second colour in the bottom-right corner. The obvious way to do 
> that in cairo seems to be to use a gradient pattern. However, I have 
> two problems:
> 
> * The period of the repeating patterns seems to be too small. If you 
> just run your eye from the top-left cell down the diagonal to the 
> bottom-right this is quite obvious.

This is a result of a rounding error, and a regression with the change
from 16.16 to 24.8 bits fixed point math - the rounding error was much
smaller before.

(The cairo_pattern_create_linear(0,0,1/27.0,1/27.0) call converts the
coordinates to fixed point before storing them in the pattern. As a result,
the 1/27.0 becomes 9/256 - which is about 1/28.4, and indeed we have about
one and a half repetitions of the pattern too many along the diagonal.)

> * Half the cells are drawn as expected with the colour stops in the 
> corners. The other half have the colour stops in the middle.

This is expected. The pattern gets repeated diagonally.

+----+----+----+----+
|       .'        .'
|     .'        .'
+    +    +    +    +
|  .'        .'
|.'        .'
+    +    +    +    +

> I attach a test problem to show what I am doing as well as it's output 
> (png). Any pointers as to what I'm doing wrong would be much 
> appreciated.

You have to translate the pattern. The way that's easiest to understand is
probably this:

    pattern=bg_from_label(label);
    cairo_save(cr);
    cairo_translate(cr, i/27.0, j/27.0);
    cairo_set_source(cr,pattern);
    cairo_pattern_destroy(pattern);
    cairo_rectangle(cr,0,0,1/27.0,1/27.0);
    cairo_fill(cr);
    cairo_restore(cr);

i.e. set up the cairo transformation so that the origin is the top left
corner of the rectangle to be drawn, /then/ set the pattern source.

You won't need the CAIRO_EXTEND_REPEAT then.

HTH,

Bertram

P.S. You can also set the pattern's transformation matrix:

cairo_pattern_t *bg_from_label(int label)
{
    cairo_pattern_t *pattern;
    pattern=cairo_pattern_create_linear(0, 0, 1, 1);
    // set color stops
    return pattern; // oops, this is missing in the original
}

// ...
    cairo_matrix_t transform;
    label=get_label(i,j);
    pattern=bg_from_label(label);

    cairo_matrix_init_translate(&transform, -i, -j);
    cairo_matrix_scale(&transform, 27.0, 27.0);
    cairo_pattern_set_matrix(pattern, &transform);

    cairo_set_source(cr,pattern);
    cairo_pattern_destroy(pattern);
    cairo_rectangle(cr, i/27.0, j/27.0, 1/27.0, 1/27.0);
    cairo_fill(cr);
// ...


More information about the cairo mailing list