Центрирование русского текста на картинке
Я пишу модуль для бота который генерирует демотиватор по заданному ему тексту и изображению. Бот ориентируется на русскую аудиторию, поэтому использование русского должно присутствовать.
Что вышло:
PADDING = 25
LINE_SIZE = 2
BOTTOM_PADDING = 150
FONTS = f"{os.getcwd()}/fonts"
def set_text(template, texts):
font_upper = ImageFont.truetype(f"{FONTS}/times.ttf", 64)
font_lower = ImageFont.truetype(f"{FONTS}/times.ttf", 46)
draw_upper_text = ImageDraw.Draw(template)
upper_text_width, _ = draw_upper_text.textsize(texts[0].encode("utf-8").decode("latin1"), font_upper)
draw_upper_text.text(
(
(template.width-upper_text_width)/2,
template.height-BOTTOM_PADDING+10
),
texts[0], fill="white", font=font_upper
)
draw_lower_text = ImageDraw.Draw(template)
lower_text_width, _ = draw_lower_text.textsize(texts[1].encode("utf-8").decode("latin1"), font_lower)
draw_lower_text.text(
(
(template.width-lower_text_width)/2,
template.height-BOTTOM_PADDING+(PADDING*4)-10
),
texts[1], fill="white", font=font_lower
)
return template
Текст с русскими символами "съезжает", а с латинскими - всё хорошо. Как можно пофиксить?
Ответы (1 шт):
Уберите .encode("utf-8").decode("latin1"), это лишнее действие, которое для кириллицы увеличивает размер текста в 2 раза
Причина в том, что текст там в utf-8, а в нем кириллица занимает 2 байта на символ. А когда вы сделали encode вы получили массив байт, а .decode("latin1") из массива байт вернул строку, причем в latin1 символы занимают 1 байт, поэтому:
- Строка с кириллицей стала в 2 раза больше
- Она стала кракозяброй
- Строка с латинскими буквами не поменялась, т.к. символы в ней занимают 1 байт и их коды совпадают с тем, что в utf-8
Как это выглядит:
text = texts[0].encode("utf-8").decode("latin1")
print(repr(texts[0]), len(texts[0]), len(text), repr(text))
# 'ПРИВЕТ' 6 12 'Ð\x9fÐ\xa0Ð\x98Ð\x92Ð\x95Т'
text = texts[1].encode("utf-8").decode("latin1")
print(repr(texts[1]), len(texts[0]), len(text), repr(text))
# 'HELLO WORLD!' 6 12 'HELLO WORLD!'
Пример:
from PIL import ImageFont, Image, ImageDraw
PADDING = 25
LINE_SIZE = 2
BOTTOM_PADDING = 150
FONTS = "fonts"
def set_text(template, texts):
font_upper = ImageFont.truetype(f"{FONTS}/times.ttf", 64, encoding='utf-8')
font_lower = ImageFont.truetype(f"{FONTS}/times.ttf", 46, encoding='utf-8')
draw_upper_text = ImageDraw.Draw(template)
upper_text_width, _ = draw_upper_text.textsize(texts[0], font_upper)
draw_upper_text.text(
(
(template.width-upper_text_width)/2,
template.height-BOTTOM_PADDING+10
),
texts[0], fill="white", font=font_upper
)
draw_lower_text = ImageDraw.Draw(template)
lower_text_width, _ = draw_lower_text.textsize(texts[1], font_lower)
draw_lower_text.text(
(
(template.width-lower_text_width)/2,
template.height-BOTTOM_PADDING+(PADDING*4)-10
),
texts[1], fill="white", font=font_lower
)
return template
img = Image.new("RGB", (400, 300), "black")
set_text(img, ["ПРИВЕТ", "HELLO WORLD!"])
img.show()
Результат:

