Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Truetype fonts not being rendered correctly with the TEXT method #4177

Closed
ADBeasley opened this issue Oct 28, 2019 · 8 comments · Fixed by #4664
Closed

Truetype fonts not being rendered correctly with the TEXT method #4177

ADBeasley opened this issue Oct 28, 2019 · 8 comments · Fixed by #4664

Comments

@ADBeasley
Copy link

ADBeasley commented Oct 28, 2019

What did you do?

Created an image suitable for the Pimoroni InkyHat display
Added italic text onto the image object at different places

What did you expect to happen?

The whole of the last character of the text to be displayed as it did to render correctly on Stretch on the Pi Zero
Looking at the font from a Mac (Mojave), the characters look fine.

What actually happened?

Depending on the length of the text, some or all of the last character is missing when using some italic fonts. If the text length is around 105 - 110 pixels then you can lose some / all of the very last character.

Padding out the text string with spaces so it is longer than 110 pixels fixes the issue

What are your OS, Python and Pillow versions?

  • OS: Raspbian Buster Lite (10.1) Kernel 4.19.75+ TIFF incorrect colours #1270 Tue Sep 24 18:38:54 BST 2019 armv6l GNU/Linux (running on a Pi Zero)
  • Python: 3.7.3 - not tested under Python 2
  • Pillow: 6.2.1 (installed using pip3)

The fonts used are available from Font Squirrel - the two are:

Open Sans here
Ubuntu here

from PIL import Image, ImageDraw, ImageFont

image_obj = Image.new('P', (212, 104), color = (255,255,255))
screen_image = ImageDraw.Draw(image_obj)

osbi = ImageFont.truetype('Fonts/OpenSans-BoldItalic.ttf', 15)
screen_image.text((10,10), 'Network Status test',fill = (0,0,0) , font = osbi)
screen_image.text((10,30), 'Bit longer no iffy ending',fill = (0,0,0) , font = osbi)

ubuntu = ImageFont.truetype('Fonts/Ubuntu-BI.ttf', 15)
screen_image.text((10,60), 'Network Status test',fill = (0,0,0) , font = ubuntu)
screen_image.text((10,80), 'Bit longer no iffy ending',fill = (0,0,0) , font = ubuntu)

image_obj.save('italic-test.png')

italic-test

@radarhere radarhere changed the title Italic true type fonts not being rendered correctly with the TEXT method Italic truetype fonts not being rendered correctly with the TEXT method Oct 29, 2019
@ADBeasley ADBeasley changed the title Italic truetype fonts not being rendered correctly with the TEXT method Truetype fonts not being rendered correctly with the TEXT method Oct 29, 2019
@ADBeasley
Copy link
Author

ADBeasley commented Oct 29, 2019

Have now discovered that:

  1. It is not only Italic fonts (can reproduce on various 'light' fonts)
  2. The range of ending positions is not limited to 110 Pixels - I now have one at 129 pixels

@BeauSlim
Copy link

BeauSlim commented Nov 5, 2019

I can replicate this error on macOS with updated libs. I've seen issues similar to this using Pillow to render text for little 1-bit OLED displays.
It looks like Pillow is using fontmode='1' since you have chosen mode 'P'.
What happens if you use 'L' or 'RGB' instead of 'P'?
If you add screen_image.fontmode='L' before rendering text does the problem go away?
This may be related to #2293 (i.e. it may be a libfreetype problem).

@ADBeasley
Copy link
Author

ADBeasley commented Nov 9, 2019 via email

@radarhere
Copy link
Member

@BeauSlim I'm not able to replicate this on my macOS machine. Are you still able to?

@radarhere radarhere removed the Linux label May 21, 2020
@BeauSlim
Copy link

I'm not able to replicate this on my macOS machine. Are you still able to?

Yes. ADBeasley's posted code produces exactly the same image as above on my macOS Catalina machine with Pillow 7.1.2 under brew's Python 3.7.7.

I played with it a bit. If you manually set screen_image.fontmode='P' the text isn't clipped, so maybe it comes down to the old fontmode '1' problem? And it appears that #2293 is not related to an outdated FreeType library since ImageFont.core.freetype2_version gives me 2.10.1 and I am still getting problems with vertical alignment with mode '1' TTF text:

ubuntu-sizes

I ended up converting the fonts I wanted into .bdf format to solve this, so no big deal, but it definitely points to a bug somewhere.

@nulano
Copy link
Contributor

nulano commented May 25, 2020

I can actually reproduce #2293 with 7.1.1 from PyPI on Windows 10 using verdanab.ttf (not verdana.ttf). I will comment here, as the other issue is closed. I have a pretty good idea of what might be causing this, I will investigate more when I get more time. The issue happens with all four combinations, both layout_engine RAQM and BASIC, as well as fontmode 1 and L. It is hard to see on L due to the thicker symbols, but the digit 0 is actually clipped at the top, indicating that this is clearly a bug. Additionally, all symbols in that font have atrocious kerning (I suspect this part of the problem):

verdanab-7 1 1

My WIP branch (#4553) doesn't have these issues, although I'm not sure it is perfect either.
Edit: The poor hinting is fixed in the new PR.

verdanab-7 2 0 dev0

from PIL import Image, ImageDraw, ImageFont
im = Image.new("RGB", (400, 100), "white")
d = ImageDraw.Draw(im)
def line(y, engine, mode):
    f = ImageFont.truetype("verdanab.ttf", 13, layout_engine=engine)
    d.fontmode = mode
    d.text((10, y), "engine: {}, mode: {}".format(engine, mode), "black", f)
    d.text((170, y), "01234567890123456789", "black", f)
line(10, 0, '1')  # 0 is basic layout
line(30, 0, 'L')
line(50, 1, '1')  # 1 is raqm layout
line(70, 1, 'L')

Edit: Corrected images.

@nulano
Copy link
Contributor

nulano commented May 25, 2020

I just realized that I forgot to actually test this bug specifically; I can reproduce this issue with both 7.1.1 and my WIP branch, getting practically the same images as OP. Note that it only happens with Basic layout.

@nulano
Copy link
Contributor

nulano commented May 27, 2020

I solved this one. The problems is that getsize is called without the mode parameter, thus performing layout with FT_LOAD_TARGET_NORMAL instead of FT_LOAD_TARGET_MONO hinting. The different hinting algorithms can in some circumstances give different results causing this bug.

Raqm layout always uses FT_LOAD_TARGET_NORMAL hinting for layout, this error doesn't accumulate and in the worst case only one pixel is clipped. Raqm doesn't do hinting during layout, only rendering. Hinting can nudge glyphs at most one pixel which may be clipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants