Repository navigation
Conversation
An interpreter for TrueType instructions: font and control value programs
per size, glyph programs with phantom points, composites, the twilight
zone and the complete instruction set. renderText() runs it by default
for fonts that have instructions and places their glyphs on whole
pixels; fonts without instructions (and CFF outlines) render as before,
{hinting: false} turns it off.
Checked against FreeType's classic (v35) interpreter on 7 fonts (manual
hints like DejaVu, ttfautohint like Noto/Open Sans, FontForge like
FreeMono), all ASCII glyphs at 31 sizes: no glyph is off by half a pixel
or more, 99.8-100% are within 1/16 px, and Noto, Noto Symbols and both
Open Sans fonts match exactly. The details follow FreeType where the
spec leaves them open: 16.16 scaling with halves rounded away from zero,
original distances measured on the unscaled outline, no movement for
near-perpendicular vectors, invalid references skip the instruction.
Random bytecode never crashes or hangs (instruction and recursion limits).
Also fixes the rasterizer dropping segments that touch the bitmap's left
edge (float noise from curve subdivision gave x < 0), which inverted the
glyph; hinted outlines hit that a lot.
The targets of text in hinted fonts are regenerated (at 56-128 px the
difference is barely visible); the layout test checks subpixel placement
and runs unhinted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
Where the TrueType spec leaves details open, the interpreter follows FreeType's ttinterp.c (rounding, original distances, IUP, movement along near-perpendicular vectors, tolerance of invalid references). The FreeType License asks for the credit line in the documentation: it is in the source header, THIRD_PARTY_NOTICES.md and the README, and the license text ships as licenses/FTL.txt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an interpreter for the hinting instructions of TrueType fonts. Hinting aligns stems and edges with the pixel grid, so small text renders crisp instead of blurry, the way Windows (GDI) and FreeType's classic mode render it. This is what #31 asks for.
Behavior
renderText()hints fonts that come with instructions (fpgm,preporcvttables) and places their glyphs on whole pixels (rounded advances and kerning).renderText(font, size, text, color, layout, {hinting: false})restores the unhinted, subpixel-positioned rendering.The interpreter
USE_MY_METRICSSROUND/S45ROUNDIP,IUP,MDRP,MD)Verification
Hinted outlines were compared point by point with current FreeType (v35 interpreter, built from source) on 7 fonts: DejaVu Sans (hand hinted), Noto Sans and Noto Sans Symbols (ttfautohint), Open Sans Bold and Open Sans Condensed (ttfautohint), FreeMono (FontForge) and Ethnocentric. Each font was checked with all printable ASCII glyphs at 31 sizes (8–32, 36, 40 and 48 px), 2632 glyph instances per font:
All of Pillow's test fonts (including broken ones) hint without errors, and 3000 random byte sequences used as glyph programs never crashed or hung (slowest: 10 ms).
Also fixed
The glyph rasterizer dropped segments touching the left edge of a glyph's bitmap: curve subdivision produced x values like -1e-17, which landed in a negative row index. Glyphs then came out inverted. Unhinted text hit this rarely, hinted outlines (whose points often lie exactly on pixel boundaries) often.
Tests
tests/font.js:hinting: false.Credits
Where the TrueType spec leaves details open, the interpreter's behavior and parts of its logic follow FreeType's interpreter. Portions of this software are copyright © 2026 The FreeType Project (https://freetype.org); the FreeType License is included as
licenses/FTL.txtand credited inTHIRD_PARTY_NOTICES.md.Closes #31