Skip to content

examples: add multiple_fonts POC — single CJK OTC, per-language glyph variants, subsetting - #283

Open
kyasu1 wants to merge 2 commits into
fschutt:masterfrom
kyasu1:poc/multiple-fonts-otc-demo
Open

examples: add multiple_fonts POC — single CJK OTC, per-language glyph variants, subsetting#283
kyasu1 wants to merge 2 commits into
fschutt:masterfrom
kyasu1:poc/multiple-fonts-otc-demo

Conversation

@kyasu1

@kyasu1 kyasu1 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds a new example, examples/multiple_fonts.rs, as a proof of concept
for three things printpdf can do with CJK text that are easy to get wrong:

  • Rendering multiple faces from one OTC on the same page. Source Han Serif
    ships as a "Super OTC" — a single OpenType Collection (SourceHanSerif.ttc,
    ~155 MiB) containing all 4 CJK regions (JA/KR/TC/SC) across 7 weights each
    (28 faces total, per the ttcf header). The example loads each face it
    needs by index via ParsedFont::from_bytes(bytes, font_index, ..),
    registers them all with doc.add_font, and switches between them with
    Op::SetFont while laying out a single page — demonstrating how printpdf
    lets a document mix several faces pulled out of one collection, rather
    than requiring one font file per face/language.

  • Han-unified glyphs render per language, not per codepoint. U+66DC (曜)
    is a textbook case of Han unification: the same Unicode codepoint is drawn
    with subtly different strokes in Japanese, Korean, Traditional Chinese, and
    Simplified Chinese fonts. The example demonstrates the low-level mechanism
    printpdf exposes to get the correct regional glyph today: load the
    language-specific face from the collection (via font_index) and switch
    Op::SetFont per run.

  • Font subsetting keeps output size proportional to used glyphs, not to
    the source font.
    With PdfSaveOptions::subset_fonts = true, the
    resulting PDF is ~1.81 MiB against a ~155.1 MiB source font collection —
    about 85x smaller (~1.2% of the original), even though the document draws
    from 28 different sub-faces across 4 scripts.

Non-goals

printpdf only exposes the primitive: given a font_index, load that face
and let the caller switch fonts per text run. It does not — and should
not — decide which face to use for a given language or script. That
decision (detecting the run's language/script and picking the matching face
out of a collection, resolving Unicode variation sequences, etc.) belongs in
a higher-level text-shaping/layout library, e.g. azul-layout, sitting above
printpdf. This example exists to prove the low-level primitive works, not to
propose printpdf grow automatic language-aware font selection.

Changes

  • examples/multiple_fonts.rs (new): builds the demo document described
    above and writes multiple_fonts.pdf.
  • Cargo.toml: register the multiple_fonts example target.

A note for @fschutt

This is a POC, so whether/how to merge it is entirely your call.

The one thing worth deciding up front: SourceHanSerif.ttc (~155 MiB) is
not included in this PR — it's over GitHub's 100 MB per-file push limit,
so it can't be added as a normal blob. Right now that means
examples/multiple_fonts.rs won't compile out of the box (the
include_bytes! target doesn't exist) unless the file is placed locally
first, downloaded from source.typekit.com/source-han-serif.

Options, roughly in order of effort:

  • Track it with Git LFS (repo + GitHub side both need LFS enabled)
  • Swap in a smaller, single-weight .ttc/.otf (loses the "one file, all
    4 languages × 7 weights" part of the demo)
  • Leave the asset out of the repo entirely and gate this example out of the
    default cargo build --examples/CI matrix, documenting how to fetch the
    font to run it locally

Happy to implement whichever direction you'd prefer, or drop the example if
it's not worth the tradeoff.

Test plan

  • cargo run --example multiple_fonts succeeds and writes
    multiple_fonts.pdf
  • Visually confirm JA/KR/TC/SC blocks render with each language's own
    font name/weight label and body text
  • Visually confirm the four U+66DC (曜) glyphs at the top of the page
    are visibly distinct across JA/KR/TC/SC
  • Confirm output PDF size is small relative to the ~155 MiB source font
    (subsetting working as expected)

Demonstrates rendering multiple faces pulled from a single OTC
(Source Han Serif) on one page, per-language Han-unified glyph
variants (U+66DC), and subset_fonts size reduction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@kyasu1

kyasu1 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

multiple_fonts.pdf

スクリーンショット 2026-07-24 22 06 58

Face order in the OTC's name table is JA/KR/SC/TC, not JA/KR/TC/SC —
verified per-face via fontTools. The texts array had TC and SC
swapped relative to font_groups, so each ran with the other's font.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@fschutt

fschutt commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Hmm yeah, I'll see if there's anything I could use for the GUI use case. Interesting, I didn't realize it was this mature already.

@fschutt

fschutt commented Jul 25, 2026

Copy link
Copy Markdown
Owner

I would just download the font file on-the-fly in the example from a URL. I mean, it's an example, doesn't affect the main codebase

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