Библиотека изображений Python — рендеринг текста

Я пытаюсь отобразить какой-то текст с помощью PIL, но результат, честно говоря, дерьмовый.

Например, вот текст, который я написал в Photoshop:

PhotoShop

и что выходит из PIL:

PIL

Как видите, результаты PIL менее чем удовлетворительны. Может быть, я просто придираюсь, но есть ли способ нарисовать текст с помощью PIL, чтобы получить результаты, более близкие к моему эталонному изображению?

Вот код, который я использую на Python 2.7 с PIL 1.1.7.

image = Image.new("RGBA", (288,432), (255,255,255))
usr_font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", 25)
d_usr = ImageDraw.Draw(image)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)

person exiva    schedule 24.03.2011    source источник


Ответы (6)


Я придумал собственное решение, которое считаю приемлемым.

Что я сделал, так это сделал текст большим, например, в 3 раза больше, чем он должен быть, а затем масштабировал его, уменьшая его размер с помощью сглаживания, это не на 100% идеально, но это чертовски намного лучше, чем по умолчанию, и не требует cairo или панго.

Например,

image = Image.new("RGBA", (600,150), (255,255,255))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", fontsize)

draw.text((10, 0), txt, (0,0,0), font=font)
img_resized = image.resize((188,45), Image.ANTIALIAS)

и вы в конечном итоге с этим результатом,

окончательный результат

что намного лучше, чем то, что я получал раньше с тем же шрифтом.

person exiva    schedule 25.03.2011
comment
Мне нужен текст по центру, а не по левому краю. Есть ли способ сделать это, используя приведенное выше решение? - person Aarohi Kulkarni; 01.12.2015
comment
Имейте в виду, однако, что шрифты обычно имеют разные формы для разных размеров (а не просто масштабирование одной формы вверх и вниз). Это особенно заметно на мишенях меньшего размера. - person Tamás Szelei; 13.02.2016
comment
Другими словами, не думайте, что вам нужно это делать. Я обнаружил, что рендеринг текста с использованием этой функции происходит довольно медленно, и это может привести к ненужному замедлению. - person chris; 18.07.2017

Попробуйте использовать pycairo — привязку Python к библиотеке чертежей Cairo — это полезно для более изысканного рисования, со сглаженными линиями и т. д., и вы также можете создавать векторные изображения

Правильная обработка шрифтов и макета сложна и требует использования библиотек «pango» и «pangocairo». Хотя они созданы для серьезной работы со шрифтами (все виджеты GTK+ используют pango для рендеринга шрифтов), доступная документация и примеры крайне скудны.

В приведенном ниже образце показаны распечатки, доступные в системе, и отображается образец текста в семействе шрифтов, переданном в качестве параметра в командной строке.

# -*- coding: utf-8 -*-
import cairo
import pango
import pangocairo
import sys

surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 320, 120)
context = cairo.Context(surf)

#draw a background rectangle:
context.rectangle(0,0,320,120)
context.set_source_rgb(1, 1, 1)
context.fill()

#get font families:

font_map = pangocairo.cairo_font_map_get_default()
families = font_map.list_families()

# to see family names:
print [f.get_name() for f in   font_map.list_families()]

#context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

# Positions drawing origin so that the text desired top-let corner is at 0,0
context.translate(50,25)

pangocairo_context = pangocairo.CairoContext(context)
pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

layout = pangocairo_context.create_layout()
fontname = sys.argv[1] if len(sys.argv) >= 2 else "Sans"
font = pango.FontDescription(fontname + " 25")
layout.set_font_description(font)

layout.set_text(u"Travis L.")
context.set_source_rgb(0, 0, 0)
pangocairo_context.update_layout(layout)
pangocairo_context.show_layout(layout)

with open("cairo_text.png", "wb") as image_file:
    surf.write_to_png(image_file)

Визуализированное изображение

person jsbueno    schedule 24.03.2011
comment
Фу. это выглядит как слишком много зависимостей для простого приложения. (Я пытаюсь настроить pango и cairo на 10.6 с помощью homebrew) ... Возможно, мне придется переосмыслить некоторые вещи. Спасибо за помощь. - person exiva; 24.03.2011
comment
Существуют и другие библиотеки изображений, которые проще настроить. Первое, что приходит мне на ум, это pygame, но он не может серьезно работать с текстом (никакого сглаживания или субпиксельного рендеринга вообще). Возможно, с обертками для imagemagick (pythonmagick) будет проще иметь дело. - person jsbueno; 24.03.2011
comment
Я должен изучить их. Спасибо! - person exiva; 24.03.2011
comment
Просто обновление: у Pygame есть сглаживание и хороший рендеринг для шрифтов. Просто некоторые его примитивы рисования этого не делают. И с этим на порядок проще иметь дело, чем с приведенным выше примером pango + cairo. - person jsbueno; 11.11.2015
comment
Рендеринг шрифтов @jsbueno Pygame уродлив в Windows, большинство показателей шрифтов не работают и даже близко не соответствуют реалистичному рендерингу. (то есть pygame 1.9. Возможно, последние версии лучше, не пробовал). - person Mikhail V; 13.11.2016

Я никогда не использовал PIL, но беглый обзор документации по методу Draw показывает, что PIL предоставляет способ визуализации простой графики. Photoshop позволяет отображать сложную графику. Чтобы приблизиться к результатам Photoshop, требуется, как минимум, подсказка шрифта и сглаживание. Документация PIL даже не намекает на наличие таких возможностей. Вы можете рассмотреть возможность использования внешнего инструмента, который лучше справляется с визуализацией текста на изображениях. Например, ImageMagick (вы захотите использовать 8-битную версию, которая обрабатывает стандартный 24-битный RGB). Вы можете найти несколько примеров рисования текста здесь: http://www.imagemagick.org/Usage/draw/

person dave-holm    schedule 24.03.2011
comment
Спасибо, Дэйв, ваш ответ был очень полезен для меня, так как я хотел программно генерировать большие отдельные буквы алфавита в виде изображений разных цветов. Imagemagick безболезненно выполнил позиционирование и обработал размеры изображения и другие параметры. - person MattH; 30.11.2012

Предложение: используйте Wand или другую библиотеку изображений.

Вот пример с палочкой -

from wand.color import Color
from wand.image import Image
from wand.drawing import Drawing
from wand.compat import nested

with Drawing() as draw:
    with Image(width=1000, height=100, background=Color('lightblue')) as img:
        draw.font_family = 'Indie Flower'
        draw.font_size = 40.0
        draw.push()
        draw.fill_color = Color('hsl(0%, 0%, 0%)')
        draw.text(0,int(img.height/2 + 20), 'Hello, world!')
        draw.pop()
        draw(img)
        img.save(filename='image.png')

изображение, которое выходит-

person Aditya Shankar    schedule 30.11.2017
comment
И почему эта строка импортирует sin, cos, pi? - person jsbueno; 06.01.2019
comment
@jsbueno не нужно, внес поправку. Благодарность ! - person Aditya Shankar; 10.01.2019
comment
Работал намного лучше для меня, чем два других. Я впервые слышу о палочке, которая является привязкой Python к ImageMagick. - person YakovK; 25.06.2019

В python3 есть опция для псевдонимов шрифтов. Я нигде не мог найти этот ответ, надеюсь, он поможет кому-то вроде меня, который нашел этот вопрос в Google, и ему пришлось долго копаться, чтобы найти ответ.

draw = ImageDraw.Draw(img)
        draw.fontmode = "L"

Упоминается в документации здесь

person Baxorr    schedule 09.07.2020
comment
Использование "L" по-прежнему приводило к сглаженному тексту, но draw.fontmode = "1" работало. Для справки: режимы задокументированы здесь; Член fontmode ImageDraw, похоже, нигде не задокументирован; спасибо, что нашли время опубликовать этот ответ! - person Reign of Error; 22.11.2020

Вы также можете попробовать написать шрифт два раза, это увеличивает качество безмерно.

image = Image.new("RGBA", (288,432), (255,255,255))
usr_font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", 25)
d_usr = ImageDraw.Draw(image)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
person sharpshadow    schedule 01.11.2014
comment
Это действительно делает его жирнее, но я не могу сказать, что лучше. Возможно, это субъективно. - person physicalattraction; 30.04.2015
comment
Жирный и менее четкий на границе, что мне кажется лучше. По крайней мере, оно приближается к стандартному качеству Photoshop или GIMP. - person sharpshadow; 06.05.2015
comment
Почему рендеринг одного и того же объекта в одном и том же месте во второй раз имеет значение? - person martineau; 14.02.2016
comment
@martineau - я предполагаю, что пиксели, имеющие оттенок серого, а не полностью черные, затемняются, когда вы рисуете их дважды. - person ArtOfWarfare; 01.09.2016