A raster grid of pixels. It does not inherently know which mark is “A,” where the baseline is, or how far the next letter should move.
From pixels
to a typeface.
What your app must actually do when a user gives it an image and expects a working
.otf, .ttf, or .woff2 font in return.
The core reality
First decide what “image → font” means. Different inputs require fundamentally different products.
A font is not a folder full of letter pictures. It is a small layout program packaged with reusable shapes.
A designed visual shape inside the font. Usually stored as one or more closed vector contours plus measurements.
Glyphs plus Unicode mappings, spacing, names, vertical metrics, and optional positioning or substitution rules.
The question that changes the entire architecture
What kind of image will the user provide? Select each case:
Deterministic conversion
Because every box has a known character, the app can crop and map glyphs without guessing. Registration marks can correct camera perspective. This is the safest first product: the user supplies the designs; your software performs image processing, vectorization, font construction, and correction.
Conversion
Every requested glyph is visibly present and labeled. Your app extracts and packages what the user actually drew.
- Predictable and explainable
- No generative model required
- The user can correct individual glyphs
Generation
Some required glyphs are absent. Your app must invent their shapes while trying to preserve the observed style.
- Requires a style-transfer or generative system
- May create inconsistent anatomy
- Needs stronger review and provenance controls
Characters are not glyphs
This distinction is the foundation of Unicode-aware font engineering.
The font’s cmap table performs the default mapping from Unicode code points to glyph IDs. A simplified example:
U+0041 LATIN CAPITAL LETTER A → glyph ID 17 → /A U+0061 LATIN SMALL LETTER A → glyph ID 43 → /a U+0020 SPACE → glyph ID 3 → /space
The mapping is not always one-to-one
One character may have multiple glyphs: a default form, stylistic alternate, or context-specific form. Italic is normally a separate font style (or a variable-font axis).
Two characters may be substituted with one ligature glyph through an OpenType rule.
A sequence of base plus combining mark may render as positioned glyphs or a precomposed glyph.
What this means for your app
- Never infer mapping from file order or glyph names. Store explicit Unicode code point mapping(s) for every encoded glyph, plus a separate internal glyph ID/name. A glyph named
Ais not mapped toU+0041untilcmapsays so. - Include a visible mapping review. A beautiful “B” accidentally mapped to
U+0041is a broken font. - Always include
.notdef. Glyph ID 0 is the missing-character glyph used when no mapping exists. - Space is a real glyph with width. It usually has no visible contour, but its advance width matters.
- Choose a character set. “Alphabet” is not a specification. Basic English, Western European, Vietnamese, Greek, and Arabic require very different coverage and shaping work.
A shared coordinate system
Every glyph lives in the same invisible measuring system. This is what makes different letters line up as text.
A glyph is usually not a centerline or “a combination of lines.” It is a filled shape bounded by closed contours.
Outline anatomy
- Outer contour: the outside boundary of the ink.
- On-curve and off-curve points: points and handles that define straight or Bézier segments.
- Counter: the negative space inside letters such as O, A, P, R, 8, and e.
A bad tracing step often loses contour hierarchy and fills counters solid. Correct hole detection is mandatory.
The em square and the five lines you must know
The em square is the font’s design grid. A common project choice is 1,000 units per em (UPM), though other values are valid. Glyphs can extend outside the em square; what matters is that every glyph uses the same scale and vertical conventions.
Try the sliders. The black shape is only the visible glyph. The invisible width around it determines rhythm when you type a word.
- Baseline
- The line most letters sit on.
- x-height
- The typical height of lowercase letters such as x.
- Cap height
- The typical height of uppercase letters.
- Ascender / descender
- Areas reached by forms such as h and p.
- Side bearings
- Built-in space to the left and right of one glyph.
- Advance width
- How far the text cursor moves after placing the glyph.
Spacing comes before kerning
Spacing is the normal left and right space assigned to every glyph. Kerning is an exception for a particular pair or class, such as reducing the awkward gap in AV or To. Do not use thousands of kerning pairs to repair poor default spacing.
The complete image pipeline
The SVG-like path is an intermediate result. These eight stages turn a photograph into structured font data.
1. Capture and rectify
Load the image, respect its orientation, detect registration marks, correct perspective, and normalize lighting. A phone photo is rarely a perfect rectangle; rectification makes the known template grid line up with the pixels.
- Input
- JPEG, PNG, HEIC, or scanner output
- Output
- A straightened, consistently scaled page image
- Main risk
- Skew and lens distortion change letter proportions
Raster cleaning is a design decision
Before tracing, the app normally converts the crop to grayscale, estimates foreground and background, thresholds it into a mask, removes tiny specks, and optionally closes small gaps. Each operation changes the design:
- A threshold that is too low makes strokes too thin or broken.
- A threshold that is too high makes strokes heavy and closes counters.
- Strong smoothing erases intentional corners and handwriting texture.
- Aggressive despeckling removes punctuation, dots on i, or intentional distress.
Therefore the user needs a preview and controls. At minimum: threshold, despeckle strength, smoothing, and a reversible bitmap eraser/restore tool.
Tracing: pixels become contours
A tracer such as Potrace converts a black-and-white bitmap into smooth Bézier contours. OpenCV can find contour boundaries and their hierarchy; you then need your own simplification and curve-fitting strategy. Tracing is inherently ambiguous: many vector shapes could have produced the same pixels, and no tracer can reconstruct detail absent from the image.
Pixel coordinates must be transformed into font coordinates
Images normally measure from the top-left with y increasing downward. Font geometry usually treats the baseline as a reference with y increasing upward. Your app must flip, scale, and translate each outline.
outline_x_min is the cleaned ink outline’s leftmost source coordinate—not the template cell edge—so cell whitespace is not accidentally counted again as a side bearing. The exact model can be more sophisticated, but all glyphs must share one deliberate scale and baseline convention.
The internal project should remain editable
Do not store only the final binary. Keep a source project so users can regenerate the font without repeating the scan.
FontProject ├── metadata: family name, style, author, license, version ├── metrics: unitsPerEm, ascender, descender, capHeight, xHeight ├── template: layout version, registration marks, slot map ├── glyphs │ └── A │ ├── codePoints: [0x0041] │ ├── originalCrop: image reference │ ├── cleanMask: editable raster mask │ ├── contours: vector path commands │ ├── advanceWidth: 700 │ ├── leftSideBearing: 70 │ ├── confidence: 0.98 │ └── provenance: user-drawn | component | generated └── kerning: classes and pair adjustments
Inside an OpenType file
An OpenType font is a binary container made of tagged tables. The extension alone does not explain its contents.
Think of MyFont.otf as a labeled filing cabinet, not as one giant SVG.
Character → glyph map
Maps Unicode character codes to default glyph IDs. Without a correct cmap, pressing “A” cannot reliably select your A glyph.
U+0041 → glyph 17
The OpenType specification lists cmap, head, hhea, hmtx, maxp, name, OS/2, and post among the required tables for a normally functioning font. Outline and layout tables are added according to the font’s technology and features.
OTF vs TTF vs WOFF2
Normally an OpenType font using TrueType glyf outlines, which use quadratic curves. Good default for broad desktop compatibility.
Usually an OpenType font using CFF/PostScript-style outlines, which use cubic curves. “OTF” is not shorthand for “better font.”
A compressed packaging format for OpenType/TrueType data used with web @font-face. It is not your editable master.
.ttf, and derive .woff2 for web use. Add CFF .otf export only when you have a specific requirement. Product copy can still say “OpenType-compatible font,” because modern .ttf files use the OpenType container and tables.
Curves matter to your exporter
SVG paths commonly use cubic Bézier curves. TrueType glyf outlines use quadratic curves. If your tracer produces cubic curves but you build a TrueType font, you need a controlled cubic-to-quadratic conversion—for example, fontTools provides cu2qu. CFF-flavored OpenType can preserve cubic outlines.
Global vertical metrics need an explicit policy
The visible baseline, cap height, and x-height are not the whole line-layout contract. Related vertical values appear in both hhea and OS/2, and older applications do not all choose the same fields. Define coherent sTypoAscender, sTypoDescender, and sTypoLineGap values for intended baseline-to-baseline spacing; choose the USE_TYPO_METRICS policy deliberately; keep hhea values compatible; and ensure usWinAscent/usWinDescent and tested bounds do not clip accents or deep descenders. Oversizing every value “to be safe” can create excessive spacing in legacy software, so test line spacing and clipping on every target platform.
Choose a small-size rendering strategy
TrueType fonts can include hinting instructions that influence how outlines fit a pixel grid. For a personal-handwriting MVP, an explicitly unhinted export may be reasonable; an autohinted or manually hinted text font is a separate quality commitment. Record the choice, decide whether a gasp table is appropriate, and test the actual font at small pixel sizes on target renderers. Do not let “small-size quality” remain an unexplained platform accident.
OpenType layout is the font’s behavior layer
GPOSpositions glyphs: kerning, mark placement, and cursive positioning.GSUBsubstitutes glyphs: ligatures, stylistic alternates, localized forms, contextual handwriting variants.GDEFclassifies glyphs and supports more advanced layout behavior.
A simple Latin handwriting MVP may begin with mapping, metrics, and kerning. Connected scripts and complex writing systems require significantly more shaping knowledge and should not be presented as a trivial extension.
App architecture
There are two credible deployment models. The product goals decide which one is better.
Web UI with a Python processing worker
The browser handles upload, previews, mapping, and edits. A sandboxed worker handles image processing, contour generation, font compilation, rendering, and validation. This gives you the most mature font tooling and easiest reproducibility.
Trade-off: uploaded handwriting reaches your server unless you design local preprocessing or explicit privacy controls.
A practical, modular stack
| Responsibility | Candidate tooling | Why / caution |
|---|---|---|
| Image decode | Pillow + OpenCV | Orientation, grayscale, perspective transform, thresholding, morphology, connected components. |
| Segmentation | Known template geometry first; OpenCV contours/components second | A manifest-backed template avoids OCR guessing and gives every crop a known Unicode target. |
| Tracing | Potrace, or custom OpenCV contour + curve fitting | Potrace is proven for high-resolution black/white tracing. Review its GPL/commercial licensing before embedding it in a proprietary service or app. |
| Font source model | Project JSON + UFO/designspace when needed | Keep editability and provenance outside the final binary. UFO is useful if you later integrate a broader font toolchain. |
| Font construction | fontTools FontBuilder, pens, feaLib, cu2qu | Python’s most established low-level family for constructing and manipulating OpenType/TrueType fonts. |
| Browser preview | Generated font via FontFace; opentype.js for inspection/editing | Always preview the actual compiled binary, not only the source SVG paths. |
| Shaping tests | HarfBuzz / uharfbuzz | Confirms that code points and OpenType features become the expected positioned glyph sequence. |
| Rendering tests | FreeType + platform/browser specimens | Render multiple sizes and strings. A valid table structure does not guarantee attractive output. |
| Validation | FontBakery + OpenType Sanitizer + custom checks | Use machine-readable reports. Treat sanitizer errors as export blockers. |
| Web packaging | fontTools/woff2 tooling | Generate WOFF2 after the base OpenType font passes validation. |
Design APIs around stages, not one magic endpoint
POST /projects → create an editable project POST /projects/:id/images → upload source image POST /projects/:id/rectify → detect/confirm page geometry POST /projects/:id/extract → produce labeled glyph crops PATCH /projects/:id/glyphs/:name → change mask, path, mapping, or metrics POST /projects/:id/compile → build a versioned font artifact GET /projects/:id/validation → structured errors and warnings GET /projects/:id/exports/font.ttf → download validated binary
Long-running work should be a job with progress and cancellation. Each stage should be repeatable from stored inputs, with parameters attached to the artifact it produced.
The per-glyph editor is not optional
Automatic processing will fail on some characters. A useful app needs a correction loop:
- Show the original crop beside the thresholded mask and vector result.
- Let the user adjust threshold/smoothing for one glyph or a selection.
- Support erase/restore for raster mistakes.
- Support moving, scaling, and baseline alignment.
- Show spacing in live words, not only isolated boxes.
- Mark low-confidence glyphs and block export only for real structural errors.
Where AI belongs
Use deterministic geometry where the answer is knowable. Use AI only where the system must infer or generate.
Deterministic pipeline
- Template registration and crop extraction
- Thresholding and contour detection
- Coordinate transforms
- Unicode mapping from known slots
- OpenType table construction
- Validation and test rendering
Inference / AI pipeline
- Recognizing an unlabeled character
- Separating touching letters in freeform text
- Suggesting missing glyph designs
- Predicting optical spacing or kerning
- Grouping stylistically consistent alternates
Few-shot font generation is style transfer, not tracing
Research systems often separate content—the structural identity of a character—from style—stroke endings, contrast, width, texture, slant, and local details. A model sees a few target glyphs and tries to apply their style to content representations of unseen characters.
This can work impressively in a demo and still fail as a typeface. A generated B may look plausible alone while having the wrong stem weight, height, width, counter size, or spacing relative to H and O. Font quality is a system-level property.
Recommended AI contract
- Label generated glyphs clearly and retain provenance.
- Never silently overwrite a user-drawn glyph.
- Return multiple candidates when confidence is low.
- Require user approval before generated glyphs enter the export set.
- Validate structure after generation: closed contours, holes, bounds, point limits, scale, mapping.
- Evaluate in words and paragraphs—not only with image similarity metrics.
Cursive handwriting is a later product
A simple font places separate glyphs one after another. Natural cursive changes shape according to neighbors and requires compatible entry/exit strokes, contextual alternates, substitution rules, and sometimes cursive attachment positioning. Tracing one isolated form per character usually produces visibly broken joins. Scope v1 to disconnected handwriting or accept that the result is a playful approximation.
Quality is more than “it installs”
A binary can parse successfully and still produce bad, incomplete, or unsafe typography.
Structural validity
- Required tables exist and checksums are valid
- Glyph 0 is
.notdef - Mappings point to valid glyph IDs
- Contours are closed and non-corrupt
- Names, style flags, and metrics agree
Outline quality
- Counters remain open
- No accidental self-intersections
- No extreme point counts or tiny segments
- Consistent contour direction
- No image noise masquerading as glyph detail
Typography quality
- Baseline, cap height, and x-height feel coherent
- Words have even rhythm
- Space and punctuation widths feel intentional
- Problem pairs are kerned without overfitting
- Accents do not collide or float
Compatibility
- Render in browser, macOS, Windows, and target apps
- Test small and large sizes under the chosen hinting/rasterization policy
- Shape representative language strings
- Install, uninstall, and update versions cleanly
- Test the exact downloaded artifact
A production compile pipeline
build source → compile TTF → structural sanitizer
→ FontBakery profile → HarfBuzz shaping tests
→ FreeType specimen renders → browser/platform smoke tests
→ WOFF2 conversion → repeat relevant checks → release
Test strings should expose different failures
| Test | What it exposes |
|---|---|
| HHOHOO / nonon | Core straight/round side-bearing rhythm. |
| AVATAR · To Wa Yo | Common kerning and diagonal-spacing problems. |
| minimum · hamburgerfontsiv | Lowercase color, joins, repeated stems, and counters. |
| 0123456789 11:48 $19.95 | Numeric widths, punctuation alignment, and tabular expectations. |
| ÁÉÍÓÚ àêö ñ Ç | Accent construction, bounds, and vertical metrics. |
| Language-specific real sentences | Coverage and shaping that pangrams alone can miss. |
Common failure modes your UI should name clearly
- Solid O / A / P
- Inner contours were lost or assigned the wrong fill relationship.
- Glyphs float or sink
- Incorrect baseline detection or per-glyph vertical normalization.
- Words feel scattered
- Side bearings and advance widths are wrong; tracing alone cannot solve spacing.
- Letters look lumpy
- Noise, too many points, or poor curve simplification.
- Wrong key types wrong shape
- Bad Unicode-to-glyph mapping in
cmap. - Font clips accents
- Global ascender/win metrics or glyph bounds are insufficient.
- Font works in one preview only
- You previewed source paths rather than testing the compiled font through real shapers/renderers.
- Font update appears unchanged
- OS/app font caches or unchanged naming/version identifiers.
Rights and provenance
Your product should ask users to confirm that they have the right to convert and distribute the uploaded lettering. A photo of a commercial typeface does not automatically grant permission to reconstruct or redistribute that design. Store source, edit, and generated provenance separately; include author, copyright, license, and version metadata in the project and font naming tables.
A realistic roadmap
Build reliability before magic. Each phase should produce a genuinely usable product.
Template → font
- Printable grid with registration marks
- Basic Latin character set
- Image correction and known-slot extraction
- Threshold/smoothing controls
- Automatic initial spacing + manual adjustment
- Explicitly unhinted TTF export, specimen, validation report
Editor + language
- Vector node editing
- Kerning classes and pair editor
- Accent components and language packs
- Alternates and simple ligatures
- Project versioning and export history
- WOFF2 and web specimen export
AI suggestions
- Unlabeled crop mapping suggestions
- Spacing and kerning suggestions
- Cleanup proposals with before/after
- Missing-glyph candidates
- Style consistency scoring
- Explicit approval and provenance
Definition of done for Phase 1
- A non-expert can print/fill/photograph the template and understand capture errors.
- Every slot maps deterministically to its intended Unicode character.
- The user can repair a bad threshold and preserve counters.
- The exported font types the expected characters in at least the target OS, browser, and creative app.
- Spacing can be reviewed in words and changed without reprocessing the image.
- The font passes your chosen structural checks with no blocking errors and has a documented hinting/rasterization policy.
- The project can be reopened and re-exported reproducibly.
Your prompt-ready brief
You do not need to make every technical decision yourself, but you must make the product contract explicit.
Decisions to answer before asking for implementation
Help me design and implement an image-to-font application. PRODUCT CONTRACT - Primary user: [who uses it and their skill level] - Input type: [a fixed printable template / labeled glyph images / freeform page] - Capture method: [phone photo / scanner / PNG upload] - Supported writing style: [disconnected handwriting / display lettering] - Explicitly out of scope: [connected cursive, arbitrary-logo-to-full-alphabet, etc.] CHARACTER COVERAGE - Required Unicode set: [list or named, versioned manifest] - Required languages: [English, Vietnamese, etc.] - Missing glyph behavior: [block export / ask user / optional generated proposal] - Required special glyphs: .notdef, space, [others] PROCESSING PIPELINE 1. Decode image and correct orientation. 2. Detect registration marks and rectify perspective. 3. Extract glyph cells using the versioned template manifest. 4. Produce an editable grayscale/binary mask per glyph. 5. Trace closed contours while retaining holes and contour hierarchy. 6. Simplify curves with configurable limits and no destructive hidden edits. 7. Convert image coordinates into one font coordinate system. 8. Set a coherent cross-platform vertical-metrics policy, side bearings, and advance widths. 9. Map code points explicitly and compile a valid font. 10. Validate, shape, render, and present actionable errors. USER CORRECTION LOOP - Show original crop, mask, vector outline, metrics, and live word preview. - Support threshold, despeckle, smoothing, erase/restore, scale, and baseline controls. - Support manual side bearings and a later kerning editor. - Preserve all source data and processing parameters in a reopenable project format. FONT REQUIREMENTS - First export: static TrueType-flavored OpenType .ttf. - Optional derived export: .woff2 after the TTF validates. - Use explicit cmap mappings and include required OpenType tables. - Add .notdef at glyph ID 0 and a correctly measured space glyph. - Define coherent OS/2 sTypo*, usWin*, and hhea vertical metrics; choose USE_TYPO_METRICS deliberately; test clipping and line spacing. - State whether TTF output is unhinted, autohinted, or manually hinted, and define the small-size/gasp testing policy. - Add font family/style/version/copyright/license metadata. - Do not claim CFF .otf, variable fonts, or complex-script support unless implemented and tested. TECHNICAL PREFERENCES - UI: [framework] - Backend/worker: [Python or browser-only] - Candidate libraries: OpenCV/Pillow for images; fontTools for font construction; HarfBuzz and FreeType for tests; FontBakery and a sanitizer for QA. - Treat any tracer dependency and its license as an explicit architecture decision. - Jobs must be reproducible, cancellable, and bounded by file/image/contour/point limits. AI POLICY - Deterministic processing for known geometry and mappings. - AI may only [suggest cleanup / suggest mapping / generate missing-glyph candidates]. - Generated content must be labeled, versioned, reversible, and user-approved. - Never silently replace user-drawn glyphs. VALIDATION AND ACCEPTANCE - Validate the exact downloadable binary, not only source paths. - Test representative strings through HarfBuzz and render with FreeType. - Smoke-test installation, line spacing, clipping, and typing in [target platforms/apps]. - Test small pixel sizes under the selected hinting/rasterization strategy. - Block export on structural corruption; show design-quality concerns as editable warnings. - Include automated tests for counter preservation, coordinate flipping, Unicode mapping, metrics, deterministic rebuilds, malformed input, and cancellation. Before coding: 1. Restate the exact product scope and identify ambiguities. 2. Separate deterministic conversion from any generative behavior. 3. Propose a staged architecture and editable project schema. 4. Identify licensing, security, privacy, and compatibility risks. 5. Define the smallest end-to-end vertical slice and its acceptance tests. Do not broaden the scope without asking me.
A shorter prompt for the first prototype
Build a local prototype that turns a fixed, labeled handwriting template into a valid TTF. Use known template slots—no OCR and no generated glyphs. Support A–Z, a–z, 0–9, space, and an explicit punctuation manifest. Show each original crop, binary mask, traced outline, baseline, and side bearings. Let me correct threshold and placement. Preserve holes in A/B/D/O/P/Q/R/0/4/6/8/9. Build with fontTools, then validate and render the exact TTF. Use an explicitly unhinted v1 unless you justify another strategy; define coherent vertical metrics and test clipping/line spacing. First give me the architecture, project schema, risks, and end-to-end acceptance test.
Small glossary
The minimum vocabulary for discussing the product precisely.
- Typeface
- The visual design system. A family may include Regular, Bold, Italic, and other styles.
- Font
- A usable implementation/file of a typeface style, such as My Hand Regular.ttf.
- Character
- An abstract textual element, such as Latin capital letter A.
- Code point
- A numeric Unicode identifier, such as U+0041.
- Glyph
- A visual representation selected to render one or more characters.
- Contour
- A closed boundary made of line and curve segments that defines a filled glyph region.
- Counter
- Enclosed or partly enclosed negative space inside a glyph.
- Bézier curve
- A mathematical curve controlled by on-curve and off-curve points.
- UPM
- Units per em: the resolution of the font’s shared design coordinate system.
- Metrics
- Measurements controlling glyph placement, width, and line layout.
- Side bearing
- The default left or right spacing around a glyph outline.
- Advance width
- The horizontal distance the layout cursor advances after a glyph.
- Kerning
- A pair/class-specific spacing adjustment beyond default side bearings.
- Shaping
- Turning Unicode sequences into correctly selected and positioned glyph sequences.
- Rasterization
- Rendering scalable outlines onto a pixel grid for display or printing.
- Tracing / vectorization
- Estimating vector contours from a raster bitmap.
- OpenType
- A table-based font format supporting TrueType or CFF outlines and advanced layout.
- cmap
- The OpenType table mapping character codes to glyph IDs.
- GPOS / GSUB
- OpenType tables for glyph positioning and substitution behavior.
- WOFF2
- Compressed web packaging for OpenType/TrueType font data.
Research sources
This guide prioritizes specifications and official project documentation. Research papers are included only to explain the separate few-shot generation problem.