10

社区。

我知道这里有很多答案、手册、教程和互联网上的参考资料,以及关于这个问题的更多信息。我也知道需要线性代数的知识。但是,当我考虑是时候弄清楚所有的理论并在实践中解决练习时 - 我的头晕了,我不能做最简单的事情:(

拜托,如果您知道一个快速的解决方案,如何在渲染之前使文本在其中心上旋转 - 请告诉我。

现在我有:

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

4 回答 4

13

至少在我的机器上可用的 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')

文本演示.png

于 2013-06-26T13:29:09.147 回答
6

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

在此处输入图像描述

所以你必须解方程 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 不正确,但你明白了。

于 2011-12-12T04:35:20.630 回答
2

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

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()
于 2017-03-21T18:18:00.087 回答
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)

?

这或许可以解释为什么它会掉到右侧

于 2011-12-11T11:06:17.667 回答