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

Use fractional coordinates when drawing text #6722

Merged
merged 3 commits into from
Nov 16, 2022

Conversation

radarhere
Copy link
Member

@radarhere radarhere commented Nov 7, 2022

Resolves #3977

That issue attempts to draw two halves of a word separately, expecting them to occupy the same pixels as the complete word. The example given there is "par" and "adise" vs "paradise".

#4959 helped by adding textlength, but did not resolve the issue completely. After switching to textlength, there was still a difference.

The ImageDraw text operation essentially has two parts - it generates a mask from the text characters with no awareness of the text position, and then pastes that mask onto the image at the relevant position. I had a thought - what if the position did matter, and text characters were rendered differently if they started halfway through a pixel?

With this PR, I have added a start argument to getmask and getmask2.

from PIL import ImageDraw, Image, ImageFont

img = Image.new('RGBA', (120, 80), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('/System/Library/Fonts/Supplemental/Arial.ttf', size=48)

mask = font.getmask2("adise", "L", start=(0, 0))[0]
draw.draw.draw_bitmap((0, 2), mask, 0)

mask = font.getmask2("adise", "L", start=(0.4, 0))[0]
draw.draw.draw_bitmap((0, 42), mask, 0)

img.save('example.png')

produces "a", "d", "s" and "e" in the same location, but a different "i" for the first line compared to the second.

example

Changing ImageDraw's text method to pass through the fractional coordinates of the text resolves the issue, allowing "par" and "adise" to fill the same pixels as "paradise".

To try and future proof the API, I have set start to be a tuple, so that both horizontal and vertical starting positions can be specified.

Copy link
Member

@hugovk hugovk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we mention the new argument in the release notes?

src/PIL/ImageFont.py Show resolved Hide resolved
src/PIL/ImageFont.py Show resolved Hide resolved
@radarhere
Copy link
Member Author

Sure. You can see the release notes at https://pillow--6722.org.readthedocs.build/en/6722/releasenotes/9.4.0.html

@hugovk hugovk merged commit 2b45623 into python-pillow:main Nov 16, 2022
@radarhere radarhere deleted the font_start branch November 16, 2022 08:56
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 this pull request may close these issues.

Font spacing changes
2 participants