[reportlab-users] Circular text (was: iCards...)

Dinu Gherman reportlab-users@reportlab.com
Wed, 29 Jan 2003 11:48:50 +0100

Content-Transfer-Encoding: 7bit
Content-Type: text/plain;

Jerome Alet:

> One thing bothers me : I did my best to translate the postscript
> algorithm into Python+ReportLab but I'm not sure it's correct
> because some strings look "not so circular" when drawn.
> Maybe that's just an optical problem or a rounding one, did you
> see this too ?

I'm attaching an experimental function which does circular text,
using Drawings, mostly as I like. I think it needs some kind of
compensation for a certain uglyness resulting from the modified
kerning between characters due to the bending effect. Maybe Just
can tell us how to do it in a typographically more satisfactory
way? ;-)


Content-Disposition: attachment;
Content-Transfer-Encoding: 7bit
Content-Type: application/text;

#! /usr/bin/env python

from math import pi, sqrt, sin, cos

from reportlab.lib import colors
from reportlab.graphics import shapes
from reportlab.graphics import renderPDF, renderPM
from reportlab.pdfbase.pdfmetrics import stringWidth

def addCT(group, x, y, radius, angle, text, fontname, fontsize, counterClockWise=0):
    "An experimental function to add some circular text to a Group shape."
    ccw = counterClockWise
    fn, fs, = fontname, fontsize
    width = stringWidth(text, fn, fs)
    alpha = width / radius / pi*180
    b = {0: -angle, 1: 180-angle}[ccw]
    for letter in text:
        # create a group containing one letter
        h = shapes.Group()
        h.add(shapes.Circle(0, 0, 3, fillColor=colors.red))
        s = shapes.String(0, 0, letter, textAnchor="middle")
        s.fontName = fn
        s.fontSize = fs

        # translate it to new origin: x,y
        h.translate(x, y)

        # translate to circle border: dx,dy
        width = stringWidth(letter, fn, fs)
        beta = width / radius / pi*180
        phi = alpha/2-b-beta/2
        if ccw: 
            phi = 180 - phi
        dx = -sin(phi*pi/180)*radius
        dy = cos(phi*pi/180)*radius
        h.translate(dx, dy)        

        # rotate as needed
        if ccw:
            phi = phi - 180

        # increment used letter widths in degrees
        b = b + beta

    return group

def main() :
    w, h = 200, 200
    x, y = 100, 100
    r = 50
    fn, fs = "Helvetica-Bold", 24
    d = shapes.Drawing(w, h)
    g = shapes.Group()

    # add a couple of helping widgets
    g.add(shapes.Rect(0, 0, w, h, fillColor=None))
    g.add(shapes.Circle(x, y, 3, fillColor=colors.black))
    g.add(shapes.Circle(x, y, r, fillColor=None))
    g.add(shapes.Circle(x, y, r+fs, fillColor=None))
    # add two circular texts
    addCT(g, x, y, 50, 45, "Python", fn, fs)
    addCT(g, x, y, 50, -180-45, "powered", fn, fs, counterClockWise=1)

    # renderPM.drawToFile(d, "circularText.jpg", "JPG")
    renderPDF.drawToFile(d, "circularText.pdf")

if __name__ == "__main__" :

Content-Transfer-Encoding: 7bit
Content-Type: text/plain;

Dinu C. Gherman
"Questions are never indiscreet. Answers sometimes are." (Oscar Wilde)