Rotate text around its center in pycairo

community.

I know that there are many answers, manuals, manuals and links on the Internet, and I ask more about this. I also know that knowledge of linear algebra is required. But when I think about the time to understand the whole theory and solutions of exercises in practice - my head is blowing, and I can not do the simplest things: (

Please, if you know a little quick solution on how to make the text rotate above its center before rendering it - tell me, pleeease.

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 does not revolve around itself. It's just like falling down on the right side :( I know my code is wrong. Maybe I will skip the transformation, but I don't know how to do it right.

UPDATE: Unfortunately, the text is not affected by translations, therefore

 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 rotate the text above its center without creating a new surface or something (for example, a new layer in the GPU): (

+6
source share
4 answers

At least on the cairo version 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() 

What can be used as follows:

 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

+8
source

OK, so cairo allows you to move move_to text and rotate. This means that you want to figure out (x, y) for move_to (T) so that when you rotate (R), the center point of your text is in the right place, c = (cx, cy):

enter image description here

So, you need to solve the equation Mv = c, where v is the text center relative to the source text:

 M = T*R T = (1 0 x) (0 1 y) (0 0 1) R = (cos r -sin r 0) (sin r cos r 0) (0 0 1) v = (w/2, h', 1) c = (cx, cy, 1) h' = h/2 - (h - y_bearing) 

Security check:

  • when r is 0 (no rotation), you get x = cx-w / 2, y = cy-h ', that you know the correct answer
  • when r = -90 (text on the side, with "up" to the right), you get what you expect, i.e. x = cx - h 'and y = cy + w / 2

For python code, you have to rewrite the above equation so that you end up with A * t = b, where t = (x, y), and you will calculate t = inv (A) * b. Then you just do

 cr.move_to(x, y) cr.rotate(r) cr.show_text(yourtext) 

Please note that the coordinate system in Cairo has + y, so a couple of characters will be fixed, and y_bearing may not be correct, but you will get this idea.

+4
source

should

 myX, myY = text_center[0] + (height / 2), text_center[1] - (width / 2) 

will be

 myX, myY = text_center[0] - (width / 2), text_center[1] + (height / 2) 

?

This may explain why it falls to the right side.

+1
source

A class function based on the above input with multi-line text support.

 def text(self, text, x, y, rotation=0, fontName="Arial", fontSize=10, verticalPadding=0): rotation = rotation * math.pi / 180 self.ctx.select_font_face(fontName, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) self.ctx.set_font_size(fontSize) fascent, fdescent, fheight, fxadvance, fyadvance = self.ctx.font_extents() self.ctx.save() self.ctx.translate(x, y) self.ctx.rotate(rotation) lines = text.split("\n") for i in xrange(len(lines)): line = lines[i] xoff, yoff, textWidth, textHeight = self.ctx.text_extents(line)[:4] offx = -textWidth / 2.0 offy = (fheight / 2.0) + (fheight + verticalPadding) * i self.ctx.move_to(offx, offy) self.ctx.show_text(line) self.ctx.restore() 
+1
source

Source: https://habr.com/ru/post/903546/


All Articles