在pycairo中心旋转文本

时间:2011-12-11 10:20:38

标签: python graphics rotation cairo pycairo

社区。

我知道这里有很多答案,有关互联网的手册,教程和参考资料,并且更多关于这个问题。我也知道线性代数的知识是必需的。 但是当我想到时间去理解所有的理论并在实践中解决练习时 - 我的头脑正在吹嘘,我不能做最简单的事情:(

如果你知道一个快速的解决方案,如何在渲染之前将文本旋转到其中心 - 请告诉我,pleeease。

现在我有:

#...
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()
#...

但是我的信并没有自我转动。这就像跌倒到右侧:( 我知道我的代码不对。也许我想念转型,但我不知道如何做到正确。

更新:不幸的是,文字不受翻译影响,所以

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

完全相同
cr.rotate(radians(15))
cr.show_text("hello")

我不知道如何在不创建新曲面或其他东西(如图形处理器中的新图层)的情况下在其中心进行文本旋转:(

4 个答案:

答案 0 :(得分:10)

至少在我的机器上可用的cairo版本(1.8.8)上,以下方法对我有用:

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()

可以通过以下方式使用:

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

答案 1 :(得分:4)

好的,所以cairo允许文本move_to和旋转。这意味着你想要的是找出move_to(T)的(x,y),这样当你旋转(R)时,文本的中心点就在你想要的位置,c =(cx,cy):

enter image description here

所以你必须求解方程Mv = c,其中v是相对于文本原点的文本中心:

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)

完整性检查:

  • 当r为0(无旋转)时,你得到x = cx-w / 2,y = cy-h',你知道 是正确的答案
  • 当r = -90(文字侧身,向右“向上”)时,你会得到你所期望的, 即x = cx-h'和y = cy + w / 2

对于python代码,你必须重写上面的等式,所以最终得到A * t = b,其中t =(x,y),你将计算t = inv(A)* b。然后,你只需要做

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

请注意,cairo中的坐标系有+ y下降,所以会有几个要修复的迹象,也许y_bearing不正确,但你明白了。

答案 2 :(得分:1)

应该

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

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

这可以解释为什么落到右侧

答案 3 :(得分:1)

基于上述输入的类函数,支持多行文本。

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()
相关问题