Feat(text tool): Add import custom fonts - #9091
Conversation
…t-custom-fonts # Conflicts: # invokeai/app/api/routers/utilities.py # invokeai/app/services/config/config_default.py # invokeai/frontend/web/public/locales/en.json # invokeai/frontend/web/src/services/api/endpoints/utilities.ts
|
@Pfannkuchensack What changed:
On the auth question: this router is not mounted behind a parent FastAPI dependency. Confirmed: I addressed that by making custom font availability reactive:
So this is no longer relying on an implicit re-render path. |
|
Thanks for the detailed review. I went through every point and made the following changes. Blocking issues
Should-fix issues
Nits
I also added or updated tests covering the persistent font registry, base-URL composition, real TTF and WOFF2 parsing, configured font directories, response headers, and configuration initialization. |
joshistoast
left a comment
There was a problem hiding this comment.
Must fix:
FontFaceleak on every text-tool activation —loadedUserFontFacesRefis auseRefinFontSelect, which only mounts while the text tool is selected (CanvasToolbar.tsx:86). On unmount the loaded faces stay indocument.fontsbut the tracking map is discarded, so the next activation re-fetches and re-adds every font and the stale-prune loop can't see the old generation.document.fontsgrows by N per activation. Fix: hoist the map to module scope intextUserFonts.ts, which already owns the module-scoped readiness registry.list_user_fontsblocks the event loop — it'sasync defbut does synchronousrglob+ font parsing. I measured 1.3 ms/font, so ~900 fonts stalls all HTTP and socket.io traffic for ~1.2 s per request, and RTK Query drops its cache 60 s after deselecting the tool so it refires regularly. Dropping theasynckeyword hands it to FastAPI's threadpool.- Unrelated
networkxdependency inpyproject.tomldrives most of the 225-lineuv.lockchurn. Also worth pushing back on: the test file rewrite strips the module docstring and the comments documenting the security intent of the auth/ownership tests, plus a cosmeticr→responserename across untouched tests.
Notable non-blockers: font IDs are heuristically-chosen file paths, so adding a file to an existing family can flip the representative and orphan a user's saved selection; symlinked font directories are silently ignored with no log or UI signal; load failures leave an option permanently disabled with no explanation, and the 2 s readiness timeout lets a raster commit with the wrong font.
|
Addressed the actionable parts. Changed:
Already fixed in current branch:
Notable non-blockers: Implemented fixes for items 2, 3, and 4. Leaving item 1 as a follow-up. Leaving item 1 as a follow-up because changing custom font IDs from heuristic representative paths to stable IDs/content hashes would be a persistence/schema decision. It affects saved canvas state compatibility and may require migration or fallback handling for existing
Note: |
|
Update on the CI note: #9457 fixed the missing |
…t-custom-fonts # Conflicts: # invokeai/frontend/web/public/locales/en.json

Summary
Add support for custom text-tool fonts loaded from
invokeai/Fonts.This feature lets users add their own font files without replacing the built-in font set. The backend now discovers and serves fonts from
invokeai/Fonts, creates the directory andREADME.txtautomatically, and parses font metadata to show clean family names. The frontend loads these fonts into the text tool, shows them separately from built-in fonts, and keeps built-in fonts as fallback when no custom fonts are available.Related Issues / Discussions
N/A
QA Instructions
.ttf,.otf,.woff, or.woff2files toinvokeai/Fontsinvokeai/Fontsis emptyinvokeai/frontend/web/src/services/api/schema.tswas regenerated after adding the new utilities endpointsMerge Plan
Standard merge.
Checklist
What's Newcopy (if doing a release after this PR)