User Rating 0.0 β˜…β˜…β˜…β˜…β˜…
Total Usage 0 times

Drop UFO files here or browse

.plist, .glif, .fea files — or select entire .ufo folder

Is this tool helpful?

Your feedback helps us improve.

β˜… β˜… β˜… β˜… β˜…

About

UFO (Unified Font Object) is a directory-based font source format specified by unifiedfontobject.org. Each UFO package contains Apple plist XML files (fontinfo.plist, kerning.plist, groups.plist, lib.plist) alongside GLIF XML files describing individual glyph outlines via contour and component elements. Manually parsing these nested XML structures is error-prone. A misread integer node or dropped dict key can corrupt downstream compilation in tools like fontmake or produce silent metric errors in final OTF/TTF binaries. This converter handles UFO versions 2 and 3.

The tool parses every plist data type: string, integer, real, array, dict, true, false, data (base64), and date (ISO 8601). GLIF files are parsed into structured objects preserving advance widths, unicode codepoints, outline point coordinates with type and smooth attributes, component references with transformation matrices, anchor positions, and per-glyph lib data. This tool approximates a full UFO reader assuming well-formed XML input. It does not validate OpenType spec compliance of the resulting data. Note: binary plist format is not supported. Only XML plist files are accepted.

ufo json font converter unified font object plist parser glif type design font development

Formulas

The conversion pipeline processes each UFO file type through a dedicated parser. Plist XML files are parsed using recursive descent on DOM nodes. The core transformation maps Apple plist XML types to their JSON equivalents.

parsePlist(xmlNode) β†’
{
Object if xmlNode = <dict>Array if xmlNode = <array>String if xmlNode = <string>Number if xmlNode ∈ {<integer>, <real>}Boolean if xmlNode ∈ {<true/>, <false/>}

For GLIF files, glyph outlines are extracted by iterating contour β†’ point elements. Each point stores coordinates (x, y) ∈ R2, a type attribute, and an optional smooth flag. Component references preserve the 6-element affine transformation matrix:

T = xScalexyScalexOffsetyxScaleyScaleyOffset001

Where xScale, yScale default to 1 and all offset/skew values default to 0 when absent. The file classification algorithm uses path-based matching: files ending in .plist are routed to the plist parser, files ending in .glif to the GLIF parser, and .fea files are stored as raw text strings.

Reference Data

UFO FilePurposeFormatUFO VersionJSON Output Key
metainfo.plistUFO format version & creatorXML plist2, 3metainfo
fontinfo.plistFont metrics, naming, dimensionsXML plist2, 3fontinfo
lib.plistArbitrary font-level data storeXML plist2, 3lib
groups.plistGlyph groupings (kerning classes)XML plist2, 3groups
kerning.plistKerning pair valuesXML plist2, 3kerning
features.feaOpenType feature codePlain text2, 3features
contents.plistGlyph name β†’ filename mappingXML plist2, 3contents
*.glifIndividual glyph outline dataGLIF XML1, 2glyphs[name]
layercontents.plistLayer directory mappingXML plist3layercontents
data/*Arbitrary binary data filesBinary3data (base64)
images/*Background images for glyphsPNG3images (base64)
GLIF Point Types
moveStart of open contourAttributeAlltype: "move"
lineStraight line segment endpointAttributeAlltype: "line"
curveCubic BΓ©zier on-curve pointAttributeAlltype: "curve"
qcurveQuadratic on-curve pointAttributeAlltype: "qcurve"
offcurveBΓ©zier control point (no type attr)ImplicitAlltype: "offcurve"
Plist Data Types
stringUTF-8 text value<string>AllJSON string
integerWhole number<integer>AllJSON number
realFloating-point number<real>AllJSON number
true / falseBoolean value<true/> <false/>AllJSON boolean
dataBase64-encoded binary<data>AllJSON string (base64)
dateISO 8601 date<date>AllJSON string (ISO)
dictKey-value dictionary<dict>AllJSON object
arrayOrdered list<array>AllJSON array

Frequently Asked Questions

The converter handles UFO version 2 and 3 structures. Version 3 introduced layercontents.plist, the data/ directory, and images/ directory. Version 1 GLIF format is also parsed since it is a subset of version 2. The converter auto-detects format version from metainfo.plist if provided.
Yes. Use the multi-file upload or drag-and-drop area. The converter reconstructs the UFO directory hierarchy from relative file paths. If your browser supports directory upload (via webkitdirectory), you can select the entire .ufo folder. Alternatively, upload individual files and they will be classified by filename and extension.
This tool only parses XML-format plist files. Binary plist format (magic bytes bplist00) is not supported. If you encounter binary plists, convert them to XML first using plutil -convert xml1 on macOS or equivalent tools. The converter will display an error toast if a binary plist is detected.
Component elements reference another glyph by base name and may include up to 6 transformation attributes: xScale, xyScale, yxScale, yScale, xOffset, yOffset. Missing attributes default to the identity matrix values (1 for scale, 0 for offset/skew). The JSON output preserves all specified attributes and omits defaulted ones to minimize output size.
UFO 3 uses groups.plist to define kerning classes prefixed with public.kern1. (left side) and public.kern2. (right side). The kerning.plist references these group names as dictionary keys. The converter preserves this structure exactly. It does not flatten group references into individual glyph pairs. You retain the class-based hierarchy in JSON.
This tool performs one-way conversion from UFO XML to JSON. The JSON output preserves enough structural information for round-tripping, but the reverse conversion (JSON to plist XML and GLIF) requires a separate tool. The output JSON uses consistent key naming matching UFO spec terminology for compatibility with custom scripts.
The converter processes files sequentially in the browser thread. For packages exceeding 1000 glyphs, expect processing times of 2 - 5 seconds depending on outline complexity. A progress indicator displays the current file count. The final JSON is generated via JSON.stringify with configurable indentation and rendered in a scrollable output area.