Beispiel #1
0
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,
    )
Beispiel #2
0
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