отсечение шрифтов с помощью PIL - PullRequest
6 голосов
/ 19 декабря 2009

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

http://img109.imageshack.us/img109/8874/screenshotep.png

Код, который создал это изображение, довольно прост (сокращенно):

import Image, ImageDraw, ImageFont

im = Image.new("RGBA", (200, 200), 'white')
draw = ImageDraw.Draw(im)

font = ImageFont.truetype("VeraSe.ttf", 12)

draw.text(
           (1, 1),
           " %s: " % "ggjyfFwe__",
           font=font,
           fill='black'
)

draw.text(
           (1, 30),
           " %s" % 15,
           font=font,
           fill='black'
)

im.show()

Я пробовал это с несколькими разными шрифтами, и оно всегда обрезается. Удивительно, но Google "Обрезка шрифтов PIL" возвращает очень мало полезных хитов ... Я использую python 2.6.4 и PIL 1.1.6 в Ubuntu 9.10

Ответы [ 5 ]

2 голосов
/ 20 декабря 2018

Вот поздний ответ на этот старый вопрос.

Проблема заключается в том, что PIL и Pillow обрезают края визуализированного текста. Чаще всего это проявляется в конце широких символов и потомков (например, 'y's). Это также может появиться в верхней части некоторых шрифтов. Это была проблема как минимум десять лет. Это происходит независимо от размера изображения, на котором вызывается text(). Похоже, конфликт заключается в выборе ограничивающего прямоугольника как «font.size * number_chars» вместо «того, что мне действительно нужно визуализировать», и это происходит глубоко в стеке (_imagingft.c). Исправление этого вызывает другие проблемы, такие как выравнивание текста, отображаемого буква за буквой.

Некоторые решения включают в себя:

  • Добавить пробел в конец вашей строки. im.text(xy, my_text + ' ', ...)
  • При проблемах с высотой получите ширину вашего текста (font.getsize()), вторую визуализируйте текст, а также хорошие восходящие и нисходящие элементы, разделите отображаемый текст до первой указанной ширины и второй фактической высоты.
  • Используйте другую библиотеку, такую ​​как AggDraw или pyvips .

На это ссылаются в различных вопросах отсечение шрифтов с помощью PIL , PIL обрезает верхнюю часть букв , Правильно отображает текст с заданным шрифтом в Python и точно определяет его границы . Эти вопросы относятся к одной и той же основной проблеме, но не являются дубликатами

1 голос
/ 31 января 2012

Я не смог решить эту проблему для некоторых шрифтов, используя упомянутые выше подходы, поэтому в итоге я использовал aggdraw в качестве прозрачной замены для методов рисования текста PIL.

Ваш код, переписанный для aggdraw, будет выглядеть так:

import Image
import aggdraw

im = Image.new("RGBA", (200, 200), 'white')
draw = aggdraw.Draw(im)

# note that the color is specified in the font constructor in aggdraw
font = aggdraw.Font((0,0,0), "VeraSe.ttf", size=12, opacity=255)

draw.text((1, 1), " %s: " % "ggjyfFwe__", font) # no color here
draw.text((1, 30), " %s" % 15, font)

draw.flush() # don't forget this to update the underlying PIL image!

im.show()
0 голосов
/ 21 марта 2015

Вот кладжа, который хорошо работает для меня. Это вариант ответа гнуда. (Достаточно отличается, чтобы заслуживать отдельного ответа и комментария, я надеюсь.) Я проверил много словосочетаний, и это выполнялось последовательно.

Когда текст рисуется без полной высоты шрифта, может произойти отсечение. Как отметил gnud, используя такие символы, как «Aj» (я использую «Fj»), вы избегаете этой ошибки.

Всякий раз, когда слово помещается:

1) Сделайте draw.textsize (текст, шрифт = шрифт) с желаемым словом. Сохраните высоту / ширину.

2) Добавьте 'Fj' (пробелFJ) в конец слова, переделайте текст и сохраните третью высоту / ширину.

4) Вы будете фактически рисовать текст со словом из пункта 2 (с 'Fj' в конце). Наличие этого дополнения предотвратит обрезание шрифта.

4) Прежде чем вы начнете рисовать текст, обрежьте изображение в том месте, где приземлится 'Fj' (crop.load () требуется, чтобы избежать ленивого копирования). Затем нарисуйте текст и поместите обрезанное изображение обратно на «Fj».

Этот процесс позволяет избежать обрезки, кажется достаточно производительным и дает полный незафиксированный текст. Ниже приведена копия / вставка раздела кода Python, который я использую для этого. Частичный пример, но, надеюсь, это добавляет понимание.

    # note: xpos & ypos were previous set = coordinates for text draw 
    #       the hard-coded addition of 4 to c_x likely will vary by font
    #       (I only use one font in this process, so kludged it.)
    width, height = draw.textsize(word, font=font)
    word2 = word + ' Fj'
    width2, height2 = draw.textsize(word2, font=font)
    # crop to overwrite ' Fj' with previous image bits
    c_w = width2 - width
    c_h = height2
    c_x = xpos + width + 4
    c_y = ypos
    box = (c_x, c_y, c_x + c_w, c_y + c_h)
    region = img.crop(box)
    region.load()
    draw.text((xpos, ypos), word2, (0,0,0), font=font)
    img.paste(region, box)
0 голосов
/ 20 марта 2012

«Ошибка» все еще существует в 2012 году, с Ubuntu 11.10. Размер шрифта 11, 12, 13 и 15 полностью подчеркивает подчеркивание.

#!/usr/bin/env python
""" demonstrates clipping of descenders for certain font sizes """
import Image, ImageDraw, ImageFont
fontPath = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf"
im = Image.new('L', (256, 256))
ys=15
for i in range(10,21):
    fh = ImageFont.truetype(fontPath, i)
    sometext="%dgt_}" % (i)
    ImageDraw.Draw(im).text((10, ys ),sometext , 254, fh)
    ys+=i+5
im.show()
0 голосов
/ 20 декабря 2009

Я предлагаю перед созданием объекта изображения получить требуемый размер текста.

Это делается с использованием font.getsize("text") ( документация ).

В скрипте создания изображений, который я создал, я сначала нашел максимальную высоту одной строки текста, вызвав эквивалент font.getsize("Åj") (Если вам нужен только US-ASCII, вы можете найти высоту "Aj" вместо ). Затем я рассчитал требуемую высоту изображения и смещения линий, включая поля и межстрочный интервал.

...