Search code examples
pythongraphicsrotationcairopycairo

rotate text around its center in pycairo


community.

I know that there are many answers here, manuals, tutorials and references over the internets and amny more about this question. Also I know that knowledge of linear algebra is required. But when I think about time to figuring out all the theory and solving exercises in practice - my head is blowing off and I can't do the simplest things :(

Please, if you know a little fast solution how to make rotation of text over its center before rendering it - tell me, pleeease.

For now I have:

#...
cr.move_to(*text_center)
myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2)

cr.save()
cr.translate(myX, myY)
cr.rotate(radians(text_angle))
cr.show_text(letter)
cr.restore()
#...

But my letter isn't rotating around itself. It's just like falling down to the right side :( I know that my code isn't right. Maybe I miss transformation but I don't know how to make it right.

UPDATE: Unfortunately, text are not affected by translations, so

cr.translate(10000, 10000)
cr.rotate(radians(15))
cr.show_text("hello")

will be exactly the same as

cr.rotate(radians(15))
cr.show_text("hello")

And I don't know how to make text rotation over its center without making new surface or something (like new layer in graphic processor) :(


Solution

  • At least on the version of cairo available on my machine (1.8.8), the following approach works for me:

    def text(ctx, string, pos, theta = 0.0, face = 'Georgia', font_size = 18):
        ctx.save()
    
        # build up an appropriate font
        ctx.select_font_face(face , cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        ctx.set_font_size(font_size)
        fascent, fdescent, fheight, fxadvance, fyadvance = ctx.font_extents()
        x_off, y_off, tw, th = ctx.text_extents(string)[:4]
        nx = -tw/2.0
        ny = fheight/2
    
        ctx.translate(pos[0], pos[1])
        ctx.rotate(theta)
        ctx.translate(nx, ny)
        ctx.move_to(0,0)
        ctx.show_text(string)
        ctx.restore()
    

    Which can be used in the following way:

    width = 500
    height = 500
    surface = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height)
    ctx = cairo.Context(surface)
    ctx.set_source_rgb(1,1,1)
    rect(ctx, (0,0), (width, height), stroke=False)
    ctx.set_source_rgb(0,0,0)
    for i in xrange(5):
        for j in xrange(5):
            x = 100 * i + 20
            y = 100 * j + 20
            theta = math.pi*0.25*(5*i+j)
            text(ctx, 'hello world', (x, y), theta, font_size=15)
    surface.write_to_png('text-demo.png')
    

    text-demo.png