Skip to content

Document and clarify _imagingft - #9908

Open
akx wants to merge 8 commits into
python-pillow:mainfrom
akx:ft-clarify
Open

Document and clarify _imagingft#9908
akx wants to merge 8 commits into
python-pillow:mainfrom
akx:ft-clarify

Conversation

@akx

@akx akx commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Refs #9898 - had to figure out what's happening in _imagingft to get to the bottom of the kerning woes, and these came out of that. The actual bugfixes will be in another PR stacked on this.

Basically:

  • there was some type confusion with FreeType's 26.6 fixed-point values; some comments noted values were in 26.6 when they are in pixels, or the other way around. This uses FT's FT_F26Dot6 type (an alias to long, since C doesn't have real newtypes, more's the shame) to make it more obvious to the reader.
  • adds macros to work with said data type, to avoid unclear * 64s or << 6s. Not truly type-safe since, well, see above about newtypes, but better than throwing magic numbers around.
  • adds doc comments for the internal functions, because the calling conventions weren't clear (more on that a couple bullet points later)
  • fixes _imagingft.pyi's types to match the reality of the module, and adds tests that prove that the typings were wrong.
  • changes the core getfont()'s signature to make all arguments required (C interface is internal #9879 in mind, that should be fine to do), since calling getfont() without encoding could handily segfault (since encoding in C was left uninitialized, set to stack garbage).

@akx
akx force-pushed the ft-clarify branch 3 times, most recently from 23b2e18 to aabb26a Compare August 26, 2026 19:25
@akx akx mentioned this pull request Aug 26, 2026
@radarhere

Copy link
Copy Markdown
Member

adds tests that prove that the typings were wrong

Looks to me like test_bytearray_not_supported() passes without the rest of your changes.

@akx

akx commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Er, yes..? The test passes (even on main) because font.getlength, font.getbbox, font.getmask don't actually accept bytearrays. If you remove the pytest.raises, it will fail.

On main, trying to pass in a bytearray fails:

$ uv pip install -e .
$ uv run python
Python 3.14.6 (main, Jun 11 2026, 03:55:33) [Clang 22.1.3 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import ImageFont
>>> f = ImageFont.load_default()
>>> f.font.getsize(bytearray(b"f"))
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    f.font.getsize(bytearray(b"f"))
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: expected string or bytes
>>>

even though the typings say they should be accepted:

~/b/Pillow (main) $ grep -C2 getsize src/PIL/_imagingft.pyi
    def getsize(
        self,
        string: str | bytes | bytearray,

Comment thread src/_imagingft.c Outdated
Comment thread src/_imagingft.c Outdated
@radarhere

Copy link
Copy Markdown
Member

Oh, right, most PR tests fail without the other changes, but that was not your intention here.

@akx
akx requested a review from radarhere August 27, 2026 14:05
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.

2 participants