Text & fonts¶
Loading a font¶
ttf, _ := os.ReadFile("font.ttf") // or an OpenType/CFF ('OTTO') font
font, err := pdfkit.LoadFont(ttf)
LoadFont parses a TrueType (glyf) or OpenType/CFF (OTTO) font once. The
returned *Font is immutable and may be shared across documents and
goroutines — pass the same *Font to SetFont on pages in different
documents without reloading. Per-document glyph usage is tracked separately
by the Document, so sharing a Font never leaks state between documents.
font.IsCFF() // true for CFF/OpenType outlines, false for TrueType glyf
font.UnitsPerEm() // the font's design grid size
font.NumGlyphs() // glyph count
font.BaseName() // PostScript name, used for the PDF /BaseFont
Drawing text¶
p.SetFont(font, 24) // Tf — select font and size (points)
p.Text(x, y, "Hello, pdfkit") // Tj — baseline origin at (x, y)
p.TextLines(x, y, []string{"line one", "line two"}) // consecutive lines
SetFont registers the font with the document for embedding on first use.
Text and TextLines return error (a wrapped errNoFont-style error) if
no font has been selected yet.
Additional text state, all emitted inside the BT/ET text object:
p.SetCharSpacing(0.5) // Tc — extra spacing between glyphs, in points
p.SetWordSpacing(1) // Tw — has no visible effect on Type0 fonts; provided for completeness
p.SetLeading(28) // TL — baseline-to-baseline distance used by TextLines
p.SetRenderMode(pdfkit.RenderStroke) // Tr — see render-mode constants below
Render modes:
| Constant | Tr | Effect |
|---|---|---|
RenderFill |
0 | fill glyphs (default) |
RenderStroke |
1 | stroke glyph outlines |
RenderFillStroke |
2 | fill then stroke |
RenderInvisible |
3 | neither — useful for an OCR text layer over an image |
RenderFillClip |
4 | fill and add to clip |
RenderStrokeClip |
5 | stroke and add to clip |
RenderFSClip |
6 | fill, stroke and add to clip |
RenderClip |
7 | add to clip only |
Measuring and wrapping¶
w := p.TextWidth("Hello, pdfkit") // width in points at the current font/size
lines := p.WrapText(longString, pdfkit.Mm(170)) // greedy word-wrap to a max width
WrapText breaks on spaces; a single word wider than maxWidth occupies its
own line. Both return zero values when no font is selected.
How fonts are embedded¶
Every font a page uses is written as a Type0 composite font with Identity-H encoding:
- An Identity CIDToGIDMap (character code == glyph index).
- A per-glyph
/Wwidth array, so PDF viewers get correct advance widths without consulting the embedded program. - A
/ToUnicodeCMap built from the runes actually drawn, so copy/paste recovers the original text. - Only the glyphs actually drawn are embedded — the subset is computed from
the document's recorded glyph usage at
Writetime, after all drawing has happened.
The outline format depends on the source font:
- TrueType (
glyf) outlines embed as a subsettedFontFile2/CIDFontType2with a/CIDToGIDMapstream, viaFont.SubsetTrueType(composite-glyph components are followed so a subset never drops a referenced sub-glyph; the subset renumbers glyphs, and the map sends each CID — the original glyph id — to its subset id). - CFF/OpenType outlines embed as a charstring-subsetted
FontFile3/CIDFontType0, viaFont.SubsetCFF, whose glyph numbering is preserved (so an Identity/CIDToGIDMapsuffices) — except a CID-keyed CFF or a CFF2 (variable) font, whichSubsetCFFcannot charstring-subset and which gracefully falls back to embedding the wholeCFF/CFF2table (see Scope and limitations).
Shaped text for complex scripts¶
TextShaped runs the go-opentype
shaper's GSUB substitution and GPOS positioning tables against the
string, then places each resulting glyph individually with its own Tm
matrix, honouring per-glyph x/y offsets and advances. Use it for Arabic,
Indic, CJK, or any Latin text needing ligatures, mark attachment or kerning
that the default path doesn't apply. features names OpenType feature tags
to enable (e.g. "liga").
The plain Text path stays a simple left-to-right codepoint→glyph (cmap)
mapping with no shaping — reach for TextShaped whenever script correctness
matters, and keep Text for simple Latin runs where the extra shaping pass
isn't needed.
Font embedding architecture¶
go-opentype/opentype supplies
every primitive PDF embedding needs: the descriptor scalars (units-per-em,
bounding box, ascent/descent, cap height, italic angle, flags, StemV), the
by-glyph advances for the /W array, and the glyph subsetters
(Font.SubsetTrueType, Font.SubsetCFF) themselves. pdfkit keeps no
private sfnt re-parse or subsetter of its own — it calls straight into
go-opentype for parsing, metrics and subsetting alike.
Scope and limitations¶
- Both outline flavours are subsetted: TrueType
glyffonts viago-opentype'sSubsetTrueTypeand CFF/OpenType fonts viaSubsetCFF(charstring subsetting, glyph numbering preserved). A CID-keyed CFF or a CFF2 (variable) font cannot be charstring-subsetted by the preserve-numbering path, so it falls back to embedding the wholeCFF/CFF2table. - Encryption, tagged PDF / PDF-A, interactive forms and annotations are not yet implemented.
Next: Images for placing JPEG/PNG artwork, or the API reference for the complete signature list.