在pycairo中围绕中心旋转文本
大家好。
我知道这里有很多答案、手册、教程和网上的参考资料,关于这个问题的内容也很多。而且我也知道,学习线性代数是必要的。
但是,当我想到要花时间去理解所有的理论和在实际中解决练习时,我的脑袋就要炸了,我连最简单的事情都做不好 :(
所以,如果你知道一个快速的方法,可以在渲染文本之前让它围绕中心旋转,请告诉我,拜托。
目前我有:
#...
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 个回答
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()
6
好的,cairo这个工具可以让你移动文本和旋转文本。这意味着你需要找出一个点(x,y),通过这个点移动文本(T),然后再旋转(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可能不太正确,但你明白这个意思就好。
14
在我电脑上安装的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')