[Image-SIG] Here is code for wrapping draw.text to fit within given pixel width

Caleb Hattingh caleb.hattingh at gmail.com
Tue Dec 7 20:27:50 CET 2004


I wrote the code below for the purpose of wrapping text to fit within
a given pixel width:

  drawer: Instance of "ImageDraw.Draw()"
  text: string of long text to be wrapped
  font: instance of ImageFont (I use .truetype)
  containerWidth: number of pixels text lines have to fit into.

Outputs described after code below:

def IntelliDraw(drawer,text,font,containerWidth):
    words = text.split()  
    lines = [] # prepare a return argument
    finished = False
    line = 0
    while not finished:
        thistext = lines[line]
        newline = []
        innerFinished = False
        while not innerFinished:
            #print 'thistext: '+str(thistext)
            if drawer.textsize(' '.join(thistext),font)[0] > containerWidth:
                # this is the heart of the algorithm: we pop words off
the current
                # sentence until the width is ok, then in the next outer loop
                # we move on to the next sentence. 
                innerFinished = True
        if len(newline) > 0:
            line = line + 1
            finished = True
    tmp = []        
    for i in lines:
        tmp.append( ' '.join(i) )
    lines = tmp
    (width,height) = drawer.textsize(lines[0],font)            
    return (lines,width,height)


Outputs of function:
  lines: list of strings which corresponds to the given "text"
argument, but broken up into list elements.
  width: pixel width of the first line (should be less than containerWidth)
  height: pixel height of first line (used for spacing successive lines)

An example of how this is used is given below:

text = 'One very extremely long string that cannot possibly fit \
into a small number of pixels of horizontal width, and the idea \
is to break this text up into multiple lines that can be placed like \
a paragraph into our image'

draw = ImageDraw.Draw(OurImagePreviouslyDefined)
font = fontpath = ImageFont.truetype('/usr/local/share/fonts/ttf/times.ttf',26)
pixelWidth = 500 # pixels

lines,tmp,h = IntelliDraw(draw,text,font,pixelWidth)
j = 0
for i in lines:
    draw.text( (0,0+j*h), i , font=font16, fill='black')
    j = j + 1

Hopefully this code works for you.  As you may observe, the algorithm
is *extremely* simple and not optimal in any way.  I would have loved
to have found something like this on the net, but couldn't, so maybe
someone else on this list is also looking.


More information about the Image-SIG mailing list