Skip to content

Instantly share code, notes, and snippets.

@twobob
Forked from turicas/example_image_utils.py
Created August 31, 2022 12:01
Show Gist options
  • Save twobob/5aa3f4ff36723b25b0bc9b73f875d3a7 to your computer and use it in GitHub Desktop.
Save twobob/5aa3f4ff36723b25b0bc9b73f875d3a7 to your computer and use it in GitHub Desktop.

Revisions

  1. Álvaro Justen - Turicas revised this gist Dec 11, 2011. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions image_utils.py
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,6 @@
    #!/usr/bin/env python
    # coding: utf-8

    # Requirement: PIL <http://www.pythonware.com/products/pil/>
    # Copyright 2011 Álvaro Justen [alvarojusten at gmail dot com]
    # License: GPL <http://www.gnu.org/copyleft/gpl.html>

    @@ -44,7 +43,7 @@ def get_font_size(self, text, font, max_width=None, max_height=None):
    text_size = self.get_text_size(font, font_size, text)

    def write_text(self, (x, y), text, font_filename, font_size=11,
    max_width=None, max_height=None, color=(0, 0, 0)):
    color=(0, 0, 0), max_width=None, max_height=None):
    if isinstance(text, str):
    text = text.decode(self.encoding)
    if font_size == 'fill' and \
  2. Álvaro Justen - Turicas created this gist Dec 10, 2011.
    37 changes: 37 additions & 0 deletions example_image_utils.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    #!/usr/bin/env python
    # coding: utf-8

    # You need PIL <http://www.pythonware.com/products/pil/> to run this script
    # Download unifont.ttf from <http://unifoundry.com/unifont.html> (or use
    # any TTF you have)
    # Copyright 2011 Álvaro Justen [alvarojusten at gmail dot com]
    # License: GPL <http://www.gnu.org/copyleft/gpl.html>

    from image_utils import ImageText

    color = (50, 50, 50)
    text = 'Python is a cool programming language. You should learn it!'
    font = 'unifont.ttf'
    img = ImageText((800, 600), background=(255, 255, 255, 200)) # 200 = alpha

    #write_text_box will split the text in many lines, based on box_width
    #`place` can be 'left' (default), 'right', 'center' or 'justify'
    #write_text_box will return (box_width, box_calculed_height) so you can
    #know the size of the wrote text
    img.write_text_box((300, 50), text, box_width=200, font_filename=font,
    font_size=15, color=color)
    img.write_text_box((300, 125), text, box_width=200, font_filename=font,
    font_size=15, color=color, place='right')
    img.write_text_box((300, 200), text, box_width=200, font_filename=font,
    font_size=15, color=color, place='center')
    img.write_text_box((300, 275), text, box_width=200, font_filename=font,
    font_size=15, color=color, place='justify')

    #You don't need to specify text size: can specify max_width or max_height
    # and tell write_text to fill the text in this space, so it'll compute font
    # size automatically
    #write_text will return (width, height) of the wrote text
    img.write_text((100, 350), 'test fill', font_filename=font,
    font_size='fill', max_height=150, color=color)

    img.save('sample-imagetext.png')
    124 changes: 124 additions & 0 deletions image_utils.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,124 @@
    #!/usr/bin/env python
    # coding: utf-8

    # Requirement: PIL <http://www.pythonware.com/products/pil/>
    # Copyright 2011 Álvaro Justen [alvarojusten at gmail dot com]
    # License: GPL <http://www.gnu.org/copyleft/gpl.html>

    import Image
    import ImageDraw
    import ImageFont


    class ImageText(object):
    def __init__(self, filename_or_size, mode='RGBA', background=(0, 0, 0, 0),
    encoding='utf8'):
    if isinstance(filename_or_size, str):
    self.filename = filename_or_size
    self.image = Image.open(self.filename)
    self.size = self.image.size
    elif isinstance(filename_or_size, (list, tuple)):
    self.size = filename_or_size
    self.image = Image.new(mode, self.size, color=background)
    self.filename = None
    self.draw = ImageDraw.Draw(self.image)
    self.encoding = encoding

    def save(self, filename=None):
    self.image.save(filename or self.filename)

    def get_font_size(self, text, font, max_width=None, max_height=None):
    if max_width is None and max_height is None:
    raise ValueError('You need to pass max_width or max_height')
    font_size = 1
    text_size = self.get_text_size(font, font_size, text)
    if (max_width is not None and text_size[0] > max_width) or \
    (max_height is not None and text_size[1] > max_height):
    raise ValueError("Text can't be filled in only (%dpx, %dpx)" % \
    text_size)
    while True:
    if (max_width is not None and text_size[0] >= max_width) or \
    (max_height is not None and text_size[1] >= max_height):
    return font_size - 1
    font_size += 1
    text_size = self.get_text_size(font, font_size, text)

    def write_text(self, (x, y), text, font_filename, font_size=11,
    max_width=None, max_height=None, color=(0, 0, 0)):
    if isinstance(text, str):
    text = text.decode(self.encoding)
    if font_size == 'fill' and \
    (max_width is not None or max_height is not None):
    font_size = self.get_font_size(text, font_filename, max_width,
    max_height)
    text_size = self.get_text_size(font_filename, font_size, text)
    font = ImageFont.truetype(font_filename, font_size)
    if x == 'center':
    x = (self.size[0] - text_size[0]) / 2
    if y == 'center':
    y = (self.size[1] - text_size[1]) / 2
    self.draw.text((x, y), text, font=font, fill=color)
    return text_size

    def get_text_size(self, font_filename, font_size, text):
    font = ImageFont.truetype(font_filename, font_size)
    return font.getsize(text)

    def write_text_box(self, (x, y), text, box_width, font_filename,
    font_size=11, color=(0, 0, 0), place='left',
    justify_last_line=False):
    lines = []
    line = []
    words = text.split()
    for word in words:
    new_line = ' '.join(line + [word])
    size = self.get_text_size(font_filename, font_size, new_line)
    text_height = size[1]
    if size[0] <= box_width:
    line.append(word)
    else:
    lines.append(line)
    line = [word]
    if line:
    lines.append(line)
    lines = [' '.join(line) for line in lines if line]
    height = y
    for index, line in enumerate(lines):
    height += text_height
    if place == 'left':
    self.write_text((x, height), line, font_filename, font_size,
    color)
    elif place == 'right':
    total_size = self.get_text_size(font_filename, font_size, line)
    x_left = x + box_width - total_size[0]
    self.write_text((x_left, height), line, font_filename,
    font_size, color)
    elif place == 'center':
    total_size = self.get_text_size(font_filename, font_size, line)
    x_left = int(x + ((box_width - total_size[0]) / 2))
    self.write_text((x_left, height), line, font_filename,
    font_size, color)
    elif place == 'justify':
    words = line.split()
    if (index == len(lines) - 1 and not justify_last_line) or \
    len(words) == 1:
    self.write_text((x, height), line, font_filename, font_size,
    color)
    continue
    line_without_spaces = ''.join(words)
    total_size = self.get_text_size(font_filename, font_size,
    line_without_spaces)
    space_width = (box_width - total_size[0]) / (len(words) - 1.0)
    start_x = x
    for word in words[:-1]:
    self.write_text((start_x, height), word, font_filename,
    font_size, color)
    word_size = self.get_text_size(font_filename, font_size,
    word)
    start_x += word_size[0] + space_width
    last_word_size = self.get_text_size(font_filename, font_size,
    words[-1])
    last_word_x = x + box_width - last_word_size[0]
    self.write_text((last_word_x, height), words[-1], font_filename,
    font_size, color)
    return (box_width, height - y)