Angled Text#

../_images/angled_text_all.png

Angled Text for all angles#

The text is advances in an anticlockwise direction when it is rotated.

Angled Text Properties#

Pil has no built-in option to create text at an angle, however it does have other modules that can produce the desired effect. The method is based on that provided by stenci angled text

Show/Hide Angled Text Attributes

PIL text has the following properties

  • xy

    Top left text corner

  • text

    Text to be written, if it contains a newline, then it is passed onto multiline_text

  • fill

    Text colour

  • font

    ImageFont instance

  • anchor

    Specify alternate anchor points, used on TTF fonts.

The angled text has the following additions and changes.

  • im

    PIL image handle, link to the calling program

  • at

    anchor to text middle

  • angle

    text angle in degrees

  • aall

    integer showing whether to have all angles, default all angles 1

Create Angled Text#

../_images/angled_text.png

Constrained Angled Text#

The text angle is restricted so that no angle produces upside down writing.

Make a function that can produce the rotated text, in essence an image of the text is created and rotated, then is pasted back into the parent image. The text image is created with an RGBA attribute set to transparent, the parent image does not need an RGBA attribute, RGB will suffice. This way a dark surround of the angled text is avoided. Remember image rotation is reckoned anticlockwise.

When the text is rotated set the expand attribute on, also set the resample filter to BICUBIC (LANCZOS does not work with rotate). The rotated text is pasted directly into the parent image at coordinates given. During rotation the box surrounding the image changes size, so determine its new size before pasting. The text image is used as its own mask for pasting.

When determining how the text sits in the parent image remember that in PIL the upper left corner of the text is used to position it. At different angles the relative position of the upper left corner and the position of the text placement shifts, according to the sector and angle. In tkinter the text uses its centre as the anchor point when positioned in the parent image. This latter method simplifies text positioning and will be used for our angled text. The necessary adjustment is not too onerous.

Show/Hide Code test_angled_text.py

from PIL import Image, ImageFont, ImageDraw
from DimLinesPIL import polar2cart
# https://stackoverflow.com/questions/245447/how-do-i-draw-text-at-an-angle-using-pythons-pil
# stenci
# text aligned middle of text

def angled_text(im, at, text, angle, font=None, fill=(0,0,0), aall=1):

    if font is None:
        font = ImageFont.load_default()

    (wide, height) = font.getsize(text)
    wide = wide + 10

    image1 = Image.new('RGBA', (wide, height), (255,255,255,0))
    draw1 = ImageDraw.Draw(image1)

    draw1.text((0, 0), text=text, font=font, fill=fill)

    # ensure angles within 0 to 360
    angle = 360 + angle if angle < 0 else angle
    angle = angle if angle < 360 else angle - 360

    if aall == 0:
        if 90 <= angle < 180:
            angle = angle + 180
        if 180 <= angle < 270:
            angle = angle - 180

    px, py = at
    # rotate angle in degrees anticlockwise
    image1 = image1.rotate(-angle, expand=1, resample=Image.BICUBIC)

    sx, sy = image1.size

    if 0 <= angle < 90:
        im.paste(image1, (px-sx//2, py-sy//2, px + sx-sx//2, py + sy-sy//2), image1)
    elif 90 <= angle <= 180:
        im.paste(image1, (px-sx//2, py - sy+sy//2, px + sx-sx//2, py+sy//2 ), image1)
    elif 180 < angle < 270:
        im.paste(image1, (px-sx+sx//2, py-sy+sy//2, px+sx//2, py+sy//2 ), image1)
    elif 270 <= angle < 360:
        im.paste(image1, (px-sx//2, py-sy//2, px + sx-sx//2, py + sy-sy//2), image1)
    #print('angle',angle,'wide,height' ,wide,height,'px,py',px,py,'sx,sy',sx,sy)

if __name__ == "__main__":
    Text = "Chihuly Exhibit" 

    Angle = 0

    Font = ImageFont.truetype('consola.ttf', 25)
    tsize = Font.getsize(Text + str(0000))

    w = 501
    h = 501
    image2 = Image.new('RGB', (w, h), (255,255,221))
    pt = (200,120) #(w//2, h//2)
    
    a = (0, 45, 90, 135, 180, 225, 270, 315)
    for j in range(len(a)):
        pt = polar2cart(pt, a[j], tsize[0]//2)
        #print(pt)
        angled_text(image2, pt, Text +' '+ str(a[j]), a[j], font=Font,
                    fill=(0,0,0), aall=1)
    
    #angled_text(image2, pt, Text +' '+ str(Angle), Angle, font=Font, fill=(0,0,0))
    image2.show()
    #image2.save('../../temp/angled_text.png')

Todo

Multiline angled text is not yet sorted out