[cairo] cairo_stroke_extents() with transformation matrix

Andreas Falkenhahn andreas at airsoftsoftwair.de
Mon Feb 1 12:07:41 PST 2010

On 01.02.2010 at 16:56 Chris Wilson wrote:

>On Mon, 01 Feb 2010 17:35:25 +0100, "Andreas Falkenhahn"
><andreas at airsoftsoftwair.de> wrote:
>> Hi,
>> how can I get cairo_stroke_extents() to take the current transformation
>> into account? I.e. please consider the following code:
>> // scale * 2 on both axes
>> cairo_matrix_init(&m, 2, 0, 0, 2, 0, 0);
>> cairo_set_matrix(cr, &m);
>> cairo_new_path(cr);
>> cairo_rectangle(cr, 0, 0, 320, 240);	
>> cairo_stroke_extents(cr, &x1, &y1, &x2, &y2);
>> I'd expect that cairo_stroke_extents() would return something in the
>> of roughly 640 for x2 and roughly 480 for y2. Instead, it simply returns
>> 320 for x2 and about 240 for y2-- just as if there was no transformation
>at all.
>> Is there a way to get cairo_stroke_extents() take the current
>> matrix into account?
>Ab, but it is. It is transforming the extents of the path from device to
>user space using the current transformation matrix. For your purposes, you
>actually want to know the device extents, and so should set an identity
>transformation when querying the extents.
>cairo_scale(cr, 2, 2);
>cairo_rectangle(cr, 0, 0, 320, 240);	
>cairo_stroke_extents(cr, &x1, &y1, &x2, &y2);
>Hope this helps, and you have fun using Cairo!

Yes, thanks, it's working now.

I'm still a little confused with transformations and user vs. device space,
though. What I want to do is fit the current path *exactly* to a surface,
ie. without any blank spaces on the sides. Optionally, scaling or rotation
shall be used. I'm doing this the following way:

1) Calculate current path dimensions using cairo_stroke_extents() with a
dummy surface of size 1x1 pixel.

2) Once I have the dimensions of the path, allocate a surface that is exactly
the same size as the current path.

3) Cut off any gaps on the left and top sides of the path. I do this by translating
the path to the top left corner like this:

cairo_stroke_extents(cr, &x1, &y1, &x2, &y2);
cairo_translate(cr, -x1, -y1);

4) Now draw the path using cairo_stroke().

If no scale or rotation matrix is present, this code works fine. The path is
positioned exactly at the top-left corner of the surface and fits pixel-perfect
to the bottom-right corner. However, as soon as I add scaling or rotation, the
translation does not work correctly. Presumably because of some problem
between user and device space that I'm unaware of. So how do I have to translate
the current path so that cairo_stroke() starts stroking exactly at the top-left corner
of my surface?
As I said, the surface is large enough to hold the current path but it seems I'm
currently passing the wrong translation coordinates...

Thanks again,

"Remember: It's nice to be important but it's more important to be nice!"

More information about the cairo mailing list