def draw_name(draw: ImageDraw.Draw, name: str, box: t.Tuple[int, int, int, int], font_path: str, font_size: int = 40) -> None: """ Draw outlined text on image centered in box, downscaling font if necessary to fit. :param draw: target :param name: content :param box: location :param font_path: path to truetype font :param font_size: max font size :return: """ if not name: return x, y, w, h = box font = ImageFont.truetype(font_path, font_size) text_width, text_height = draw.multiline_textsize(name, font) downsize_factor = min( w / text_width, h / text_height, ) if downsize_factor < 1.: font = ImageFont.truetype(font_path, int(font_size * downsize_factor)) text_width, text_height = draw.multiline_textsize(name, font) x_1, y_1, x_2, y_2 = center_box(w, h, text_width, text_height) draw_text_with_outline( draw=draw, xy=(x_1 + x, y_1 + y), text=name, font=font, color=(255, ) * 3, background_color=(0, ) * 3, )
def make_text( text: str, box=(0, 0), font_path='', init_font_size=76, color=(0, 0, 0, 255), stroke=None, # stroke can be a color tuple align='left', emojis={}, instance=''): if contains_emojis(text, emojis): # fancy rendering enabled # redirect to fit_text_with_emojis_in_box() return make_emoji_text(text, emojis=emojis, instance=instance, box=box, font_path=font_path, color=color, stroke=stroke, align=align) canvas = Image.new('RGBA', box, color=(255, 255, 255, 0)) draw = Draw(canvas) textsize = (box[0] + 1, box[1] + 1) font_size = init_font_size # max font size is 72; decrease by 4 until fit while textsize[0] > box[0] or textsize[1] > box[1]: # doesn't fit if 0 < font_size <= 16: font_size -= 1 elif 16 < font_size < 32: font_size -= 2 elif font_size >= 32: font_size -= 4 else: break font = truetype(font_path, size=font_size) # try to fit in the horizontal boundary wrapped = wrap_text(text, box[0], font) textsize = draw.multiline_textsize(wrapped, font=font) # when wrapped text fits in box, loop will exit, and font is remembered draw.multiline_text( (0, 0), wrapped, fill=color if stroke is None else WHITE, font=font, stroke_fill=stroke, stroke_width=(max(font_size // 20, 2) if stroke is not None else 0), align=align) return canvas