[cairo] drawing inconsistency

Mon Jan 21 04:09:18 PST 2008

```Hi,

> >    ... is overwriting the top and the right side of the white
> > rectangle previously stroked.
> >
> >    Anyone has any idea what I am doing wrong?
>
> Yes. cairo_stroke() draws a line that extends symmetrically to both
> sides of the current path. At a line width of 1, the part that lies
> outside the path will have width 1/2. Now cairo_fill() fills the
> interior of the current path (not stroke!), so on a vector surface
> you'd end up with a 120x40 rectangle with a 1/2 unit border around it.
> Without antialiasing, cairo will miss a 1/2 unit wide horizontal or
> vertical line 50% of the time.

I've put my hands on cairo about a couple weeks ago. In that time,
I did not find some information about how Cairo maps logical
coordinates onto pixels.
Something like:
http://www.sffjunkie.co.uk/beos/BeBook/TheInterfaceKit_The_Coordinate_Space.html

So, the question here goes:
How does the 1.0 logical coordinate maps to the pixels?

IMO it should be like this: (at least that what I expect, but I can adapt)

-------------------------
|   |   |   |   |   |   |
-------------------------
|   | + | - | - | + |   |
-------------------------
|   | | |   |   | | |   |
-------------------------
|   | + | - | - | + |   |
-------------------------

The 1.0 horizontal(/vertical) line would go through the middle of the
pixels. 0.5 would also paint the pixels at row 1, as it would 1.49.
0.9 would paint the pixel on line 0 and 1.50 the pixel on line 2.

I need pixel precision, so could you please point me to a
page/document on how cairo maps logical coordinates to physical
pixels?
If there is none, then I hope you would not mind if we continue to

> There are a few ways to fix this:
> - use a line width of 2 (which is, incidentally, cairo's default).

AFAIR it gives the same result, only that the line is thicker at
the left/bottom side.

> - accept the sampling artifacts, but fill before stroking.

Cannot do that. :) The contents of the rectangle is changing color
in an animation effect.

> - use a different path for the stroke:
>   cairo_rectangle(cr, 99.5, 99.5, 121, 41);

That I could do, but I think it has to be different for filling not
for stroking.

> >    I think I am to blame, or SDL, because if I create the surface this way:
> > cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);
> > ... and write that into a .png, the result is OK.
>
> I can't reproduce that. Did you add the cairo_set_line_width(cr, 1)
> line after testing that, perhaps?

Strange.
In the code snippet I gave, cairo_set_line_width(cr, 1) is present.

To reproduce:
1) - take the code from the first mail, add
cairo_surface_write_to_png(cairoSurface, "image2.png");
right before
cairo_destroy(cr);
cairo_surface_destroy(cairoSurface);
=> check image2.png and see the inconsistency.

2) let cairo_surface_write_to_png(cairoSurface, "image2.png");
to be where it was pointed at 1)
then replace:
cairoSurface = cairo_image_surface_create_for_data(
(unsigned char*)screen->pixels,
CAIRO_FORMAT_ARGB32,
gWidth,
gHeight,
screen->pitch);
with:
cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);

=> check the image and see that the result is correct (the rectangle
is properly shown/visible)

So, this is why I'm puzzled. If I provide a pre-allocated drawing
buffer, Cairo won't draw properly, but if I tell it to allocate the
drawing buffer, the result is just fine.

Strange, very strange.