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

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


--Apple-Mail-4--1041862128
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

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? ;-)

Dinu


--Apple-Mail-4--1041862128
Content-Disposition: attachment;
	filename=circularText.py
Content-Transfer-Encoding: 7bit
Content-Type: application/text;
	x-unix-mode=0644;
	x-mac-type=54455854;
	name="circularText.py"

#! /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
        h.add(s)

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

        # increment used letter widths in degrees
        b = b + beta
        
        group.add(h)

    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)
    d.add(g)

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


if __name__ == "__main__" :
        main()

--Apple-Mail-4--1041862128
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed


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

--Apple-Mail-4--1041862128--