[cairo] Problem with degenerate lines

Krzysztof Kosiński tweenk.pl at gmail.com
Sat Nov 6 13:35:43 PDT 2010


2010/11/6 Steve Harrington <steven.harrington at comcast.net>:
> Searching the archives I found this method of drawing a single point:
>      cairo_move_to( cr, x, y );
>      cairo_close_path( cr );
>      cairo_stroke( cr );
>
> Which works fine in some cases.  However, the following code (in the expose
> handler) doesn't work as expected.  See the comments in the code for the
> results and times needed to draw them.  BTW is also seems to show a fairly
> gross inefficiency somewhere in the drawing chain.

Nothing gets drawn because you need to set a square line cap.
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);

The drawing will be inefficient because you need to add 0.5, not 1 to
each coordinate. Otherwise you end up drawing "in between" pixels,
which turns off optimizations in Cairo for pixel-aligned drawing. It's
better to do something like this, which also avoids computing the
stroke.

cairo_rectangle(cr, i, j, i+1, j+j);
cairo_fill(cr);

For this kind of per-pixel drawing, instead of using Cairo drawing
routines, you would be better off writing the gradient to an image
surface, and then blitting it to the screen in one go. You can also
use OpenMP to parallelize it.

cairo_surface_t *grad =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, Allocation.width,
Allocation.height);
int stride = cairo_image_surface_get_stride(grad), i, j;
unsigned char *px = cairo_image_surface_get_data(grad);

#pragma openmp parallel for
for (i = 0; i < Allocation.height; ++i) {
  for (j = 0; j < Allocation.width; ++j) {
    guint32 *pixel = (guint32*)(px + i*stride + j*sizeof(guint32));
    guint32 r = round((double)i / Allocation.width * 255.0);
    guint32 g = round((double)j / Allocation.height * 255.0);
    guint32 b = round((double)(i*j) /
(Allocation.width*Allocation.height) * 255.0);
    *pixel = (255 << 24) | (r << 16) | (g << 8) | (b);
  }
}
cairo_surface_mark_dirty(grad);
cairo_translate(cr, Allocation.x, Allocation.y);
cairo_set_source_surface(cr, grad, 0, 0);
cairo_paint(cr);
cairo_surface_destroy(grad);

Note, I haven't debugged this code, so it might contain some errors.

Regards, Krzysztof


More information about the cairo mailing list