вращать текст вокруг его центра в Pycairo - PullRequest
7 голосов
/ 11 декабря 2011

сообщество.

Я знаю, что здесь есть много ответов, руководств, учебных пособий и ссылок по интернетам и еще много вопросов по этому вопросу.Также я знаю, что знание линейной алгебры обязательно.Но когда я думаю о времени, чтобы выяснить все теории и решить упражнения на практике - у меня отрывается голова, и я не могу делать самые простые вещи: (

Пожалуйста, если вы знаете небольшое быстрое решение, какчтобы сделать вращение текста по центру перед его рендерингом - скажите мне, пожалуйста.

Пока у меня есть:

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

10 голосов
/ 26 июня 2013

По крайней мере в версии 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

5 голосов
/ 12 декабря 2011

ОК, поэтому cairo допускает текст move_to и rotate.Это означает, что вы хотите выяснить (x, y) для move_to (T), чтобы при вращении (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)

Обратите внимание, что в системе координат в Каире + y понижается, поэтому нужно исправить пару знаков, и, возможно, y_bearing не верен, но вы поняли идею.

1 голос
/ 21 марта 2017

Функция класса на основе указанного выше ввода с поддержкой многострочного текста.

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 голос
/ 11 декабря 2011

Должны

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

быть

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

Это может объяснить, почему падает на правую сторону .

...