tecs.gfx.truetype

TrueType outlines, metrics, coverage rasterization, and signed distance fields.

A face is parsed once from the bytes of a .ttf or .ttc-free single-font file and answers three questions: which glyph a codepoint selects, what that glyph advances, and where its outline runs. rasterize turns one outline into an antialiased coverage bitmap and distanceField turns that bitmap into the field a distance-field text shader samples.

const face, reason = tecs.gfx.truetype.parse(bytes)
assert(face, reason)

const glyph = face:glyphIndex(0x41)
const contours = tecs.gfx.truetype.outline(face, glyph, 48.0 / face.unitsPerEm)

Everything here works in font units until a scale is supplied. A font unit is one of unitsPerEm divisions of the em square, so dividing by unitsPerEm gives em units and multiplying those by a point size gives pixels.

Only the glyf outline format is read. A face whose outlines live in a CFF table, which is what an OpenType font built from PostScript curves carries, parses to a failure reason rather than to empty glyphs. Kerning comes from a format-zero kern table when one is present; GPOS positioning is not read, so a font that kerns only through GPOS lays out with its advance widths alone.

Module contents

Types

TypeKindDescription
FacerecordA parsed font file.
OutlinetypeOne glyph outline, as closed contours of flattened points.

Functions

FunctionKindDescription
distanceFieldfunctionTurns one coverage bitmap into a signed distance field.
outlinefunctionReturns one glyph's flattened outline and its bounding box.
parsefunctionParses a single-font TrueType file.
rasterizefunctionFills one outline into an antialiased coverage bitmap.

Types#

Facerecord#

record Face ...

A parsed font file.

Immutable once parse returns, apart from the kerning table it fills in on first use.

Members

NameKindDescription
unitsPerEmfieldRead-only.
ascenderfieldRead-only.
descenderfieldRead-only.
lineGapfieldRead-only.
numGlyphsfieldRead-only.
bytesfield
locaAtfield
locaLongfield
glyfAtfield
hmtxAtfield
hMetricsfield
cmapAtfield
cmapFormatfield
kernAtfield
kernPairsfield
glyphIndexmethod
advanceOfmethod
bearingOfmethod
kerningOfmethod

unitsPerEmfield#

unitsPerEm: integer

Read-only. Reports the em square's divisions, which every font unit in this face is one of.

ascenderfield#

ascender: integer

Read-only. Reports the distance from the baseline to the top of the typographic ascent, in font units.

descenderfield#

descender: integer

Read-only. Reports the distance from the baseline to the bottom of the typographic descent, in font units. It is negative in every ordinary font.

lineGapfield#

lineGap: integer

Read-only. Reports the extra leading between two lines, in font units.

numGlyphsfield#

numGlyphs: integer

Read-only. Reports how many glyphs the face holds, including .notdef at index zero.

bytesfield#

bytes: string
@private

locaAtfield#

locaAt: integer
@private

locaLongfield#

locaLong: boolean
@private

glyfAtfield#

glyfAt: integer
@private

hmtxAtfield#

hmtxAt: integer
@private

hMetricsfield#

hMetrics: integer
@private

cmapAtfield#

cmapAt: integer
@private

cmapFormatfield#

cmapFormat: integer
@private

kernAtfield#

kernAt: integer
@private

kernPairsfield#

kernPairs: {[integer]: number}?
@private

glyphIndexmethod#

glyphIndex: function(borrows self: Face, codepoint: integer): integer
Arguments
NameTypeDescription
borrows selfFace
codepointinteger
Returns
TypeDescription
integer

advanceOfmethod#

advanceOf: function(borrows self: Face, glyph: integer): number
Arguments
NameTypeDescription
borrows selfFace
glyphinteger
Returns
TypeDescription
number

bearingOfmethod#

bearingOf: function(borrows self: Face, glyph: integer): number
Arguments
NameTypeDescription
borrows selfFace
glyphinteger
Returns
TypeDescription
number

kerningOfmethod#

kerningOf: function(exclusive self: Face, left: integer, right: integer): number
Arguments
NameTypeDescription
exclusive selfFace
leftinteger
rightinteger
Returns
TypeDescription
number

Outlinetype#

type Outline = {{number}}

One glyph outline, as closed contours of flattened points.

Each contour is a flat array of alternating x and y in font units, with y increasing upward the way the font file stores it. The last point joins the first; the closing segment is not repeated.

Functions#

distanceFieldfunction#

function distanceField(coverage: {integer}, width: integer, height: integer, spread: number): {integer}

Turns one coverage bitmap into a signed distance field.

The field is stored the way a distance-field shader expects it: 0.5 sits on the outline, values above it are inside, and one texel of distance is 0.5 / spread of the stored range. A shader recovers coverage by smoothstepping around 0.5.

Distance comes from a two-pass sequential Euclidean transform over the thresholded coverage, which is exact for the texel centers it visits and within a fraction of a texel elsewhere. That is well inside what a spread of several texels can represent.

Arguments

NameTypeDescription
coverage{integer}

the bitmap rasterize produced

widthinteger

the bitmap width in texels

heightinteger

the bitmap height in texels

spreadnumber

the distance in texels the field reaches on each side of the outline, which must be positive

Returns

TypeDescription
{integer}

a width times height array of field values from zero to 255, indexed from one, which the caller owns

outlinefunction#

function outline(self: Face, glyph: integer, scale: number): Outline, number, number, number, number

Returns one glyph's flattened outline and its bounding box.

The box comes from the flattened points rather than from the glyph header, so it encloses exactly what rasterize will fill. An empty glyph, which is what a space is, returns no contours and a zero box.

Arguments

NameTypeDescription
selfFace

the parsed face

glyphinteger

the glyph index

scalenumber

the font units to pixels factor the flattening is tuned for

Returns

TypeDescription
Outline

the contours, in font units with y increasing upward

number

the smallest x, then the smallest y, then the largest x, then the largest y, all in font units

number
number
number

parsefunction#

function parse(bytes: string): Face?, string?

Parses a single-font TrueType file.

Arguments

NameTypeDescription
bytesstring

the complete contents of a .ttf or .otf file

Returns

TypeDescription
Face?

the face, or nil when the bytes are not a readable TrueType font

string?

why the bytes were rejected, when unsuccessful

rasterizefunction#

function rasterize(contours: Outline, width: integer, height: integer, originX: number, originY: number, scale: number): {integer}

Fills one outline into an antialiased coverage bitmap.

The bitmap runs left to right and top to bottom, so it uploads as image rows without a flip. Font y increases upward and texel y increases downward, which is the only place the two conventions meet.

Arguments

NameTypeDescription
contoursOutline

the flattened contours, in font units

widthinteger

the bitmap width in texels, which must be positive

heightinteger

the bitmap height in texels, which must be positive

originXnumber

the font-unit x that lands on the bitmap's left edge

originYnumber

the font-unit y that lands on the bitmap's top edge

scalenumber

the font units to texels factor

Returns

TypeDescription
{integer}

a width times height array of coverage from zero to 255, indexed from one, which the caller owns